This presentation can be found at emarchak.github.io/atyourservice
This module can be found at github.com/emarchak/atyourservice
$ drupal generate:module
Enter the new module name:
> Fastpaced videos
$ drupal generate:entity:bundle
Enter the module name [admin_toolbar]:
> fastpaced_videos
Enter the machine name of your new content type [default]:
> video
$ drupal module:install fastpaced_videos
Log into the site and configure the content type as needed, before you export it.
$ drupal config:export:content:type
> video
Export content type in module as an optional configuration (yes/no) [yes]:
> no
$ drupal create:nodes
/**
* Implements hook_cron().
*/
function fastpaced_videos_cron() {
\Drupal::service('fastpaced_videos.import')->import();
}
Some parts of Drupal 8 are still procedural like 7, hook_theme
and hook_cron
, for example.
$ drupal generate:service
Enter the service name [fastpaced_videos.default]:
> fastpaced_videos.import
Enter the Class name [DefaultService]:
> ImportService
Do you want to load services from the container (yes/no) [no]:
> yes
Enter your service [ ]:
> http_client
> entity.query
> entity_type.manager
> config.factory
> serialization.json
Drupal 8 has lots of new services in core you can explore.
logger.channel.fastpaced_videos:
parent: logger.channel_base
arguments: ['fastpaced_videos']
use Psr\Log\LoggerInterface;
/**
* Psr\Log\LoggerInterface definition.
*
* @var Psr\Log\LoggerInterface;
*/
protected $logger;
// Log how many videos we’ve imported.
$this->logger
->info('Imported @count fast paced videos', ['@count' => $imported]);
There's a new way to handle logging in Drupal 8.
// Get our search parameters.
// Query YouTube based on our search results.
// Check the result of our search request.
try {
// If we have something, list the results.
$results = [];
// Loop through the results.
for ($i = 0; isset($results[$i]); $i++) {
// Increment our imported count on successful import.
$imported++;
}
} catch (RequestException $e) {
watchdog_exception('fastpaced_videos', $e);
}
$ drupal generate:form:config
Enter the Form Class name [DefaultForm]:
> ImportSettingsForm
Do you want to generate a form structure? (yes/no) [yes]:
> y
Type: textfield
Input label: Search Terms
Description: Feed to import from
Default value: macaframa
Update routing file (yes/no) [yes]:
> yes
Generate a menu link (yes/no) [yes]:
> yes
A title for the menu link [ImportSettingsForm]:
> Fast Paced Import Settings
Menu parent [system.admin_config_system]:
> system.admin_config_services
$ drupal config:export:single --directory=modules/custom/fastpaced_videos/config/install
Configuration type [Simple configuration]:
> system.simple
Configuration name [automated_cron.settings]:
> fastpaced_videos.importsettings
import() {
// Get our search parameters.
$config = $this->config_factory->getEditable('fastpaced_videos.importsettings');
$search_terms = $config->get('search_terms');
$this->logger
->info('Searching for @terms', ['@terms' => $search_terms]);
protected function getSearchURL($search_terms = '') {
$search_url = URL::fromUri(
'https://www.googleapis.com/youtube/v3/search',
[ 'query' => [
'q' => urlencode($search_terms),
'part' => 'snippet',
'type' => 'video',
'safeSearch' => 'strict',
'maxResults' => '50',
'key' => $_SERVER['GGL_API_KEY']
]])->toUriString();
return $search_url;
}
import() {
// Query YouTube based on our search results.
$search_url = $this->getSearchURL($search_terms);
$response = $this->http_client->request('GET', $search_url);
// Check the result of our search request.
try {
if ($response->getReasonPhrase() != 'OK') {
throw new Exception(t(
'Received status @status',
array('$status' => $response->getReasonPhrase())
));
}
// If we have something, list the results.
$data = $this->serialization_json->decode($response->getBody());
$results = $data['items'];
// Create the video URL.
$video_url = $this->getVideoURl($results[$i]);
/**
* Helper method to return the video URL
*/
protected function getVideoURL($item = []) {
$video_url = '';
$video_url = Url::fromUri(
'https://www.youtube.com/watch',
[ 'query' => [
'v' => $item['id']['videoId']
]])->toUriString();
return $video_url;
}
// Check to see if we have the video URL imported
$is_new = $this->uniqueField('field_video', $video_url);
/**
* Check if file is unique among nodes.
*/
protected function uniqueField($field = '', $value = '') {
$result = $this->entity_query->get('node')
->condition($field, $value, '=')
->execute();
$unique = empty($result);
return $unique;
}
if ($is_new) {
$item = $results[$i]['snippet'];
$was_saved = $this->createNode($item['title'], [
'body' => $item['description'],
'field_video' => $video_url,
]);
// Increment our imported count on successful import.
if ($was_saved) {
$imported++;
}
/**
* Create node and populate fields for video content types.
*/
protected function createNode($title = '', $fields = []) {
$node_storage = $this->entity_type_manager->getStorage('node');
// Create the node.
$node = $node_storage->create([
'type' => 'video',
'title' => $title,
'uid' => 1,
]);
// Populate the fields
foreach ($fields as $field => $value) {
$node->set($field, $value);
}
// Save the node
return $node->save();
}
$ drupal generate:controller
Enter the Controller class name [DefaultController]:
> FrontPageController
Enter the Controller method title (leave empty and press enter when done) [ ]:
> Front
Enter the action method name [hello]:
> load
Enter the route path [fastpaced_videos/hello/{name}]:
> front
Enter your service [ ]:
> entity_type.manager
Add our theme function to fastpaced_videos.module
.
This looks for fastpaced-gallery.html.twig
.
function fastpaced_videos_theme() {
return [
'fastpaced_gallery' => [
'variables' => [
'videos' => NULL
]
]
];
}
Some parts of Drupal 8 are still procedural like 7, hook_theme
and hook_cron
, for example.
Add the variables to src/Controller/FrontPageController.php
.
load() {
// Get our libraries to make this easier.
$storage = $this->entity_type_manager->getStorage('node');
$query = $storage->getQuery();
$view = $this->entity_type_manager->getViewBuilder('node');
// Fetch the 10 most recent nodes
$nids = $query
->condition('status', NODE_PUBLISHED)
->condition('type', 'video')
->sort('created', 'DESC')
->pager(10)
->execute();
$nodes = $storage->loadMultiple($nids);
foreach($nodes as &$node) {
$node = $view->view($node, 'teaser');
}
// Return the nodes to the template.
return [
'#theme' => 'fastpaced_gallery',
'#videos' => $nodes
];