Twitter Bootstrap 4 + Automattic _s = UnderStrap

UnderStrap combines the Underscores starter theme (by Automattic) and the mobile-first, responsive grid framework Bootstrap 4 (by Twitter) into a perfect open source foundation for your next WordPress theme project.

In passato avevo già affrontato l’argomento:

Temi per WordPress


ma le tecnologie si evolvono e si aggiornano.
UnderStrap mette a disposizione dello sviluppatore WordPress l’ultima release del framework Bootstrap per la realizzazione di theme custom.

Scrivere i log prodotti da Drupal 8 nello stream di Amazon CloudWatch


L’attività di logging se ben concepita può essere una miniera di informazioni per il debug di errori e per tenere traccia di quello che succede nell’applicazione, per capire cosa è andato storto o anche solo per monitorare l’attività degli utenti che ha indotto all’errore.

Se avete dimestichezza con Symfony avrete sicuramente imparato ad amare la versatilità di Monolog, scritto dallo stesso sviluppatore che ha inventato Composer.
Monolog supporta canali (Channels) di log differenti, ciascuno dei quali associati a degli Handler che sono in grado di scrivere un messaggio di log sulle destinazioni più disparate, da un semplice database passando per Syslog fino a soluzioni più evolute come postare un messaggio su Slack o Logstash.

Utilizzando un handler di Monolog possiamo interfacciarci con Amazon CloudWatch che è un servizio di monitoraggio per le risorse cloud AWS e le applicazioni in esecuzione su AWS. Si può utilizzare Amazon CloudWatch per raccogliere e monitorare parametri e file di log, impostare allarmi e reagire automaticamente ai cambiamenti nelle risorse AWS.

Quindi andiamo per ordine:

  • per poter scrivere i nostri log dentro la piattaforma CloudWatch abbiamo bisogno di installare il wrapper di Monolog per Drupal 8
    composer require drupal/monolog:^1.0
  • sucessivamente dovremo installare l’handler specifico per CloudWatch
    composer require maxbanton/cwh:^1.0
  • nella stessa directory del file settings.php del sito dovremo creare uno specifico file per il servizio (monolog.services.yml per esempio) e poi aggiungere questa riga di codice nel file settings.php stesso:
    $settings['container_yamls'][] = 'sites/default/monolog.services.yml';

Ora abbiamo due possibili strade, la cui scelta dipende solo dalle specifiche esigenze del progetto.

Tutti i channel vengono scritti in un unico stream

Nel file sites/default/monolog.services.yml mettiamo queste impostazioni sostituendo i parametri che iniziano con my_ che sono solamente dei segnaposto.
[php]

parameters:
monolog.channel_handlers:
default:
– cloudwatch_handler

monolog.processors:
– message_placeholder
– current_user
– request_uri
– ip
– referer

services:
cloudwatch_client:
class: Aws\CloudWatchLogs\CloudWatchLogsClient
arguments:

credentials:
key: my_amazon_accesskey
secret: my_amazon_secretkey
region: my_amazon_region
version: latest

cloudwatch_handler:
class: Maxbanton\Cwh\Handler\CloudWatch
arguments:
– "@cloudwatch_client"
– my_group_name
– my_stream_name
– 30
– 10000

mytag: tag
– DEBUG

[/php]

Ogni channel di Monolog verrà scritto in uno specifico stream

Se vogliamo fare in modo che ogni channel, magari per una migliore leggibilità dei log, venga scritto in un proprio stream dobbiamo prima creare un handler custom che possiamo mettere in un modulo creato appositamente oppure in un altro modulo custom. Occhio solo a mettere il namespace corretto.

[php]
<?php

namespace Drupal\my_custom_module\Logger\Handler;

use Aws\CloudWatchLogs\CloudWatchLogsClient;
use Maxbanton\Cwh\Handler\CloudWatch;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;

/**
* Class CloudWatchHandler
*
* @package Drupal\my_custom_module\Logger\Handler
*/
class CloudWatchHandler extends AbstractProcessingHandler {

/**
* CloudWatch constructor.
*/
public function __construct() {
parent::__construct(Logger::DEBUG, TRUE);
}

/**
* Writes the record down to the log of the implementing handler
*
* @param array $record
*
* @return void
*/
protected function write(array $record) {

$sdkParams = [
‘region’ => "my_amazon_region",
‘version’ => "latest",
‘credentials’ => [
‘key’ => "my_amazon_key",
‘secret’ => "my_amazon_secret",
],
];

$client = new CloudWatchLogsClient($sdkParams);

$group = "my_group_name";

if (empty($record[‘channel’])) {
$stream = "default";
}
else {
$stream = $record[‘channel’];
}

/** @var \Maxbanton\Cwh\Handler\CloudWatch $handler */
$handler = new CloudWatch($client, $group, $stream, 30, 10000, [], Logger::DEBUG);

$handler->write($record);
}

}
[/php]

A questo punto nel nostro file sites/default/monolog.services.yml mettiamo le configurazioni:

[php]

parameters:
monolog.channel_handlers:
default:
– cloudwatch_handler

monolog.processors:
– message_placeholder
– current_user
– request_uri
– ip
– referer

services:
cloudwatch_handler:
class: Drupal\my_custom_module\Logger\Handler\CloudWatchHandler
#Modificare con il namespace corretto
[/php]

Come si può notare il servizio è molto spartano, ma può essere ampliato iniettando come argomento magari \Drupal\Core\Config\ConfigFactoryInterface $config_factory per caricare una configurazione oppure \Drupal\Core\Entity\EntityTypeManager $entity_type_manager per interfacciarsi con il repository di un’entità.

Drupal Console + dotenv

Questo post nasce per dare una risposta alla domanda:

quale è il modo più semplice in un progetto Drupal per gestire le variabili di ambiente?

Le ultime versioni di Drupal Console includono una feature molto utile per gestire le variabili che hanno valori che possono variare tra i diversi ambienti come parametri di connessione al db o path dell’installazione.

Questo è possibile tramite una libreria che è una dipendenza di drupal-console: https://github.com/vlucas/phpdotenv.
In pratica ce lo troviamo già nelle nostre disponibilità senza fare nulla.
Vediamo quindi come utilizzarlo, anche in un progetto già avviato.

drupal dotenv:init

Nella shell ci verrà chiesto di immettere alcuni valori, come i parametri di accesso al db: nome, utente, password.
Drupal Console creerà un file .env nella root e modificherà il file web/sites/default/settings.php per fare in modo che le variabili presenti nel file .env vengano lette.
Questo è un esempio di .env

[bash]
# ENV
ENVIRONMENT=stage

# DATABASE
DATABASE_NAME=drupal
DATABASE_USER=drupal
DATABASE_PASSWORD=aUVOicUSmS9Zn9SiW6zB
DATABASE_HOST=localhost
DATABASE_PORT=3306

# PATH
ROOT=/var/www/demowebsite.it/web

# SETTINGS
[/bash]

Se lavoriamo in collaborazione con altri sviluppatori possiamo creare anche un file di distribuzione .env.dist con i valori di default da includere nel repository git.

L’utilizzo più comodo che ci viene gratis è fare in modo che anche il nostro file .aliases legga il file .env così non dobbiamo sempre settare i path quando lanciamo un comando drush, drupalconsole oppure robo:

[bash]
#!/bin/bash
export $(egrep -v ‘^#’ .env | xargs)
alias drush="vendor/bin/drush -r $ROOT"
alias drupal="vendor/bin/drupal –root=\"$ROOT\""
alias robo="vendor/bin/robo"
[/bash]

Come dicevo anche il task runner Robo, può leggere le variabili di ambiente dichiarate in .env.

Ecco un semplice esempio:

[php]
/**
* RoboFile constructor.
*/
public function __construct() {
$dotenv = new \Dotenv\Dotenv(__DIR__);
$dotenv->load();
$this->environment = getenv(‘ENVIRONMENT’);
}
[/php]

Magento, il terrore delle performances

Magento, uno dei software per l’ecommerce più utilizzati al mondo, se non opportunamente configurato è molto ingordo di risorse e il rischio di schiantare la macchina che lo ospita è tutt’altro che remoto.
Vi racconto una storia.
C’era una volta un sito dove girava Magento CE (community edition). Con grande soddisfazione dei proprietari dopo un paio d’anni dalla pubblicazione del sito gli affari andavano molto bene e girava abbastanza traffico da giustificare un hosting serio, praticamente risorse illimitate.
Il database girava su una macchina dedicata, utilizzando l’ultima release di Percona Server, il fork di MySQL.
Le performance inizialmente buone, a mano a mano, che il database aumentava di “volume”, diventavano sempre più problematiche: query lentissime, un sacco di deadlock, ore (ore!!!) di waiting for table level lock, rendendo di fatto la situazione insostenibile.
Armato di santa pazienza, come si fa in questi casi, cerco su Stack Overflow e nella documentazione Percona ovviamente, una possibile soluzione.
I consigli che ne ho ricavato sono abbastanza ovvi ma inefficaci: aumentare il lock wait timeout di InnoDb, settare la transaction isolation a READ-COMMITTED. Ma il database si schiantava ancora ogni tre per due.
Fino a che non trovo un post che consiglia di utilizzare https://github.com/major/MySQLTuner-perl.
MySQLTuner è uno script scritto in Perl che ti permette di rivedere rapidamente le configurazioni di un’installazione di MySQL e ti suggerisce le modifiche da apportare per aumentare le prestazioni e la stabilità.
Facilissimo da utilizzare, anche da remoto. Non apporta modifiche direttamente al database, questo è molto importante, ma dopo aver analizzato i log e le configurazioni correnti ti fornisce una serie di suggerimenti.
Nel caso citato sopra, MySQLTuner si è rivelata la provvidenziale manna: dopo aver apportato alcune delle modifiche suggerite il database è tornato a livelli di perfomance davvero ottime. Dopo questo intervento non ha più avuto problemi e down.

Nel favoloso mondo di Docker

Mi sono ritrovato a fare i conti con il mantenimento di un sito che gira ancora su PHP 5.4 in un hosting condiviso, dove quindi non è possibile fare l’upgrade dell’interprete.
Per ricrearmi in locale le stesse condizioni di environment presenti in produzione la scelta è stata Docker.
Ed è stata una droga. Un tunnel che mi ha risucchiato.
In rete è pieno di tutorial su come iniziare con Docker, per cui non mi dilungo.
Quello che vorrei comunicare qui sono i vantaggi che questa scelta ha portato alle mie operazioni quotidiane di DevOps.
Perché virtualizzare un’intera macchina, quando sarebbe possibile virtualizzare solamente una piccola parte di essa? I container consentono allo sviluppatore di pacchettizzare una applicazione con tutte le parti necessarie (le librerie e altre risorse correlate) e consegnarla appunto come un unico pacchetto.
Al contrario di una virtual machine (che crea un intero sistema operativo virtuale), Docker consente alle applicazioni di usare lo stesso kernel Linux del sistema host su cui stanno girando e richiede soltanto che le applicazioni vengano consegnate senza elementi che risiedano già sulla macchina che le ospita. Per questo motivo i vantaggi più grandi di Docker sono la riduzione dello spazio occupato dall’applicazione, l’aumento delle prestazioni e l’isolamento.
Ecco quindi che mi sono lanciato nella mischia creando le mie immagini, specifiche per le questioni che affronto ogni giorno:

Questo è il un mio classico docker-compose.yml:

Segnalo comunque che per non reinventare la ruota ogni volta, in ambito Drupal ci sono due iniziative che meritano sicuramente un approfondimento:

A starter theme for Drupal 8


Non so voi, ma a me le vacanze estive regalano tanta voglia di provare cose nuove.
Volevo mettere insieme uno starter kit per lo sviluppo di theme custom in Drupal 8.
L’idea era quella di non dover reinventare la ruota ogni volta e perdere tempo a configurare Gulp per le solite operazioni di lint, beautify, minify, concatenate del JavaScript e del CSS.

Il risultato è questo: https://github.com/erighetto/d8t, un subtheme di Classy.

Cosa ruggisce sotto il cofano?

  • Gulp come task-running
  • Sass per il pre-processing CSS, tramite Libsass così non tiriamo in ballo Ruby
  • Browser Sync test simultanei su molteplici browsers
  • Bower per gestire in modo organizzato le librerie esterne.
  • Bourbon  che è una Sass mixin library
  • Neat per le griglie pensato per lavorare con Bourbon

Per dovere di cronaca devo dire che non è tutta farina del mio sacco.
L’idea di fondo è di fatto un fork di https://github.com/startinggravity/Drupal-8-Theme.
Ho preferito creare un progetto separato perchè ritenevo poco significativa la presenza di un tool come
patternlab mentre imperdonabile la mancanza di Bower in combinata con i due tool wiredep e gulp-main-bower-files per gestire le librerie esterne.

Il progetto è tutt’altro che “definitivo”, quindi suggerimenti e consigli sono sempre ben accetti.

5 considerazioni a corredo del mio primo progetto basato su Drupal 8

Schermata 2016-02-07 alle 16.34.41

1) Migrazione
Grazie al terzetto di moduli migrate_plus, migrate_upgrade, migrate_tools il passaggio da Drupal 6 a Drupal 8 è stato abbastanza agevole. Nel mio caso specifico ho dovuto comunque effettuare numerosi tentativi, sopratutto per sanare cck e node type che nel tempo si erano “rotti” già in D6 e per eliminare 3 mila utenti spam che si erano formati negli anni. Ho dovuto cancellare a mano le tabelle create da Migrate a migrazione conclusa. In Drupal 7 una volta disinstallato il modulo Migrate le tabelle propedeutiche alla migrazione venivano cancellate automaticamente. Non ho capito se in Drupal 8 questo non avvenga per un problema alla mia installazione, sia un bug oppure sia voluto.

2) E’ possibile mettere on line un sito senza scrivere PHP?
La mia idea era provare a fare un sito senza nemmeno scrivere una riga di codice, ma mi sono scontrato con un paio di bug che ho contribuito a risolvere: Colorbox e Search API.
Inoltre ho dovuto mettere in piedi una piccola raccolta di operazioni di normalizzazione che ho eseguito sui nodi per:

  • settare l’italiano come lingua predefinita, visto che in Drupal 6 era indefinita.
  • settare il flag “Generate automatic URL alias” e rigenerare il path con i patter predefiniti in Pathauto
  • rimuovere il flag “Promoted” per tutti in nodi che fanno parte di un certo Content Type
  • cambiare il content type di certi nodi

3) Pathauto, Metatag, Redirect e Xml sitemap sono moduli ormai imprescindibili, sono utilizzabili?
Pathauto e Metatag hanno delle alpha e beta release che lavorano in modo egregio.
Redirect: il porting per il momento è su github.com ma il branch master è stabile e funziona “as aspected”. Tanto che ci ho pure messo vicino un plugin che permette di aggiungere dei redirect partendo da una lista di errori segnalati da Google Search Console.
xmlsitemap non funziona ma al contrario simple_sitemap funziona benissimo e fa la medesima cosa.

4) Development Tools
In corso d’opera ho mollato Aptana in favore di PHPStorm stanco dei continui alert per le sintassi PHP 5.6 non supportate. Quando mai non l’ho fatto prima questo passaggio. PHPStorm è una bomba.
Drush nella versione 8 è nell’ordine delle cose che venga affiancato da Composer e Drupal Console ma se uno ha un minimo dimestichezza con Symfony trova solo che giovamento da questa commistione. Ancora adesso però talvolta vado in errore perchè ogni tanto mi scappa un “drush cc all” che in Drupal 8 è stato sostituito da “drush cr all” o “drupal cache:rebuild all”.

5) Hosting
Con Drupal 8, specialmente nei primi 40 giorni dopo il rilascio ufficiale, dove per i moduli contrib gli aggiornamenti erano al ritmo di due al giorni, gestire il sito col il classico meccanismo “porto i file modificati in produzione via ftp” era diventato assurdo. Il rischio di perdere modifiche per strada era diventato un rischio non trascurabile quindi il sito è stato migrato in una struttura che mi permettesse di gestire il progetto con un più azzeccato GIT flow supportato da Composer. Ho implementato https://github.com/drupal-composer/drupal-project e ne sono rimasto molto soddisfatto. Mi dicono però che pure questo https://github.com/vincenzodibiaggio/drupal8_base è molto valido e gestisce le configurazioni del sistema a livello di file e non nel database facilitando la transizione delle modifiche tra ambiente di dev e prod.

Case history: come rendere mobile-friendly uno sito che non prevedeva il responsive design

Case history: come rendere mobile-friendly uno sito che non prevedeva il responsive design

Da Google lo avevano promesso e si è puntalmente verificato: le pagine che presentano incompatibilità con i dispositivi mobile a partire dal 21 di Aprile nelle ricerche effetuate in mobilità vengono penalizzate rispetto a quelle che invece sono compatibili.
Occorre quindi correre ai ripari, mettendo in piedi una strategia che tenga presente i dettami del responsive web design e renda visualizzabile correttamente il sito anche sugli schermi diversi dal classico desktop.

Normalmente la strada più semplice è costruire da zero un nuovo layout, supportato da uno dei tanti framework css ora disponibili (Twitter Bootstrap, ZURB Foundation, Skeleton per citarne alcuni) e aggiungendo poi le regole custom, con un po’ di criterio, preferibilmente con una delle metodologie BEM, che per mezzo delle media queries adatti il contenuto al dispositivo con cui viene visualizzato.

Un’altra soluzione potrebbe essere, se il sito su cui dobbiamo apportare la compatibilità è un CMS popolare come WordPress o Drupal, installare un theme mobile-friendly e mostrare quello specifico layout solo alle utenze mobile.
In WordPress ci viene in aiuto il plugin Any Mobile Theme Switcher mentre in Drupal ci sono due soluzioni fornite da moduli contrib: context_mobile_detect oppure mobile_detect. Entrambe sono valide, il loro uso è condizionato solo dal tipo di approccio attivo sul nostro progetto, Context o ThemeKey appunto.

E se il sito non fosse un CMS ma possedesse comunque un sistema di templating?

E’ proprio questo il caso di cui vi voglio raccontare l’evoluzione.
Il sito è un portale di e-commerce, realizzato con un framework PHP e pubblicato verso la fine del 2011. Il completo refactoring e restyling sono previsti per la fine del 2016. Cosa era possibile fare quindi per non regalare ai competitor tutta l’utenza mobile per un periodo di non meno di 18 mesi?
Ragionando in termini MVC, dal momento che il sito sarebbe stato completamente rifatto di li a poco, era importante fare un intevento in economia, che quindi non prevedesse modifiche ai Model e ai Controller.
Fortunatamente il front end del sito in questione era stato sviluppato con il sistema di griglie molto in voga in quegli anni 960.gs (l’altro framework molto usato era Blueprint) costituendo una solida base di partenza. Questo aspetto di fatto ha ridotto al minimo le modifiche necessarie ai file template responsabili delle View.

  • Primo passo: emulare le media queries. 960gs pur difettando di tutte le utilità responsive a cui ci ha abituato Bootstrap, ha reso disponibile adapt, una libreria javascript che in base al viewport del dispositivo carica il file css dedicato al range in uso.
  • Secondo passo: sfruttare la potenza del processore LESS. Ho preso il vecchio codice legacy e con un tool online l’ho trasformato da CSS a LESS. Niente di trascendentale, eh! Molte regole le ho dovute rivedere manualmente perchè la compilazione in LESS del tool in alcune circostanze era poco significativa. Poco male: ne ho approfittato per rivedere il vecchio codice, togliendo regole obsole e mettendo in pratica la metodologia SMACSS per organizzare il lavoro.
  • Terzo passo: rimpiazzare le regole in cui venivano definite altezze e larghezze fisse. Il punto più ostico è stato adeguare uno slider di immagini presente in home page in modo che fosse anch’esso responsive.
  • Quarto passo: box da 4 colonne nel desktop ma allo stesso tempo da 8 nel mobile. In alcuni punti del sito, come la pagina di dettaglio del prodotto, era indispensabile prevedere che la griglia del layout si comportasse diversamente nelle varie visualizzazioni, con molta più granularità di quello che mette a disposizione 960gs. Ho trovato molto utile il progetto fluidable.com che ho inglobato e personalizzato nel theme.
  • Quinto passo:  non chiudiamo fuori dalla porta le vecchie versioni di IE. Questo si risolve molto agilmente includendo delle librerie specifiche per i HTML5 Shiv e il supporto CSS3 con Selectivizr.

A conti fatti: con 5 giorni di lavoro abbiamo bonificato un aspetto penalizzante lato SEO. Rifare completamente il layout in termini di effort avrebbe comportato tempi superiori di almeno 6 volte.