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!
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