My previous blog highlighted my first foray into Drupal 8 development and the successful launch of my site from inception to launch. This blogs takes the narrative further - how I developed the site.
Underpinning the site is its use of entity content types. The relationships between the content type fields is fundamental to how the data works, and to aid this entity references are now bundled into core whereas back in Drupal 7 there were separate modules for references (for content types) and entity references. So I have a content type for 'Teams' (e.g. 'Liverpool', 'New Zealand'), two of which (home and away) form an 'Event' (along with other fields such as start time and broadcast time) and that 'Event' also needs a 'Competition' reference (e.g. 'Premier League', 'IPL Cricket'). On top of that there is a vocabulary for broadcasters, and further content types to cover the creation of banner type adverts on the site.
To ensure that my site would gain an advantage over similar sites I needed to ensure that structured schema.org data could be integrated into the pages with RDFa thus improving its SEO ranking. This would be used throughout for the broadcast events that I would listing. Now Drupal 8 supports RDFa and I took a couple of days to asses the contributed module RDF UI thinking this would be a neat way of satisfying my needs. Alas the module doesn't support parent / child relationships and my desire was to use a parent of a Broadcast Event and a child of a Sports Event. So in the end that was abandoned and I manually populated the RDFa in the TWIG templates.
Each 'Event' uses a convention of '{Home team} v {Away team}' for the title. Since the home and away teams are both references this aught to have been easy to automatically build the title by using the Automatic Nodetitles contrib module. Unfortunately not! The module hasn't been ported to Drupal 8 yet, but by poking around I discovered an early development version and tried it. It didn't work. I then noticed someone had an unmerged pull request that looked like it would provide the functionality I would need, so I manually downloaded the commit and merged it into the code I already had. Hey presto! Automatic Nodetitles on Drupal 8! It's great when a punt comes off!
When each 'Event' comes around to its broadcast time I wanted an automated Tweet generating and issued to Twitter. This would enable me to gain experience of how to use external PHP libraries within Drupal 8 since I was going to use the reliable PHP TwitterOAuth Library. The first requirement is to have the dependency management tool composer installed on the host box. After that the contrib module Composer Manager should be installed. This will allow Drupal to manage its dedicated composer.json file whilst each package can have its own composer file. Instructions on the use of the contrib module are at Composer Manager for Drupal 8 and I can testify they are well written and easy to follow! With the PHP TwitterOAuth Library available your own class can access it using something like this (vastly abbreviated!):
<?php namespace Drupal\tv_twitter\Model; use Abraham\TwitterOAuth\TwitterOAuth; class TwitterModel { private $connection; private $credentials = array(); private $friendsids; private $followersids; public function __construct() { // Setup $this->credentials['API_KEY'] = \Drupal::config('twitter.credentials')->get('API_KEY'); $this->credentials['TWITTER_API_SECRET'] = \Drupal::config('twitter.credentials')->get('TWITTER_API_SECRET'); $this->credentials['TWITTER_ACCESS_TOKEN'] = \Drupal::config('twitter.credentials')->get('TWITTER_ACCESS_TOKEN'); $this->credentials['TWITTER_ACCESS_TOKEN_SECRET'] = \Drupal::config('twitter.credentials')->get('TWITTER_ACCESS_TOKEN_SECRET'); $this->credentials['TWITTER_USER'] = \Drupal::config('twitter.credentials')->get('TWITTER_USER'); } public function authenticate() { $this->connection = new TwitterOAuth( $this->credentials['API_KEY'], $this->credentials['TWITTER_API_SECRET'], $this->credentials['TWITTER_ACCESS_TOKEN'], $this->credentials['TWITTER_ACCESS_TOKEN_SECRET'] ); } ?>
modules/custom/my_twitter_module/config/install/twitter.credentials.yml
API_KEY: 'XXXXX' TWITTER_API_SECRET: 'XXXXXX' TWITTER_ACCESS_TOKEN: 'XXXXXX' TWITTER_ACCESS_TOKEN_SECRET: 'XXXXXX' TWITTER_USER: 'XXXXX'
<?php /** * {@inheritdoc} */ public function build() { $creative = $this->loadBannerContent(); return [ '#theme' => 'tv_banner_banner_content_bottom_block', '#creative' => $creative, '#cache' => [ 'max-age' => 300, ] ]; } ?>
/etc/php5/fpm/php.ini
;[opcache] opcache.enable=1 opcache.revalidate_freq=0 opcache.validate_timestamps=0 opcache.max_accelerated_files=10007 opcache.memory_consumption=192 opcache.interned_strings_buffer=16 opcache.fast_shutdown=1