The Coolest Symfony Components you’ve never heard of - DrupalCon 2017
-
Upload
ryan-weaver -
Category
Technology
-
view
838 -
download
0
Transcript of The Coolest Symfony Components you’ve never heard of - DrupalCon 2017
The Coolest Symfony Components you’ve never
heard of
with your friend @weaverryan
(they’re just hiding in your project, waiting for their big break)
> Lead of the Symfony documentation team
> Writer for KnpUniversity.com
> SensioLabs & Blackfire fanboy/evangelist
> Husband of the much more talented @leannapelham
knpuniversity.com twitter.com/weaverryan
Hallo!
> Father to my more handsome son, Beckett
What is Symfony exactly?
@weaverryan
Symfony: the reason you had to
wait 5 years for Drupal to come out
@weaverryan
Nope!
(well maybe partially, but it was worth it!)
@weaverryan
Symfony is a collection of small PHP libraries
(the components)
@weaverryan
Drupal uses
of these libraries@weaverryan
100%65%80%53%
And how many of the 26 included components
are you using?
@weaverryan
Symfony & Composer
teamwork makes the dream work!
@weaverryan
> ls vendor/symfony
https://www.flickr.com/photos/debabratad/4569271310
> composer show
symfony/debug
@weaverryan
public function build() { $items = []; $items[] = Drupal::root(); return [ '#theme' => 'item_list', '#list_type' => 'ul', '#items' => $items, ];}
Do you want to build a snowman? Or a block?
@weaverryan
@weaverryan
// sites/default/settings.phpuse Symfony\Component\Debug\Debug; Debug::enable();
@weaverryan
public function build() { $items = []; $items[] = \Drupal::root(); return [ '#theme' => 'item_list', '#list_type' => 'ul', '#items' => $items, ];}
Wait! I didn’t need to install it?
@weaverryan
Maybe not???
@weaverryan
@weaverryan
{ "require": { "composer/installers": "^1.0.24", "wikimedia/composer-merge-plugin": "~1.3" }}
composer.json
{ "require": { "symfony/class-loader": "~2.8", "symfony/console": "~2.8", "symfony/dependency-injection": "~2.8", "symfony/event-dispatcher": "~2.8", "symfony/http-foundation": "~2.8", "symfony/http-kernel": "~2.8", "symfony/routing": "~2.8", "symfony/serializer": "~2.8", "symfony/translation": "~2.8", "symfony/validator": "~2.8", "symfony/process": "~2.8", "symfony/polyfill-iconv": "~1.0", "symfony/yaml": "~2.8", "twig/twig": "^1.23.1", }, }
core/composer.json
{ "require": { "composer/installers": "^1.0.24", "wikimedia/composer-merge-plugin": “~1.3", "symfony/debug": "^2.8" }}
composer.json
symfony/finder
@weaverryan
use Symfony\Component\Finder\Finder; $finder = new Finder();$finder->files() ->in(\Drupal::root().'/core/themes/*/templates') ->name('*.twig') ->size('> 1k') ->sortByName(); $items = [];foreach ($finder as $file) { // Cool! But what is $file?}
use Symfony\Component\Finder\Finder; $finder = new Finder();$finder->files() ->in('ftp://example.com/templates/*/templates') ->name('*.twig') ->size('> 1k') ->sortByName(); $items = [];foreach ($finder as $file) { // Cool! But what is $file?}
use Symfony\Component\Finder\Finder; $finder = new Finder();$finder->files() ->in(\Drupal::root().'/core/themes/*/templates') ->name('*.twig') ->size('> 1k') ->sortByName(); $items = [];foreach ($finder as $file) { // Cool! But what is $file?}
symfony/var-dumper
@weaverryan
use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; $finder = new Finder();$finder->files() ->in(\Drupal::root().'/core/themes/*/templates') ->name('*.twig') ->size('> 1k') ->sortByName(); $items = [];foreach ($finder as $file) { dump($file);}
@weaverryan
$items =[];
/** @var SplFileInfo $file */foreach ($finder as $file) { $items[] = sprintf( '%s (%s kb)', $file->getFilename(), round($file->getSize() / 1024) );}
@weaverryan
symfony/console
@weaverryan
// command.phprequire __DIR__.'/vendor/autoload.php'; $app = new Application();$app->register('greet') ->addArgument('name', InputArgument::REQUIRED) ->addOption('yell', null, InputOption::VALUE_NONE) ->setCode(function($input, $output) { $name = $input->getArgument('name'); $greeting = sprintf( 'Hey <comment>'.$name.'!</comment>'); if ($input->getOption('yell')) { $greeting = strtoupper($greeting); } $output->writeln($greeting); });$app->run();
// command.phprequire __DIR__.'/vendor/autoload.php'; $app = new Application();$app->register('greet') ->addArgument('name', InputArgument::REQUIRED) ->addOption('yell', null, InputOption::VALUE_NONE) ->setCode(function($input, $output) { $name = $input->getArgument('name'); $greeting = sprintf( 'Hey <comment>'.$name.'!</comment>'); if ($input->getOption('yell')) { $greeting = strtoupper($greeting); } $output->writeln($greeting); });$app->run();
$app->register('templates:find') ->addArgument('dir', InputArgument::REQUIRED) ->setCode(function($input, $output) { $finder = new Finder(); $finder->files() ->in($input->getArgument('dir')) // ... ; /** @var SplFileInfo $file */ foreach ($finder as $file) { $output->writeln(sprintf( '<comment>%s</comment> <info>%s kb</info>', $file->getFilename(), round($file->getSize() / 1024) )); } });
@weaverryan
But wait, there’s more!
$table = new Table($output); $table->setHeaders(['File', 'Size']);$progress = new ProgressBar($output, count($finder));foreach ($finder as $file) { $table->addRow([ '<comment>'.$file->getFilename().'</comment>', '<info>'.round($file->getSize() / 1024).'</info>' ]); $progress->advance(); usleep(500000);} $progress->clear();$table->render();
$app->register('some-db-process') ->setCode(function($input, $output) { $kernel = new DrupalKernel('prod', $autoloader); $kernel->handle(new Request()); $container = $kernel->getContainer(); $database = $container->get('database'); // do some work in the database! $stmt = $database->query('SHOW TABLES’); dump($stmt); });
symfony/filesystem
@weaverryan
$fs = new Filesystem();$fs->mkdir(__DIR__.'/many/levels/deep');$fs->mirror( __DIR__.'/core/themes/bartik/templates', __DIR__.'/many/levels/deep'); $fs->chmod( Finder::create()->files() ->in(__DIR__.'/many/levels/deep') ->name('block*'), 0777);
symfony/process
@weaverryan
$process = new Process('cowsay Mooooo');$process->setTimeout(5); $process->start();while ($process->isRunning()) { echo 'Running....'; sleep(1); } if (!$process->isSuccessful()) { echo 'Something is wrong with the cow!'; echo $process->getErrorOutput();} else { echo $process->getOutput();}
symfony/lock
@weaverryan
$store = new RedisStore( new \Predis\Client('tcp://localhost:6379') ); $store = new RetryTillSaveStore($store);$factory = new Factory($store); $lock = $factory->createLock('some-lock'); if ($lock->acquire()) { // do you stuff that needs locking! $lock->release();}
symfony/dotenv
@weaverryan
// sites/default/settings.php$databases['default']['default'] = array ( 'database' => getenv('DB_NAME'), 'username' => getenv('DB_USER'), 'password' => getenv('DB_PASS'), 'host' => getenv('DB_HOST'), 'driver' => 'mysql', );
# .envDB_NAME=dcon_baltimoreDB_USER=rootDB_PASS=passDB_HOST=localhost
// sites/default/settings.phpuse Symfony\Component\Dotenv\Dotenv; $dotenv = new Dotenv();$dotenv->load(__DIR__.'/../../.env');$databases['default']['default'] = array ( // ...);
# .envDB_NAME=dcon_baltimoreDB_USER=rootDB_PASS=passDB_HOST=localhostDEBUG=1
# some services.yml file parameters: twig.config: debug: '%env(DEBUG)%'
… and in the future (8.4?) …
symfony/cache
@weaverryan
// create a new item by trying to get it from the cache$numProducts = $cache->getItem('stats.num_products');// assign a value to the item and save it$numProducts->set(4711);$cache->save($numProducts);// retrieve the cache item$numProducts = $cache->getItem('stats.num_products');if (!$numProducts->isHit()) { // ... item does not exists in the cache} // retrieve the value stored by the item$total = $numProducts->get();// remove the cache item$cache->deleteItem('stats.num_products');
@weaverryan
✓choose from many adapters (apcu, db, memcached, redis, etc)
✓cache tagging invalidation
✓expiration
✓free cookies
symfony/expression-language
@weaverryan
# Get the special price ifuser.getGroup() in ['good_customers', 'collaborator']
# Promote article to the homepage whenarticle.commentCount > 100 and article.category not in ["misc"] # Send an alert whenproduct.stock < 15
What if you need to write business logic… that’s stored in the database?
use Symfony\Component\ExpressionLanguage\ExpressionLanguage; $language = new ExpressionLanguage();class Apple{ public $variety; } $apple = new Apple();$apple->variety = 'Honeycrisp'; var_dump($language->evaluate( 'fruit.variety', array( 'fruit' => $apple, )));
# ABC.routing.yml file old_bay_season_food: path: /season/oldbay/{count} # require there to be a ?load=1 on the URL condition: "context.getQueryString() == 'load=1'"
services: # new OldBaySeasoner( # $container->get('config.factory')->get('old_bay.default') # ); old_bay.seasoner: class: Drupal\old_bay\Service\OldBaySeasoner arguments: - '@=service("config.factory").get("old_bay.default")'
maybe in the future???
symfony/property-info
@weaverryan
symfony/workflow
@weaverryan
$definition = new DefinitionBuilder() ->addPlaces(['draft', 'review', 'rejected', 'published']) // Transitions have a unique name, origin place & destination place ->addTransition(new Transition('to_review', 'draft', 'review')) ->addTransition(new Transition('publish', 'review', 'published')) ->addTransition(new Transition('reject', 'review', 'rejected')) ->build(); $marking = new SingleStateMarkingStore('currentState');$workflow = new Workflow($definition, $marking);
$workflow->can($post, 'publish'); // False$workflow->can($post, 'to_review'); // True$workflow->apply($post, 'to_review'); $workflow->can($post, 'publish'); // True // ['publish', 'reject']$workflow->getEnabledTransitions($post);0
symfony/ldap
@weaverryan
symfony/image?
@weaverryan
symfony/utf8?
@weaverryan
symfony/your-laundry?
https://pixabay.com/p-567951/
Drupal is using Symfony
@weaverryan
But are you?
@weaverryan
@weaverryan
@weaverryan
@weaverryan
Side Note: COMPOSER <3’S YOUR INSANE
LEGACY PROJECT
@weaverryan
(that you've been forced to maintain and not allowed to modernize, despite numerous meetings and efforts to explain things to management)
https://www.flickr.com/photos/zzpza/3269784239
You have Drupal modules…
https://www.flickr.com/photos/zzpza/3269784239
~50 Symfony components
https://www.flickr.com/photos/zzpza/3269784239
… and every other PHP package on the planet
So build something ridiculous
@weaverryan
Ryan Weaver @weaverryan
THANK YOU!