talks/drupal-vm-symfony-console/2016-07-23-drupalcamp-bristol/index.html
2017-07-02 00:51:42 +01:00

742 lines
22 KiB
HTML
Executable file

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Drupal VM, Meet Symfony Console</title>
<meta name="description" content="Drupal VM, Meet Symfony Console">
<meta name="author" content="Oliver Davies">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/simple.css" id="theme">
<link rel="stylesheet" href="lib/css/tomorrow-night-bright.css">
<link rel="stylesheet" href="assets/css/custom.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1 class="big">Drupal VM, Meet Symfony Console</h1>
<p>
<img class="no-border" src="assets/images/drupalcamp-bristol.png" >
</p>
</section>
<section>
<h2>Oliver Davies (opdavies)</h2>
<div class="col--6-5">
<ul class="bullets medium">
<li>Senior Drupal Developer for Appnovation</li>
<li>Symfony hobbyist</li>
<li>Drupal VM user, Drupal VM Generator maintainer</li>
<li>Drupal Bristol organiser, PHPSW co-organiser, DrupalCamp committee member</li>
</ul>
</div>
<div class="col--6-1">
<img src="assets/images/me_thumb.jpg" class="no-border">
<img src="assets/images/appno.jpg" class="no-border">
<!-- <img src="assets/images/drupal-bristol.jpg" class="no-border"> -->
</div>
</section>
<section>
<h2>Prerequisites</h2>
<ul class="bullets">
<li>Object-orientated PHP</li>
<li>Composer</li>
<li>Autoloading, PSR-4</li>
</ul>
</section>
<section>
<h2>About Drupal VM</h2>
<ul class="bullets">
<li>Virtual machine for Drupal development</li>
<li>Developed and maintained by Jeff Geerling</li>
<li>Vagrant, Ansible</li>
<li>Configured via YAML files</li>
<li>Customisable</li>
</ul>
</section>
<section>
<h2>Using Drupal VM (< 3.0)</h2>
<ul class="bullets">
<li>Download the project</li>
<li>Copy example.config.yml to config.yml</li>
<li>Edit values</li>
<li>Start the VM</li>
</ul>
</section>
<section>
<h2>Using Drupal VM (>= 3.0)</h2>
<ul class="bullets">
<li>Download the project</li>
<li>default.config.yml contains default values</li>
<li>Make config.yml if needed and override values</li>
<li>Start the VM</li>
</ul>
</section>
<section>
<h2>About the Drupal VM Generator</h2>
<ul class="bullets">
<li>Symfony application</li>
<li>Twig</li>
<li>Generates minimal, use-case specific configuration files</li>
<li>http://bit.ly/announcing-drupal-vm-generator</li>
</ul>
</section>
<section>
<h2>Using Drupal VM (>= 3.0)</h2>
<ul class="bullets">
<li>Download the project</li>
<li>default.config.yml contains default values</li>
<li><strong>Make config.yml if needed and override values</strong></li>
<li>Start the VM</li>
</ul>
<aside class="notes">
<ul class="bullets">
<li>Time consuming - 297 lines</li>
<li>Too much cruft</li>
</ul>
</aside>
</section>
<section>
<h2>Drupal VM Generator Example 1</h2>
<img src="assets/images/drupal-vm-generator-example.gif" alt="">
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">Drupal VM Generator Example 2</h2>
<pre><code class="php text-medium">
drupalvm config:generate \
--machine-name="drupalbristol" \
--hostname="drupalbristol.l" \
--ip-address="192.168.88.88" \
--cpus="1" --memory="512" \
--webserver="nginx" --drupal-version="8" \
--database-name="drupal" --database-user="drupal" \
--database-password="drupal" --build-makefile=false \
...
</code></pre>
</section>
<section>
<h2>CLI Examples</h2>
<ul class="bullets">
<li>Drush</li>
<li>Symfony/Drupal Console</li>
<li>Terminus (Pantheon)/Platform.sh</li>
<li>Artisan (Laravel)</li>
<li>Composer</li>
<li>Sculpin</li>
</ul>
</section>
<section>
<h2>CLI Examples</h2>
<ul class="bullets">
<li><s>Drush</s></li>
<li>Symfony/Drupal Console</li>
<li>Terminus (Pantheon)/Platform.sh</li>
<li>Artisan (Laravel)</li>
<li>Composer</li>
<li>Sculpin</li>
</ul>
<aside class="notes">
<ul class="bullets">
<li>All of these except Drush are based on Symfony Console</li>
</ul>
</aside>
</section>
<section data-background="#0076C2" data-background-transition="none">
<h1 class="white big">Symfony Console</h1>
</section>
<section>
<h3 class="title">The Console component eases the creation of beautiful and testable command line interfaces.</h3>
<p>The Console component allows you to create command-line commands. Your console commands can be used for any recurring task, such as cronjobs, imports, or other batch jobs.</p>
<br>
<div class="text-small">
<p>
<a href="http://symfony.com/doc/current/components/console/introduction.html">http://symfony.com/doc/current/components/console/introduction.html</a>
</p>
</div>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">Installation</h2>
<pre><code class="bash text-big" data-trim>
$ composer require symfony/console
$ composer install
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">Installation (cont)</h2>
<pre><code class="json text-big" data-trim>
# composer.json
"require": {
"symfony/console": "^3.1"
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">Installation (cont)</h2>
<pre><code class="php text-big">
# app.php
require __DIR__ . '/vendor/autoload.php';
// Do stuff.
</code></pre>
</section>
<section data-background="#0076C2" data-background-transition="none">
<h2 class="white">Building a Console Application</h2>
</section>
<section>
<h2>Steps</h2>
<ul class="bullets">
<li>Download the Console component</li>
<li>Add an "entry point"</li>
<li>Configure and run an <code>Application</code> class</li>
<li>Add new Commands</li>
</ul>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">bin/drupalcamp</h2>
<pre><code class="php text-big">
#!/usr/bin/env php
require __DIR__ . '/drupalcamp.php';
</code></pre>
<aside class="notes">
<ul class="bullets">
<li>No .php file extension</li>
<li>Formatting issues</li>
<li>Convenience</li>
</ul>
</aside>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">bin/drupalcamp.php</h2>
<pre><code class="php text-medium">
require __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\Console\Application;
$application = new Application();
$application->run();
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<img src="assets/images/console-application-1.png" alt="" style="max-width: 100%">
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">bin/drupalcamp.php (cont)</h2>
<pre><code class="php text-medium">
require __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\Console\Application;
$application = new Application();
$application->run('DrupalCamps', '1.0');
</code></pre>
<aside class="notes">
<ul>
<li>No .php extension</li>
</ul>
</aside>
</section>
<section data-background="#000" data-background-transition="none">
<img src="assets/images/console-application-2.png" alt="">
</section>
<section data-background="#0076C2" data-background-transition="none">
<h2 class="white">Adding Commands</h2>
</section>
<section>
<h2>Adding Commands</h2>
<ul class="bullets">
<li>Add command classes in <code>src/</code></li>
<li>Autoload via Composer</li>
<li>Add to <code>Application</code></li>
</ul>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">Autoloading via Composer</h2>
<pre><code class="php text-big" data-trim>
# composer.json
"autoload": {
"psr-4": {
"": "src/"
}
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">Autoloading via Composer</h2>
<pre><code class="php text-big" data-trim>
# composer.json
"autoload": {
"psr-4": {
"DrupalCamps\\": "src/"
}
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">src/GoCommand.php</h2>
<pre><code class="php text-medium" data-trim>
use Symfony\Component\Console\Command\Command;
class GoCommand extends Command
{
public function configure()
{
$this->setName('go')
->setDescription('Go to a DrupalCamp.');
}
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">src/GoCommand.php (cont)</h2>
<pre><code class="php text-normal">
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
...
public function execute(InputInterface $input, OutputInterface $output)
{
// Execute the command.
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">bin/drupalcamp.php</h2>
<pre><code class="php text-big">
$application = new Application();
$application->add(new GoCommand());
$application->run();
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">bin/drupalcamp.php</h2>
<pre><code class="php text-big">
$application = new Application();
$application->addCommands(
[
new GoCommand(),
]
);
$application->run();
</code></pre>
</section>
<section data-background='#000' data-background-transition="none">
<img src="assets/images/go-command-1.png" alt="">
</section>
<section data-background="#0076C2" data-background-transition="none">
<h2 class="white">Arguments and Options</h2>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">src/GoCommand.php</h2>
<pre><code class="php text-normal" data-trim>
use Symfony\Component\Console\Input\InputArgument;
...
public function configure()
{
$this->setName('go')
->setDescription('Go to a DrupalCamp')
->addArgument('name', InputArgument::OPTIONAL, 'Which DrupalCamp?')
->addOption('past', null, InputOption::VALUE_NONE);
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">src/GoCommand.php (cont)</h2>
<pre><code class="php text-normal" data-trim>
public function execute(InputInterface $input, OutputInterface $output)
{
$text = $input->getArgument('name');
$past = $input->getOption('past');
...
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<img src="assets/images/command-arguments.png" alt="">
</section>
<section data-background="#0076C2" data-background-transition="none">
<h2 class="white">Input and Output</h2>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">InputInterface</h2>
<ul class="bullets">
<pre><code class="php text-big" data-trim>
$input->getArgument('foo');
$input->getOption('bar');
</code></pre>
<aside class="notes">
Gets values inputted by the user.
</aside>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">OutputInterface</h2>
<pre><code class="php text-big" data-trim>
$output->write($text);
$output->writeln($text);
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">OutputInterface</h2>
<pre><code class="php text-big" data-trim>
$output->write("<info>$text</info>");
$output->write("<error>$text</error>");
$output->write("<debug>$text</debug>");
</code></pre>
</section>
<section>
<h2>SymfonyStyle</h2>
<div class="col--6-3">
<ul class="bullets">
<li>title</li>
<li>section</li>
<li>text</li>
<li>comment</li>
<li>note</li>
<li>caution</li>
<li>table</li>
</ul>
</div>
<div class="col--6-3">
<ul class="bullets">
<li>ask</li>
<li>askHidden</li>
<li>confirm</li>
<li>choice</li>
<li>success</li>
<li>error</li>
<li>warning</li>
</ul>
</div>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">SymfonyStyle</h2>
<pre><code class="php text-normal">
public function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$io->table(
['Title', 'Speaker'],
[
['Drupal VM, Meet Symfony Console', 'Oliver Davies'],
['Drupal 8 and the Symfony EventDispatcher', 'Eric Smith'],
['Building with APIs', 'Nigel Dunn'],
]
);
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<img src="assets/images/talks-command.png" alt="">
</section>
<section data-background="#0076C2" data-background-transition="none">
<h2 class="white">Interaction</h2>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">src/GoCommand.php</h2>
<pre><code class="php text-normal">
public function interact(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
if (!$input->getArgument('name')) {
$input->setArgument('name', $io->ask('Which DrupalCamp?'));
}
}
</code></pre>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">src/GoCommand.php</h2>
<pre><code class="php text-normal">
public function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$io->success($input->getArgument('name'));
}
</code></pre>
</section>
<section data-background="#0076C2" data-background-transition="none">
<h2 class="white">Dependency Injection</h2>
</section>
<section>
<h2>Dependency Injection</h2>
<ul class="bullets">
<li>Instantiate dependencies in single place or DI container</li>
<li>Add as arguments when adding commands</li>
<li>Add as arguments to the constructor and assign to properties</li>
</ul>
<h3 class="note">
Make sure to call the __construct() method within the parent class.
</h3>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">src/Console/Application.php</h2>
<pre><code class="php text-medium" data-trim>
use GuzzleHttp\Client;
...
$client = new Client();
$application->add(new NewCommand($client));
</code></pre>
<aside class="notes">
<ul class="bullets">
<li>Example from the Drupal VM Generator</li>
<li>Downloads an archive of Drupal VM from GitHub</li>
<li></li>
</ul>
</aside>
</section>
<section data-background="#000" data-background-transition="none">
<h2 class="white">src/Command/NewCommand.php</h2>
<pre><code class="php text-normal" data-trim>
use GuzzleHttp\ClientInterface;
use Symfony\Component\Console\Command;
final class NewCommand extends Command
{
private $client;
public function __construct(ClientInterface $client)
{
parent::__construct();
$this->client = $client;
}
}
</code></pre>
</section>
<section data-background="#0076C2" data-background-transition="none">
<h2 class="white">Distributing Your Application</h2>
</section>
<section>
<h2>.phar files</h2>
<ul class="bullets">
<li>PHP archive file</li>
<li>Packages your application into one file</li>
<li><code>box build</code></li>
</ul>
</section>
<section data-background='#000' data-background-transition="none">
<h2 class="white">Generating phar files</h2>
<pre><code class="json text-small">
# composer.json
"scripts": {
"build": [
"box build",
"shasum drupalvm.phar |
awk '{print $1}' > drupalvm.phar.version"
]
}
</code></pre>
<pre><code class="bash text-small">
$ composer run-script build
</code></pre>
</section>
<section>
<h2>Roadmap</h2>
<ul class="bullets medium">
<li>Keep up to date with Drupal VM stable releases</li>
<li>New commands - updating existing files, adding vhosts</li>
<li>Improve user defaults and settings</li>
</ul>
</section>
<section>
<h2>Resources</h2>
<ul class="bullets medium">
<li>https://github.com/opdavies/drupal-vm-generator</li>
<li>https://www.drupalvmgenerator.com</li>
<!-- <li>http://docs.drupalvmgenerator.com</li> -->
<li>http://bit.ly/announcing-drupal-vm-generator</li>
<li>http://symfony.com/doc/current/components</li>
<li>http://symfony.com/doc/current/cookbook/console</li>
</ul>
</section>
<section data-background="#0076C2" data-background-transition="none">
<h2 class="white">Questions?</h2>
</section>
<section>
<h2>Feedback</h2>
<ul class="bullets">
<li>@opdavies</li>
<li>https://www.oliverdavies.uk</li>
</ul>
</section>
</div>
</div>
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: false,
progress: true,
history: true,
center: true,
transition: 'none', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/zoom-js/zoom.js', async: true },
{ src: 'plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>