Drupal 8 Every Day: An Intro to Developing With Drupal 8

Post on 22-Jan-2018

1.975 views 0 download

Transcript of Drupal 8 Every Day: An Intro to Developing With Drupal 8

Drupal 8 Every DayAn Intro to Developing With Drupal 8

Erin Marchak

● Acquia Certified Front End Specialist, and Developer

● dgo.to/@emarchak

Geoff Appleby

● Acquia Certified Developer

● dgo.to/@gapple

● Persistent Login & drupalreleasedate.com

1. Unboxing

2. Installation

3. Configuration Management

a. Development Workflow

b. Export

c. Import

4. Development

a. Module Generation

b. Page Controllers

c. Entity Bundles

d. Forms

5. Theming

a. Theme Generation

b. Twig Syntax

c. Debugging

d. Including Assets

Unboxing

Unboxing Drupal 8

New Features

Configuration Management

Twig replaces PHPTemplate

PHPUnit supplements SimpleTest

Responsive base theme & admin

Fast by Default

New modules in core

Requirements

Minimum

PHP 5.5.9

MySQL 5.5.3

Recommended

PHP 5.6.5

APCu

New file structureCore is now in ./core

Modules are now in ./modules

Profiles are now in ./profiles

Themes are now in ./themes

Drupal Console

Interactive console

Scaffolding

Site Management

What about Drush?

curl -LSs http://drupalconsole.com/installer | php

Installation

Site Install - site:new

Site Install - site:install

Configuration Management

ProductionDevelopment

Active

Storage

Active

Storage

Code Repository

Sync Storage

ImportExport

Configuration Management

Move database settings to settings.local.php

Uncomment include() statement

Set config sync directory in settings.php

$config_directories[CONFIG_SYNC_DIRECTORY] = __DIR__ . '/config';

cp example.gitignore .gitignore

git add -f sites/default/settings.php

mkdir sites/default/config

Configuration Management - Export

Console creates an archive of YML files

drupal config:export

Drush outputs YML files directly to the sync directory

drush config-export

Configuration Management - Import

Console imports an archive of YML files

drupal config:import [file name]

Drush imports YML files directly from the sync directory

drush config-import

Development

Development - Generate a Custom Module

Development - Generate a Page Controller

Development - ./photography.routing.yml

photography.gallery_controller_gallery:path: '/photography'defaults:

_controller: '\Drupal\photography\Controller\GalleryController::gallery'_title: 'Photography Gallery'

requirements:_permission: 'access content'

photography.order_form:path: '/photography/order'defaults:

_form: '\Drupal\photography\Form\OrderForm'_title: 'Photo Order Form'

requirements:_permission: 'access content'

Development - ./src/Controller/GalleryController.php

/*** @file* Contains Drupal\photography\Controller\GalleryController.*/namespace Drupal\photography\Controller;

use Drupal\Core\Controller\ControllerBase;

/*** Class GalleryController.** @package Drupal\photography\Controller*/class GalleryController extends ControllerBase {

/*** Helper function to load all published photographs.*/public function loadAllPhotos($bundle_type = 'photograph') {...}

/*** Gallery display.*/public function gallery() {...}

}

Development - Generate an Entity Bundle

Development - GalleryController->loadAllPhotos()

/*** Helper function to load all published photographs.** @param string $bundle_type* @return \Drupal\Core\Entity\EntityInterface[]* Array of node objects keyed by nid.*/public function loadAllPhotos($bundle_type = 'photograph') {

// Return the entity manager service and load the the storage instance for nodes.// That way we have access to the enity api while keeping our controller lean.$storage = $this->entityManager()->getStorage('node');

// loadByProperties() allows us to query and load entities in one line!return $storage->loadByProperties(array(

'type' => $bundle_type,'status' => 1,

));

}

Development - GalleryController->gallery()

/*** Gallery display.*/public function gallery() {

$langcode = $this->languageManager()->getCurrentLanguage('language');$photographs = $this->loadAllPhotos();$view_mode = 'teaser';$gallery = array();

// Loop through the loaded photograph node objects and output their rendered result into a list.$viewBuilder = $this->entityManager->getViewBuilder('node');

foreach ($photographs as $photograph) {

$gallery[] = $viewBuilder->view($photograph, $view_mode);

}

// If the gallery is empty, we should apologise.if (empty($gallery)) {...}

// Return an item list of photographs for our gallery.return [

'#theme' => 'item_list','#items' => $gallery,

];}

Development - ./src/Form/OrderForm.php

/*** @file* Contains Drupal\photography\Form\OrderForm.*/namespace Drupal\photography\Form;

use Drupal\Core\Form\FormBase;use Drupal\Core\Form\FormStateInterface;

/*** Class OrderForm.** @package Drupal\photography\Form*/class OrderForm extends FormBase {

public function getFormId() {...}

public function buildForm(array $form, FormStateInterface $form_state) {...}

protected function validPostalCode(string $postal_code) {...}

public function validateForm(array &$form, FormStateInterface $form_state) {...}

public function submitForm(array &$form, FormStateInterface $form_state) {...}

}

Development - ./Tests/src/OrderFormTests.php

/*** @file* Contains Drupal\photography\Tests\OrderFormTest.*/namespace Drupal\photography\Tests;

use Drupal\Tests\UnitTestCase;use Drupal\photography\Form\OrderForm;

/*** Tests validation of postal codes.** @group photography*/class OrderFormTest extends UnitTestCase {

...

/*** Test valid postal codes.*/

public function testPostalCodeValid() {...}

/*** Test invalid postal codes.*/

public function testPostalCodeInvalid() {...}

}

Theming

Theming with Twig - generate:theme

Twig Syntax

PHPTemplate Twig

<?php print $variable ?> {{ variable }}

<?php if (condition): ?> {% if condition %}

<?php foreach ($users as $user): ?>

{% for user in users %}

<?php print t(“string”) ?> {{ “string”|t }}

{%set classes = [

'node','node--type-' ~ node.bundle|clean_class,node.isPromoted() ? 'node--promoted',node.isSticky() ? 'node--sticky',not node.isPublished() ? 'node--unpublished',view_mode ? 'node--view-mode-' ~ view_mode|clean_class,

]%}

{{ attach_library('classy/node') }}

<article{{ attributes.addClass(classes) }}>{{ title_prefix }}

{% if not page %}<h2{{ title_attributes }}>

<a href="{{ url }}" rel="bookmark">{{ label }}</a></h2>

{% endif %}

{{ title_suffix }}

<div{{ content_attributes.addClass('node__content') }}>{{ content }}

</div>

</article>

Twig Debug

sites/default/services.ymlparameters:

twig.config:debug: true

<!-- THEME DEBUG --><!-- THEME HOOK: 'block' --><!-- FILE NAME SUGGESTIONS:

* block--bartik-main-menu.html.twig* block--system-menu-block--main.html.twigx block--system-menu-block.html.twig* block--system.html.twig* block.html.twig

--><!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block--system-menu-block.html.twig' --><nav role="navigation"

aria-labelledby="block-bartik-main-menu-menu" id="block-bartik-main-menu" class="contextual-region block block-menu navigation menu--main">

Adding CSS

portfolio.libraries.ymlglobal-styling:

version: 1.xcss:

theme:css/portfolio-global.css: {}

portfolio.info.ymllibraries:

- portfolio/global-styling

Questions or Comments? We’d love to hear from you!

twitter.com/emarchak

twitter.com/gappleca

twitter.com/myplanetHQ

We can also help with your Drupal projects.

We know how to nudge the big wigs to give D8 a chance.

Extra pair of hands to plug in and help out.

That’s all, folks!

Thank you

Resources

Github Repository https://github.com/gapple/drupal-8-every-day

Database Dump https://drive.google.com/file/d/0B-PTT5Vfuw18RTdId2poQUFNR1E/view

Drupal Console https://www.drupal.org/project/console

Theming Guide https://www.drupal.org/theme-guide/8

CMI Documentation https://www.drupal.org/documentation/administer/config