Hi I have a requirement to display the data from external api but should not be imported into any entities. What I did is I have written a custom view query plugin which displays the data from external api. What I did is I have used the GuzzleHttp Client to get the data. Here is how my service looks like
namespace Drupal\***_services;
use Drupal\Component\Serialization\Json;
class NewsBlogsClient {
/**
* @var \GuzzleHttp\Client
*/
protected $client;
/**
* NewsBlogsClient constructor.
*
* @param $http_client_factory \Drupal\Core\Http\ClientFactory
*/
public function __construct($http_client_factory) {
$this->client = $http_client_factory->fromOptions([
'base_uri' => 'https://****************/',
]);
}
/**
* Get all the news.
*
* @return array
*/
public function getNews() {
$response = $this->client->get('****');
$data = Json::decode($response->getBody());
return $data;
}
/**
* Get all the blogs.
*
* @return array
*/
public function getBlogs() {
$response = $this->client->get('****');
$data = Json::decode($response->getBody());
return $data;
}
}
I called the service into my plugin query and mapped it to the view fields that I have created using hook_views_data(). Here is how my plugin query looks like.
namespace Drupal\****\Plugin\views\query;
use Drupal\views\ViewExecutable;
use Drupal\views\ResultRow;
use Drupal\views\Annotation\ViewsQuery;
use Drupal\Core\Annotation\Translation;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Datetime\DrupalDateTime;
/**
* Views query plugin which wraps calls to the *** API in order to
* expose the results to views.
*
* @ViewsQuery(
* id = "news",
* title = @Translation("News"),
* help = @Translation("Query against the API.")
* )
*/
class News extends QueryPluginBase implements ContainerFactoryPluginInterface {
/**
* @var \Drupal\*****\NewsBlogsClient
*/
protected $newsBlogsClient;
/**
* FeaturedNews constructor.
*
* @param array $configuration
* @param $plugin_id
* @param $plugin_definition
* @param $newsBlogsClient \Drupal\****\NewsBlogsClient
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, $news_blogs_client) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->newsBlogsClient = $news_blogs_client;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('news_blogs_client')
);
}
/**
*
* {@inheritdoc}
*/
public function execute(ViewExecutable $view) {
$index = 0;
if ($news_items = $this->newsBlogsClient->getNews()) {
foreach ($news_items as $news_item) {
$row['title'] = $news_item['title'];
$row['link'] = $news_item['view_node'];
$date = $news_item['field_published_date'];
$dateTime = new DrupalDateTime($date);
$timestamp = $dateTime->format('U');
$row['pubdate'] = $timestamp;
$row['summary'] = $news_item['field_short_description'];
$row['thumbnail'] = $news_item['uri'];
// 'index' key is required.
$row['index'] = $index++;
$view->result[] = new ResultRow($row);
}
}
}
/**
* Ensures a table exists in the query.
*
* This replicates the interface of Views' default SQL backend to simplify
* the Views integration of the API. Since the API has no
* concept of "tables", this method implementation does nothing. If you are
* writing API-specific Views code, there is therefore no reason at all
* to call this method.
* See https://www.drupal.org/node/2484565 for more information.
*
* @return string
* An empty string.
*/
public function ensureTable($table, $relationship = NULL) {
return '';
}
/**
* Adds a field to the table. In our case, the API has no
* notion of limiting the fields that come back, so tracking a list
* of fields to fetch is irrelevant for us. Hence this function body is more
* or less empty and it serves only to satisfy handlers that may assume an
* addField method is present b/c they were written against Views' default SQL
* backend.
*
* This replicates the interface of Views' default SQL backend to simplify
* the Views integration of the API.
*
* @param string $table
* NULL in most cases, we could probably remove this altogether.
* @param string $field
* The name of the metric/dimension/field to add.
* @param string $alias
* Probably could get rid of this too.
* @param array $params
* Probably could get rid of this too.
*
* @return string
* The name that this field can be referred to as.
*
* @see \Drupal\views\Plugin\views\query\Sql::addField()
*/
public function addField($table, $field, $alias = '', $params = array()) {
return $field;
}
}
Everything is working great. I can display and control the data through views. The only missing thing is paging. The API is also from another Drupal application which supports pagination. I also need to setup a pager for this query. Tried lot of things but didn't work. I don't know how actually a view pager works. Can anyone explain and provide me any example snippet or code to work with.