Proof of Concept

&

Prototyping your Ideas

Joël Pittet (joelpittet)

Twitter: @joelpittet

Joël Pittet

  • Drupal 8 Theme System co-maintainer and contrib module commit access collector
  • UBC CS - Web application developer
  • Soccer player

Twitter: @joelpittet

Laziness is the first step towards efficiency.

 Patrick Bennett

Be lazy!

Assumptions

  • You are a programmer/developer or I can inspire you to start.
  • You have Drupal installed locally and have Drush
  • You have a healthy distaste for the mouse

Caveat

  • I'm not an expert at all things and you don't need to be, just helps to be curious and patient

The UI is slow*

* when used lots ;)

Drupal "Throw Away" Scripts

$ drush use @drupalvm.cascadia2017.dev
$ drush php-script ../scripts/throw-away.php

Where do I start?

or better yet see how they do it in Tests!

Google

PHPStorm: cmd-o / ctrl-n EntityTest
drupal 8 programmatically create content type

LIVE DEMO

<?php

use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\node\Entity\NodeType;
use Drupal\node\NodeTypeInterface;
use Symfony\Component\Yaml\Yaml;

// Copied from
// core/modules/node/tests/modules/node_test_config/config/install/node.type.default.yml
$yaml_content_type = <<<'EOC'
type: property
name: Real Estate Property
description: 'Real estate property.'
help: ''
new_revision: true
display_submitted: true
preview_mode: 1
status: true
langcode: en
EOC;

// Parsed from https://api.drupal.org/api/drupal/vendor!symfony!yaml!Yaml.php/function/Yaml%3A%3Aparse/8.2.x
$values = Yaml::parse($yaml_content_type);

// Test the values are in the array that I expect from the YAML parsing.
drush_print_r($values);

// Running this script twice produces a fatal, obviously because the content
// type already exists.
$type = NodeType::load('property');
if ($type) {
  $type->delete();
}
// Found in core/modules/simpletest/src/ContentTypeCreationTrait.php
// ctrl-b to add PHP use statement for NodeType or copy from test.
$type = NodeType::create($values);
$type->save();

node_add_body_field($type);
node_add_size_field($type, 'property_size', [
  'settings' => [
    'max_length' => 3,
  ],
]);

node_add_size_field($type, 'property_price', [
  'label' => 'Price',
  'settings' => [
    'max_length' => 3,
  ],
]);


function node_add_size_field(NodeTypeInterface $type, $field_name = 'property_size', $options = []) {
  $options += [
    'label' => 'Size',
    'field_type' => 'string',
    'widget_type' => 'string_textfield',
    'settings' => [],
  ];

  // Add or remove the field, as needed.
  $field_storage = FieldStorageConfig::loadByName('node', $field_name);
  $field = FieldConfig::loadByName($type->getEntityTypeId(), $type->id(), $field_name);

  // If the field storage config doesn't exist create and save it.
  if (empty($field_storage)) {
    // https://api.drupal.org/api/drupal/core%21modules%21field%21src%21Entity%21FieldStorageConfig.php/class/FieldStorageConfig/8.3.x
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => $type->getEntityTypeId(),
      'type' => $options['field_type'],
      'settings' => $options['settings'],
    ]);
    $field_storage->save();
  }

  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'bundle' => $type->id(),
      'label' => $options['label'],
      // Default storage settings used.
      'settings' => [],
    ]);
    $field->save();

    // Assign widget settings for the 'default' form mode.
    EntityFormDisplay::create([
      'targetEntityType' => $type->getEntityTypeId(),
      'bundle' => $type->id(),
      'mode' => 'default',
      'status' => TRUE,
    ])->setComponent($field_name, [
      'type' =>  $options['widget_type'],
    ])->save();

    // Assign display settings for the 'default' and 'teaser' view modes.
    EntityViewDisplay::create([
      'targetEntityType' => $type->getEntityTypeId(),
      'bundle' => $type->id(),
      'mode' => 'default',
      'status' => TRUE,
    ])->setComponent($field_name, [
      'label' => 'hidden',
      'type' => $options['field_type'],
    ])->save();

    // The teaser view mode is created by the Standard profile and therefore
    // might not exist.
    $view_modes = \Drupal::service('entity.manager')->getViewModes($type->getEntityTypeId());
    if (isset($view_modes['teaser'])) {
      EntityViewDisplay::create([
        'targetEntityType' => $type->getEntityTypeId(),
        'bundle' => $type->id(),
        'mode' => 'teaser',
        'status' => TRUE,
      ])->setComponent($field_name, [
        'label' => 'hidden',
        'type' => $options['field_type'],
      ])->save();
    }
  }

  return $field;
}

Twig Hacking

How install and use Twig without Drupal

$ cd ~/Sites/twig
$ composer require twig/twig:~1.0

Bootstrap Twig

include '../vendor/autoload.php';

// Tell twig where you are putting your templates.
$loader = new Twig_Loader_Filesystem('templates');

$twig_options = [
  'cache' => 'cache',  // Cache folder.
  'autoescape' => TRUE,
  'strict_variables' => FALSE,
  'auto_reload' => TRUE,
];
$twig = new Twig_Environment($loader, $twig_options);

// Pass data in to a twig template and print it.
$data = [
  'title' => 'Card title',
  'caption' => 'Card image cap',
  'content' => 'Some quick example text to build on...',
  'button_text' => 'Go somewhere',
];
print $twig->render('component.twig', $data);

Component

{% extends "index.twig" %}

{% block content %}
  <div class="card" style="width: 20rem;">
    <img class="card-img-top" src="..." alt="{{ caption }}">
    <div class="card-block">
      <h4 class="card-title">{{ title }}</h4>
      <p class="card-text">{{ content }}</p>
      <a href="#" class="btn btn-primary">{{ button_text }}</a>
    </div>
  </div>
{% endblock %}

Result for the component rendered by Twig

Twig Fiddle

Front-End Hacking

HTML

JS

CSS

JS Fiddle

Browser Developer Tools

Firefox Event Inspection

Drupal Test Drives

Questions?

Twitter: @joelpittet

PNWDS 2017 - Proof of Concept & Prototyping your Ideas

By Joel Pittet

PNWDS 2017 - Proof of Concept & Prototyping your Ideas

http://pnwdrupalsummit.org/2017/sessions/proof-concept-prototyping-your-ideas

  • 1,218