with your friend @weaverryan Its-a me, Ryan! > Lead of the - - PowerPoint PPT Presentation

with your friend weaverryan it s a me ryan
SMART_READER_LITE
LIVE PREVIEW

with your friend @weaverryan Its-a me, Ryan! > Lead of the - - PowerPoint PPT Presentation

with your friend @weaverryan Its-a me, Ryan! > Lead of the Symfony documentation team > Writer for KnpUniversity.com > Symfony fanboy/evangelist > Husband of the much more talented @leannapelham > Father to my more


slide-1
SLIDE 1

with your friend @weaverryan

slide-2
SLIDE 2

> Lead of the Symfony documentation team
 > Writer for KnpUniversity.com > Symfony fanboy/evangelist > Husband of the much more talented @leannapelham

knpuniversity.com twitter.com/weaverryan

It’s-a me, Ryan!

> Father to my more handsome son, Beckett

slide-3
SLIDE 3

You have… a superpower!

@weaverryan

slide-4
SLIDE 4

You know Drupal!

@weaverryan

slide-5
SLIDE 5

@weaverryan

> Object-Oriented Principles > Namespaces > Routes & Controllers* > Service Container* > Events & Event Listeners* > Drupal Console*

Drupal 8 leverages:

* come from Symfony components

slide-6
SLIDE 6

Symfony

@weaverryan

slide-7
SLIDE 7

a collection of small PHP libraries

(the components)

@weaverryan

Symfony is…

slide-8
SLIDE 8

@weaverryan

glue that makes these components work together

The Symfony Framework is…

slide-9
SLIDE 9

@weaverryan

glue that makes these components work together

Drupal is…

???

slide-10
SLIDE 10

Drupal = Route & Controller System

Container

+

full of many services (objects) that do EVERYTHING & give all CMS features

@weaverryan

slide-11
SLIDE 11

Symfony = Route & Controller System

Container

+

full of almost zero services

@weaverryan

slide-12
SLIDE 12

Imagine Drupal… where you uninstalled every single module

(including core)

@weaverryan

That’s Symfony

slide-13
SLIDE 13

@weaverryan

… but you can install all the features you need. Symfony is lean & mean…

slide-14
SLIDE 14

Let’s code!

@weaverryan

Follow the code at: http://bit.ly/dcon18-symfony

slide-15
SLIDE 15

composer create-project symfony/skeleton dcon18

slide-16
SLIDE 16
slide-17
SLIDE 17
slide-18
SLIDE 18

@weaverryan

slide-19
SLIDE 19

Hello Symfony Flex!

slide-20
SLIDE 20

@weaverryan

15 files No Database

slide-21
SLIDE 21

@weaverryan

Let’s start the built-in PHP web server

slide-22
SLIDE 22

@weaverryan

http://localhost:8000/

slide-23
SLIDE 23

Create an API Endpoint

@weaverryan

slide-24
SLIDE 24

@weaverryan

Step 1: Controller

(i.e. function that builds the page)

<?php
 // src/Controller/SongController.php 
 namespace App\Controller;
 
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 
 class SongController extends AbstractController
 {
 public function apiWriteSong()
 {
 return $this->json([
 'I rode my truck, through some mud',
 ]);
 }
 }


slide-25
SLIDE 25

@weaverryan

# config/routes.yaml
 song_api_write_song:
 path: /api/songs
 controller: App\Controller\SongController::apiWriteSong


Step 2: Route

(i.e. URL that points to the controller)

slide-26
SLIDE 26

@weaverryan

* YES! No need to rebuild any cache!

@weaverryan

slide-27
SLIDE 27

@weaverryan

Your project is small

  • service container
  • routing system
  • < 50 services
slide-28
SLIDE 28

Your project is small

> no templating > no database/ORM > no logging > no koopa troopas

slide-29
SLIDE 29

Need something? Install it! Drupal modules = Symfony bundles

@weaverryan

slide-30
SLIDE 30

Install annotations support

@weaverryan

slide-31
SLIDE 31

composer require annotations

slide-32
SLIDE 32

An alias

(see symfony.sh)

slide-33
SLIDE 33

@weaverryan @weaverryan

slide-34
SLIDE 34

Recipes

slide-35
SLIDE 35

@weaverryan

Step 1 (of 1):

Controller & Route

<?php // src/Controller/SongController.php
 
 // ...
 
 class SongController extends AbstractController
 {
 /**
 * @Route("/api/songs")
 */ public function apiWriteSong()
 {
 return $this->json([
 'I rode my truck, through some mud',
 ]);
 }
 }


Hey! Annotations! Like Drupal Plugins!

slide-36
SLIDE 36

Let’s render a template!

(Twig)

@weaverryan

slide-37
SLIDE 37

composer require twig

slide-38
SLIDE 38
slide-39
SLIDE 39

@weaverryan

# config/packages/twig.yaml
 twig:
 paths: ['%kernel.project_dir%/templates']


Automated configuration

Twig

templates/ directory created automatically

slide-40
SLIDE 40

Create a new HTML page

// src/Controller/SongController.php
 // ... 
 /**
 * @Route("/another-song")
 */
 public function writeAnotherSong()
 {
 $song = 'Back-road, boot-scooting, honkey-tonkin CMS';
 
 return $this->render('song/anotherSong.html.twig', [
 'song' => $song,
 ]);
 } {# templates/song/anotherSong.html.twig #}
 {% extends 'base.html.twig' %}
 
 {% block body %}
 <h1>{{ song }}</h1>
 {% endblock %}


slide-41
SLIDE 41

@weaverryan @weaverryan

slide-42
SLIDE 42

@weaverryan

Drupal Console? Symfony has bin/console

slide-43
SLIDE 43

php bin/console debug:twig

slide-44
SLIDE 44

php bin/console debug:router

slide-45
SLIDE 45

Better debugging tools!

(e.g. devel for Symfony)

@weaverryan

slide-46
SLIDE 46

composer require debug

slide-47
SLIDE 47
slide-48
SLIDE 48

@weaverryan @weaverryan

slide-49
SLIDE 49

@weaverryan @weaverryan

slide-50
SLIDE 50

More bundles means more services

(e.g. the “logger” service)

@weaverryan

slide-51
SLIDE 51

public function writeAnotherSong()
 {
 $logger = \Drupal::getContainer()->get('logger');
 
 $logger->debug($song); // ... }

Fetching Services in Drupal

… or you can / should use dependency injection and update a services YML file ( the cheating way)

slide-52
SLIDE 52

Fetching Services in Symfony

use Psr\Log\LoggerInterface;
 // ... public function writeAnotherSong(LoggerInterface $logger)
 {
 $logger->debug($song);
 
 // ...
 }

Just ask for the service you need

slide-53
SLIDE 53

php bin/console debug:autowiring

slide-54
SLIDE 54

Organizing Code

// src/Service/SongGenerator.php
 namespace App\Service;
 
 class SongGenerator
 {
 public function generateSong($noun)
 {
 $title = '...'; // magic song generator
 
 return $title;
 }
 }

slide-55
SLIDE 55

Organizing Code

// src/Controller/SongController.php
 use App\Service\SongGenerator; // ... 
 /**
 * @Route("/api/songs")
 */
 public function apiWriteSong(SongGenerator $songGenerator)
 {
 return $this->json([
 $songGenerator->generateSong('truck'),
 ]);
 }

slide-56
SLIDE 56

Let’s add a Database!

(doctrine)

@weaverryan

slide-57
SLIDE 57

composer require doctrine

slide-58
SLIDE 58
slide-59
SLIDE 59
slide-60
SLIDE 60

# .env
 ###> doctrine/doctrine-bundle ### 
 # Configure other settings in config/packages/doctrine.yaml
 DATABASE_URL=mysql://root:VERYSECURE@127.0.0.1:3306/dcon2018_symfony 
 ###< doctrine/doctrine-bundle ###


.env ≈ settings.php

php bin/console doctrine:database:create

(creates a db… but it’s empty for now)

slide-61
SLIDE 61

composer require maker

php bin/console list make

slide-62
SLIDE 62

@weaverryan

Doctrine *also* has “entities”

  • ne Entity class = one DB table
slide-63
SLIDE 63

php bin/console make:entity

slide-64
SLIDE 64

php bin/console make:entity

slide-65
SLIDE 65

// src/Entity/CountrySong.php
 namespace App\Entity;
 
 use Doctrine\ORM\Mapping as ORM;
 
 class CountrySong
 {
 /**
 * @ORM\Id()
 * @ORM\GeneratedValue()
 * @ORM\Column(type="integer")
 */
 private $id;
 
 /**
 * @ORM\Column(type="string", length=255)
 */
 private $title;
 
 // ... getTitle(), setTitle(), etc methods
 }

slide-66
SLIDE 66

php bin/console make:migration

// src/Migrations/Version20180409012347.php
 
 class Version20180409012347 extends AbstractMigration
 {
 public function up(Schema $schema)
 {
 $this->addSql('CREATE TABLE country_song (id INT AUTO_INCREMENT
 NOT NULL, title VARCHAR(255) NOT NULL, PRIMARY KEY(id))
 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
 ENGINE = InnoDB');
 }
 
 public function down(Schema $schema)
 {
 // ... holds the opposite
 }
 }


slide-67
SLIDE 67

php bin/console doctrine:migrations:migrate

slide-68
SLIDE 68

Let’s create an API endpoint to save new country songs

@weaverryan

slide-69
SLIDE 69

// src/Controller/SongController.php
 use Doctrine\ORM\EntityManagerInterface; /**
 * @Route("/api/songs", methods="POST")
 */
 public function apiWriteSong(SongGenerator $generator, EntityManagerInterface $em)
 {
 $song = new CountrySong();
 $song->setTitle($generator->generateSong('truck'));
 $em->persist($song);
 $em->flush();
 
 return $this->json([
 'title' => $song->getTitle(),
 'id' => $song->getId(),
 ]);
 }

slide-70
SLIDE 70

Hmm… creating the JSON was too much work

@weaverryan

slide-71
SLIDE 71

public function apiWriteSong(SongGenerator $gen, EntityManagerInterface $em)
 {
 $song = new CountrySong();
 $song->setTitle($gen->generateSong('truck'));
 $em->persist($song);
 $em->flush();
 
 return $this->json($song);
 }

does that work? …. noop

slide-72
SLIDE 72

composer require serializer

public function apiWriteSong(SongGenerator $gen, EntityManagerInterface $em)
 {
 $song = new CountrySong();
 $song->setTitle($gen->generateSong('truck'));
 $em->persist($song);
 $em->flush();
 
 return $this->json($song);
 }

slide-73
SLIDE 73

GET /api/songs/{id}

// src/Controller/SongController.php 
 /**
 * @Route("/api/songs/{id}", methods="GET")
 */
 public function apiGetSong(CountrySong $song)
 {
 return $this->json($song);
 }

slide-74
SLIDE 74

Let’s generate a CRUD

@weaverryan

slide-75
SLIDE 75

php bin/console make:crud

slide-76
SLIDE 76

php bin/console make:crud

slide-77
SLIDE 77

@weaverryan @weaverryan

slide-78
SLIDE 78

Security

@weaverryan

slide-79
SLIDE 79

composer require security-checker

slide-80
SLIDE 80

bin/console security:check

Flex will also give you a warning if you try to install a package with a known security vulnerability

slide-81
SLIDE 81

@weaverryan @weaverryan

slide-82
SLIDE 82

Bonus: API Platform

@weaverryan

slide-83
SLIDE 83

// src/Entity/CountrySong.php
 // ...
 
 /**
 * @ApiResource()
 * @ORM\Entity()
 */
 class CountrySong
 {
 // ..
 }

composer require api

slide-84
SLIDE 84

@weaverryan @weaverryan

slide-85
SLIDE 85
slide-86
SLIDE 86
slide-87
SLIDE 87
slide-88
SLIDE 88

http://localhost:8000/country_songs.json

slide-89
SLIDE 89

Bonus: Admin Generator

@weaverryan

slide-90
SLIDE 90

composer require admin

# config/packages/easy_admin.yaml
 easy_admin:
 entities:
 # List the classes you want to manage


  • App\Entity\CountrySong

slide-91
SLIDE 91

@weaverryan @weaverryan

http://localhost:8000/admin

slide-92
SLIDE 92

Bonus: Webpack Encore

@weaverryan

slide-93
SLIDE 93

Drupal & Symfony

great, awkward, friends

@weaverryan

slide-94
SLIDE 94

Drupal Symfony

Routing & Controllers Container modules bundles Console Tool bin/console OOP, namespaces, Composer, etc ✅ ✅

(many services)

(few services)

Plugins Drupal Console ✅ ✅ ✅

slide-95
SLIDE 95

Symfony Starts Tiny

> twig > doctrine > api > logging > cache > debug > … more at symfony.sh

… grows with you…

slide-96
SLIDE 96

Have a project that doesn’t need a CMS?

slide-97
SLIDE 97

Try Symfony!

(it’ll make you even better at Drupal anyways)

github.com/weaverryan/drupalcon18-symfony-for-drupalers

slide-98
SLIDE 98

Ryan Weaver @weaverryan

Free Symfony Video Tutorial: https://knpuniversity.com/tracks/symfony

THANK YOU DRUPALCON!