Run prettier

This commit is contained in:
Oliver Davies 2020-03-14 23:39:56 +00:00
parent 49b98d0681
commit 81640d24ed
8 changed files with 398 additions and 437 deletions
dist/getting-your-data-into-drupal-8
src
deploying-drupal-ansible-ansistrano
drupal-testing-workshop
having-fun-drupal-8-drupalorg-api
taking-flight-with-tailwind-css
test-driven-drupal
using-laravel-collections-outside-laravel

View file

@ -1,4 +1,5 @@
- Demonstrate plugins - Demonstrate plugins
- Writing own source/process plugins - Writing own source/process plugins
- Core source plugins (Drupal to Drupal) - Core source plugins (Drupal to Drupal)
- Demo `hook_migrate_prepare_row()` and `hook_migrate_MIGRATION_ID_prepare_row()` - Demo `hook_migrate_prepare_row()` and
`hook_migrate_MIGRATION_ID_prepare_row()`

View file

@ -1,14 +1,11 @@
autoscale: true autoscale: true build-lists: true code: line-height(1.2) header-emphasis:
build-lists: true #53B0EB text: alignment(left) theme: simple, 8
code: line-height(1.2)
header-emphasis: #53B0EB
text: alignment(left)
theme: simple, 8
# [fit] **Deploying PHP applications** <br>using Ansible, Ansible Vault <br>and Ansistrano # [fit] **Deploying PHP applications** <br>using Ansible, Ansible Vault <br>and Ansistrano
^ I work primarily with PHP, and there will be some PHP-isms in this talk (LAMP stack, Composer). ^ I work primarily with PHP, and there will be some PHP-isms in this talk (LAMP
Will be using a Drupal 8 application as the example, but the tools are tool and language agnostic. stack, Composer). Will be using a Drupal 8 application as the example, but the
tools are tool and language agnostic.
--- ---
@ -18,14 +15,13 @@ Will be using a Drupal 8 application as the example, but the tools are tool and
## **What we'll be looking at** ## **What we'll be looking at**
* **Ansible** crash course - **Ansible** crash course
* Keeping secrets with **Ansible Vault** - Keeping secrets with **Ansible Vault**
* Deployments with **Ansistrano** - Deployments with **Ansistrano**
--- ---
[.build-lists: false] [.build-lists: false][.header: #111111]
[.header: #111111]
![right 500%](../images/me-phpnw-inviqa.jpg) ![right 500%](../images/me-phpnw-inviqa.jpg)
@ -37,31 +33,28 @@ Will be using a Drupal 8 application as the example, but the tools are tool and
- @opdavies - @opdavies
- www.oliverdavies.uk - www.oliverdavies.uk
^ Maintain Drupal modules, PHP CLI tools and libraries, Ansible roles ^ Maintain Drupal modules, PHP CLI tools and libraries, Ansible roles Blog on my
Blog on my website website I work primarily with Drupal and Symfony I work for Inviqa, but this
I work primarily with Drupal and Symfony based on my personal and side projects. I've been using Ansible for a number of
I work for Inviqa, but this based on my personal and side projects. years, initially only for provisioning and setting up my laptop, and later for
I've been using Ansible for a number of years, initially only for provisioning and setting up my laptop, and later for application deployments application deployments
--- ---
![350% inline](images/logo-platformsh.png) ![350% inline](images/logo-platformsh.png)
![150% inline](images/logo-acquia.png) ![150% inline](images/logo-acquia.png) ![130% inline](images/logo-pantheon.png)
![130% inline](images/logo-pantheon.png)
^ Large, well-known managed hosting companies ^ Large, well-known managed hosting companies Optimised servers for PHP/Drupal
Optimised servers for PHP/Drupal applications applications Include some sort of deployment system This workflow doesn't apply
Include some sort of deployment system to this scenario
This workflow doesn't apply to this scenario
--- ---
![100%](images/logo-digital-ocean.png) ![100%](images/logo-digital-ocean.png) ![30%](images/logo-linode.png)
![30%](images/logo-linode.png)
![30%](images/logo-vultr.png) ![30%](images/logo-vultr.png)
^ More applicable to virtual or dedicated servers with no existing deployment process ^ More applicable to virtual or dedicated servers with no existing deployment
Not enough budget for fully-managed, or using internal infrastructure process Not enough budget for fully-managed, or using internal infrastructure
This is where the this workflow would be useful This is where the this workflow would be useful
--- ---
@ -82,17 +75,18 @@ This is where the this workflow would be useful
### **What is Ansible?** ### **What is Ansible?**
* CLI tool - CLI tool
* Written in Python - Written in Python
* Configured with YAML - Configured with YAML
* Executes ad-hoc remote commands - Executes ad-hoc remote commands
* Installs software packages - Installs software packages
* Performs deployment steps - Performs deployment steps
* Batteries included - Batteries included
^ Written in Python but you don't need to write or know Python to use it ^ Written in Python but you don't need to write or know Python to use it Drupal,
Drupal, Symfony and a lot of other projects use YAML Symfony and a lot of other projects use YAML First-party modules (SSH keys, file
First-party modules (SSH keys, file and directory management, package repositories, stopping/starting/restarting services, DO/Linode/AWS integration) and directory management, package repositories, stopping/starting/restarting
services, DO/Linode/AWS integration)
--- ---
@ -100,15 +94,15 @@ First-party modules (SSH keys, file and directory management, package repositori
### **What is Ansible?** ### **What is Ansible?**
* Hosts/Inventories - Hosts/Inventories
* Commands - Commands
* Playbooks - Playbooks
* Tasks - Tasks
* Roles - Roles
^ Hosts: where your managed nodes/hosts are. Can be static or dynamic. ^ Hosts: where your managed nodes/hosts are. Can be static or dynamic. Commands:
Commands: run from a control node onto managed nodes run from a control node onto managed nodes Playbooks and Tasks: YAML
Playbooks and Tasks: YAML representation of a series of commands/steps representation of a series of commands/steps
--- ---
@ -116,17 +110,16 @@ Playbooks and Tasks: YAML representation of a series of commands/steps
### **Why Ansible?** ### **Why Ansible?**
* Familiar syntax - Familiar syntax
* Easily readable - Easily readable
* No server dependencies - No server dependencies
* Easy to add to an existing project - Easy to add to an existing project
* Includes relevant modules (e.g. Composer) - Includes relevant modules (e.g. Composer)
* Idempotency - Idempotency
^ Drupal 8, Symfony, Ansible all use YAML ^ Drupal 8, Symfony, Ansible all use YAML Runs on any server with Python Plugins
Runs on any server with Python into Drupal via CLI apps like Drush and Drupal Console Changes are only made
Plugins into Drupal via CLI apps like Drush and Drupal Console when needed (once)
Changes are only made when needed (once)
--- ---
@ -175,7 +168,7 @@ webservers | SUCCESS => {
--- ---
# `ansible all `<br>`-i hosts.yml `<br>`-m command `<br>`-a 'git pull `<br>`--chdir=/app'` # `ansible all`<br>`-i hosts.yml`<br>`-m command`<br>`-a 'git pull`<br>`--chdir=/app'`
--- ---
@ -206,7 +199,7 @@ webservers | SUCCESS => {
--- ---
# `ansible-playbook `<br>`playbook.yml -i hosts.yml` # `ansible-playbook`<br>`playbook.yml -i hosts.yml`
--- ---
@ -313,7 +306,7 @@ ok: [webservers]
TASK [geerlingguy.apache : Include OS-specific variables.] ************************************************************* TASK [geerlingguy.apache : Include OS-specific variables.] *************************************************************
ok: [webservers] ok: [webservers]
TASK [geerlingguy.apache : Include variables for Amazon Linux.] TASK [geerlingguy.apache : Include variables for Amazon Linux.]
skipping: [webservers] skipping: [webservers]
TASK [geerlingguy.apache : Define apache_packages.] ******************************************************************** TASK [geerlingguy.apache : Define apache_packages.] ********************************************************************
@ -444,9 +437,9 @@ $ANSIBLE_VAULT;1.1;AES256
```yaml ```yaml
# vars/vars.yml # vars/vars.yml
--- ---
database_name: "{{ vault_database_name }}" database_name: '{{ vault_database_name }}'
database_user: "{{ vault_database_user }}" database_user: '{{ vault_database_user }}'
database_password: "{{ vault_database_password }}" database_password: '{{ vault_database_password }}'
``` ```
--- ---
@ -488,7 +481,7 @@ tasks:
- name: Uploading application - name: Uploading application
synchronize: synchronize:
src: "{{ playbook_dir }}/../" src: '{{ playbook_dir }}/../'
dest: /app dest: /app
- name: Installing Composer dependencies - name: Installing Composer dependencies
@ -501,9 +494,9 @@ tasks:
# Disadvantages # Disadvantages
* Single point of failure - Single point of failure
* No ability to roll back - No ability to roll back
* Sensitive data stored in plain text - Sensitive data stored in plain text
--- ---
@ -513,20 +506,19 @@ tasks:
![full inline](images/ansistrano.png) ![full inline](images/ansistrano.png)
^ Just another role, specifically for deployments ^ Just another role, specifically for deployments Ansible port of Capistrano
Ansible port of Capistrano
--- ---
# Features # Features
* Multiple release directories - Multiple release directories
* Shared paths and files - Shared paths and files
* Customisable - Customisable
* Multiple deployment strategies - Multiple deployment strategies
* Multi-stage environments - Multi-stage environments
* Prune old releases - Prune old releases
* Rollbacks - Rollbacks
^ rsync, Git, SVN etc ^ rsync, Git, SVN etc
@ -544,7 +536,6 @@ Ansible port of Capistrano
```yaml ```yaml
# deploy.yml # deploy.yml
--- ---
- hosts: all - hosts: all
@ -557,14 +548,14 @@ Ansible port of Capistrano
```yaml ```yaml
# deploy.yml # deploy.yml
--- ---
# ... # ...
vars: vars:
project_deploy_dir: /app project_deploy_dir: /app
ansistrano_deploy_to: '{{ project_deploy_dir }}' ansistrano_deploy_to: '{{ project_deploy_dir }}'
ansistrano_deploy_via: git ansistrano_deploy_via: git
ansistrano_git_branch: master ansistrano_git_branch: master
ansistrano_git_repo: 'git@github.com:opdavies/dransible' ansistrano_git_repo: 'git@github.com:opdavies/dransible'
``` ```
--- ---
@ -673,10 +664,9 @@ drwxr-xr-x 9 4096 Jul 22 20:30 20190722203038Z
![inline 140%](images/ansistrano-flow.png) ![inline 140%](images/ansistrano-flow.png)
^ Shared = files directory, logs ^ Shared = files directory, logs Before/after symlink shared = run tests Symlink
Before/after symlink shared = run tests = 'current' symlink, site is live Clean up = remove node_modules, database
Symlink = 'current' symlink, site is live export, sqlite testing DB
Clean up = remove node_modules, database export, sqlite testing DB
--- ---
@ -685,16 +675,19 @@ Clean up = remove node_modules, database export, sqlite testing DB
--- ---
# ... # ...
ansistrano_after_symlink_shared_tasks_file: '{{ playbook_dir }}/deploy/after-symlink-shared.yml' ansistrano_after_symlink_shared_tasks_file:
ansistrano_after_symlink_tasks_file: '{{ playbook_dir }}/deploy/after-symlink.yml' '{{ playbook_dir }}/deploy/after-symlink-shared.yml'
ansistrano_after_update_code_tasks_file: '{{ playbook_dir }}/deploy/after-update-code.yml' ansistrano_after_symlink_tasks_file:
'{{ playbook_dir }}/deploy/after-symlink.yml'
ansistrano_after_update_code_tasks_file:
'{{ playbook_dir }}/deploy/after-update-code.yml'
release_web_path: '{{ ansistrano_release_path.stdout }}/web' release_web_path: '{{ ansistrano_release_path.stdout }}/web'
release_drush_path: '{{ ansistrano_release_path.stdout }}/vendor/bin/drush' release_drush_path: '{{ ansistrano_release_path.stdout }}/vendor/bin/drush'
``` ```
^ Each step has a 'before' and 'after' step ^ Each step has a 'before' and 'after' step Ansistrano allows us to add more
Ansistrano allows us to add more things by providing a path to a playbook and adding additional steps. things by providing a path to a playbook and adding additional steps.
--- ---
@ -722,7 +715,8 @@ Ansistrano allows us to add more things by providing a path to a playbook and ad
# deploy/after-symlink.yml # deploy/after-symlink.yml
--- ---
- name: Clear Drupal cache - name: Clear Drupal cache
command: '{{ release_drush_path }} --root {{ release_web_path }} cache-rebuild' command:
'{{ release_drush_path }} --root {{ release_web_path }} cache-rebuild'
``` ```
--- ---
@ -741,7 +735,7 @@ Ansistrano allows us to add more things by providing a path to a playbook and ad
vars: vars:
# ... # ...
ansistrano_shared_paths: ansistrano_shared_paths:
- "{{ drupal_root }}/sites/default/files" - '{{ drupal_root }}/sites/default/files'
``` ```
--- ---
@ -786,15 +780,16 @@ vault_database_user: user
vault_database_password: secret vault_database_password: secret
vault_hash_salt: dfgiy$fd2!34gsf2*34g74 vault_hash_salt: dfgiy$fd2!34gsf2*34g74
``` ```
--- ---
```yaml ```yaml
# vars/vars.yml # vars/vars.yml
--- ---
database_name: "{{ vault_database_name }}" database_name: '{{ vault_database_name }}'
database_password: "{{ vault_database_password }}" database_password: '{{ vault_database_password }}'
database_user: "{{ vault_database_user }}" database_user: '{{ vault_database_user }}'
hash_salt: "{{ vault_hash_salt }}" hash_salt: '{{ vault_hash_salt }}'
``` ```
--- ---
@ -864,7 +859,9 @@ $base_url = '{{ item.1.settings.base_url }}';
- name: Create settings files - name: Create settings files
template: template:
src: settings.php.j2 src: settings.php.j2
dest: '{{ item.0.drupal_root }}/sites/{{ item.1.name|default("default") }}/{{ item.1.filename|default("settings.php") }}' dest:
'{{ item.0.drupal_root }}/sites/{{ item.1.name|default("default") }}/{{
item.1.filename|default("settings.php") }}'
with_subelements: with_subelements:
- '{{ drupal_settings }}' - '{{ drupal_settings }}'
- sites - sites
@ -874,6 +871,7 @@ $base_url = '{{ item.1.settings.base_url }}';
--- ---
# **Multiple environments** # **Multiple environments**
## Dev, test, production ## Dev, test, production
--- ---
@ -907,7 +905,7 @@ all:
project_deploy_path: /app project_deploy_path: /app
git_branch: master git_branch: master
drupal_hash_salt: "{{ vault_drupal_hash_salt }}" drupal_hash_salt: '{{ vault_drupal_hash_salt }}'
drupal_install: true drupal_install: true
drupal_settings: drupal_settings:
@ -928,7 +926,7 @@ all:
project_deploy_path: /app-test project_deploy_path: /app-test
git_branch: develop git_branch: develop
drupal_hash_salt: "{{ vault_drupal_hash_salt }}" drupal_hash_salt: '{{ vault_drupal_hash_salt }}'
drupal_install: true drupal_install: true
drupal_settings: drupal_settings:

View file

@ -1,10 +1,5 @@
autoscale: true autoscale: true build-lists: true header-emphasis: #3D85C6 header:
build-lists: true alignment(left) text: alignment(left) text-emphasis: #3D85C6 theme: poster, 8
header-emphasis: #3D85C6
header: alignment(left)
text: alignment(left)
text-emphasis: #3D85C6
theme: poster, 8
code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.5) code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.5)
[.header: alignment(center)] [.header: alignment(center)]
@ -12,6 +7,7 @@ code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.5)
![](../images/title.png) ![](../images/title.png)
# [fit] Drupal Testing Workshop # [fit] Drupal Testing Workshop
### _September 2018_ ### _September 2018_
--- ---
@ -32,15 +28,16 @@ code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.5)
- Drupal core requirement - _<https://www.drupal.org/core/gates#testing>_ - Drupal core requirement - _<https://www.drupal.org/core/gates#testing>_
- More important with regular D8 releases - More important with regular D8 releases
^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst developing rather than after it's been released) ^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst
Refer to tests when writing implementation code developing rather than after it's been released) Refer to tests when writing
ONO merge conflict implementation code ONO merge conflict
--- ---
[.header: alignment(center)] [.header: alignment(center)]
## [fit] _Having tests does not mean_ ## [fit] _Having tests does not mean_
## [fit] there will be no bugs ## [fit] there will be no bugs
--- ---
@ -48,6 +45,7 @@ ONO merge conflict
[.header: alignment(center)] [.header: alignment(center)]
## [fit] _Testing may add time now_ ## [fit] _Testing may add time now_
## [fit] but save more time in the future ## [fit] but save more time in the future
--- ---
@ -68,7 +66,7 @@ ONO merge conflict
- PHP class with _.php_ extension - PHP class with _.php_ extension
- _tests/src_ directory within each module - _tests/src_ directory within each module
- Within the *Drupal\Tests\module_name* namespace - Within the _Drupal\Tests\module_name_ namespace
- Class name must match the filename - Class name must match the filename
- Namespace must match the directory structure - Namespace must match the directory structure
- One test class per feature - One test class per feature
@ -79,6 +77,7 @@ ONO merge conflict
--- ---
### _Exercise 1_ ### _Exercise 1_
## Local site setup ## Local site setup
--- ---
@ -109,11 +108,13 @@ ONO merge conflict
--- ---
### _Exercise 2_ ### _Exercise 2_
## Running Tests ## Running Tests
--- ---
### _Option 1_ ### _Option 1_
## Simpletest module (UI) ## Simpletest module (UI)
--- ---
@ -147,6 +148,7 @@ ONO merge conflict
--- ---
### _Option 2_ ### _Option 2_
## Command line ## Command line
--- ---
@ -181,7 +183,7 @@ cd web/core
--- ---
## Pro-tip: Add paths to _$PATH_ ## Pro-tip: Add paths to _\$PATH_
```bash ```bash
# ~/.zshrc # ~/.zshrc
@ -196,6 +198,7 @@ export PATH=node_modules/.bin:$PATH
--- ---
### _Option 2_ ### _Option 2_
## CLI with Docksal ## CLI with Docksal
--- ---
@ -223,6 +226,7 @@ cd web/core
--- ---
### _Option 3_ ### _Option 3_
## Docksal PHPUnit addon ## Docksal PHPUnit addon
--- ---
@ -234,8 +238,7 @@ cd web/core
- Copies a stub phpunit.xml file if exists, or duplicates phpunit.xml.dist - Copies a stub phpunit.xml file if exists, or duplicates phpunit.xml.dist
- Shorter command, combines two actions - Shorter command, combines two actions
^ Checks for core/phpunit.xml on each test run ^ Checks for core/phpunit.xml on each test run Will create one if is not present
Will create one if is not present
--- ---
@ -271,6 +274,7 @@ fin phpunit web/modules/contrib/examples/phpunit_example
Copying /var/www/web/core/phpunit.xml.dist to /var/www/web/core/phpunit.xml. Copying /var/www/web/core/phpunit.xml.dist to /var/www/web/core/phpunit.xml.
Please edit it's values as needed and re-run 'fin phpunit'. Please edit it's values as needed and re-run 'fin phpunit'.
``` ```
--- ---
``` ```
@ -290,6 +294,7 @@ OK (34 tests, 41 assertions)
--- ---
### _Option 4_ ### _Option 4_
## IDE/text editor integration ## IDE/text editor integration
--- ---
@ -317,8 +322,6 @@ OK (34 tests, 41 assertions)
--- ---
[.header: #3D85C6] [.header: #3D85C6]
## Functional tests ## Functional tests
@ -327,12 +330,12 @@ OK (34 tests, 41 assertions)
- Easiest to start with - Easiest to start with
- Provide most value - Provide most value
^ Less setup steps ^ Less setup steps No mocking etc.
No mocking etc.
--- ---
### _Exercise_ ### _Exercise_
## Let's write a <br>functional test ## Let's write a <br>functional test
--- ---
@ -357,7 +360,6 @@ type: module
--- ---
```php ```php
// ExampleFunctionalTest.php // ExampleFunctionalTest.php
@ -393,10 +395,8 @@ public function test_example_page_exists() {
} }
``` ```
^ Snake case test method names ^ Snake case test method names Still works because it has the 'test' prefix More
Still works because it has the 'test' prefix readable than camel case? Works with Simpletest/D7
More readable than camel case?
Works with Simpletest/D7
--- ---
@ -410,8 +410,7 @@ public function example_page_exists() {
} }
``` ```
^ Remove the prefix, use annotation ^ Remove the prefix, use annotation PHPUnit only
PHPUnit only
--- ---
@ -541,6 +540,7 @@ OK (1 test, 3 assertions)
--- ---
### _Exercise_ ### _Exercise_
## Let's write a <br>kernel test ## Let's write a <br>kernel test
--- ---
@ -692,6 +692,7 @@ OK (1 test, 5 assertions)
--- ---
### _Exercise_ ### _Exercise_
## Let's write a <br>unit test ## Let's write a <br>unit test
--- ---
@ -775,7 +776,6 @@ OK (1 test, 1 assertion)
--- ---
## _Test Driven Development_ ## _Test Driven Development_
- Write a failing test - Write a failing test
@ -785,8 +785,8 @@ OK (1 test, 1 assertion)
--- ---
[.background-color: #FFFFFF] [.background-color:
[.footer: https://github.com/foundersandcoders/testing-tdd-intro] #FFFFFF][.footer: https://github.com/foundersandcoders/testing-tdd-intro]
[.footer-style: #2F2F2F] [.footer-style: #2F2F2F]
![100%](../images/tdd-loop.png) ![100%](../images/tdd-loop.png)
@ -804,8 +804,8 @@ OK (1 test, 1 assertion)
--- ---
### _Exercise_ ### _Exercise_
## Let's build a blog using test driven development
## Let's build a blog using test driven development
--- ---
@ -828,12 +828,14 @@ OK (1 test, 1 assertion)
## _Implementation_ ## _Implementation_
- Use views module - Use views module
- Do the mininum amount at each step, make no assumptions, let the tests guide us - Do the mininum amount at each step, make no assumptions, let the tests guide
us
- Start with functional test - Start with functional test
--- ---
### _Step 1_ ### _Step 1_
## Create the module ## Create the module
--- ---
@ -849,6 +851,7 @@ type: 'module'
--- ---
### _Step 2_ ### _Step 2_
## Ensure the blog page exists ## Ensure the blog page exists
--- ---
@ -869,7 +872,6 @@ class BlogPageTest extends BrowserTestBase {
--- ---
```php ```php
public function testBlogPageExists() { public function testBlogPageExists() {
$this->drupalGet('/blog'); $this->drupalGet('/blog');
@ -880,7 +882,6 @@ public function testBlogPageExists() {
--- ---
``` ```
There was 1 error: There was 1 error:
@ -937,7 +938,7 @@ id: blog
``` ```
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists 1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided
by <em class="placeholder">tdd_blog</em> by <em class="placeholder">tdd_blog</em>
have unmet dependencies: <em class="placeholder">views.view.blog have unmet dependencies: <em class="placeholder">views.view.blog
(node.type.article, node, views)</em> (node.type.article, node, views)</em>
@ -945,7 +946,6 @@ have unmet dependencies: <em class="placeholder">views.view.blog
--- ---
```yml,[.highlight: 1, 7-10] ```yml,[.highlight: 1, 7-10]
# tdd_blog.info.yml # tdd_blog.info.yml
@ -961,10 +961,9 @@ dependencies:
--- ---
``` ```
1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists 1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists
Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided
by <em class="placeholder">tdd_blog</em> have unmet dependencies: by <em class="placeholder">tdd_blog</em> have unmet dependencies:
<em class="placeholder">views.view.blog (node.type.article)</em> <em class="placeholder">views.view.blog (node.type.article)</em>
``` ```
@ -975,7 +974,6 @@ by <em class="placeholder">tdd_blog</em> have unmet dependencies:
--- ---
``` ```
OK (1 test, 3 assertions) OK (1 test, 3 assertions)
``` ```
@ -993,11 +991,11 @@ OK (1 test, 3 assertions)
--- ---
### _Step 3_ ### _Step 3_
## Ensure only published articles are shown ## Ensure only published articles are shown
--- ---
```php ```php
public function testOnlyPublishedArticlesAreShown() { public function testOnlyPublishedArticlesAreShown() {
// Given I have a mixture of published and unpublished articles, // Given I have a mixture of published and unpublished articles,
@ -1012,11 +1010,11 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
### _Option 1_ ### _Option 1_
## Functional tests ## Functional tests
--- ---
```php ```php
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
@ -1043,11 +1041,11 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
### _Option 2_ ### _Option 2_
## Kernel tests ## Kernel tests
--- ---
```php ```php
namespace Drupal\Tests\tdd_blog\Kernel; namespace Drupal\Tests\tdd_blog\Kernel;
@ -1074,10 +1072,8 @@ public function testOnlyPublishedArticlesAreShown() {
} }
``` ```
^ Kernel test approach ^ Kernel test approach Dropping down a level No need for the brower, not
Dropping down a level asserting against HTML Faster to run
No need for the brower, not asserting against HTML
Faster to run
--- ---
@ -1156,7 +1152,8 @@ Failed asserting that actual size 2 matches expected size 1.
--- ---
>- _There is no content type filter on the view_ > - _There is no content type filter on the view_
- Add the filter - Add the filter
- Re-export and save the view - Re-export and save the view
@ -1183,11 +1180,11 @@ OK (1 test, 6 assertions)
--- ---
### _Step 4_ ### _Step 4_
## Ensure the articles are ordered by date ## Ensure the articles are ordered by date
--- ---
```php ```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -1202,7 +1199,6 @@ public function testArticlesAreOrderedByDate() {
--- ---
```php ```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -1232,7 +1228,6 @@ $this->createNode([
--- ---
```php ```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -1267,7 +1262,6 @@ public function testArticlesAreOrderedByDate() {
--- ---
```php ```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -1281,7 +1275,6 @@ public function testArticlesAreOrderedByDate() {
--- ---
``` ```
There was 1 failure: There was 1 failure:
@ -1346,14 +1339,14 @@ OK (1 test, 5 assertions)
- Writing tests is an _investment_ - Writing tests is an _investment_
- OK to _start small_, introduce tests gradually - OK to _start small_, introduce tests gradually
- Easier to _refactor_ - Easier to _refactor_
- Tests can pass, but things can _still be broken_. Tests only report on what they cover. - Tests can pass, but things can _still be broken_. Tests only report on what
they cover.
^ Made me think about how I'm going to do something more starting to do it ^ Made me think about how I'm going to do something more starting to do it Less
Less cruft, only write code that serves a purpose cruft, only write code that serves a purpose Spending time writing tests pays
Spending time writing tests pays dividends later on dividends later on Start by introducing tests for new features or regression
Start by introducing tests for new features or regression tests when fixing bugs tests when fixing bugs If you know things pass, then you can refactor code
If you know things pass, then you can refactor code knowing if something is broken knowing if something is broken Manual testing is still important
Manual testing is still important
--- ---

View file

@ -1,10 +1,10 @@
# Having fun with Drupal 8, PHP libraries Drupal.org API # Having fun with Drupal 8, PHP libraries Drupal.org API
- Open slides - Open slides
- Open Chrome tabs - Open Chrome tabs
- Open PhpStorm for all projects - Open PhpStorm for all projects
- Open Sequel Pro for both DBs - Open Sequel Pro for both DBs
+ Clear cache tables - Clear cache tables
- Start PHP server for each site - Start PHP server for each site
- Start recording - Start recording
@ -12,13 +12,13 @@
- Show in PhpStorm - Show in PhpStorm
- Show readme with examples - Show readme with examples
+ Run test.php - Run test.php
- Show query classes - Show query classes
+ Not drupal coding standards (PSR-2) - Not drupal coding standards (PSR-2)
+ Explain laravel collections - Explain laravel collections
- Show entity classes - Show entity classes
- Show tests - Show tests
+ Show fake query classes - Show fake query classes
- Run tests - Run tests
## Project statistics ## Project statistics
@ -26,18 +26,18 @@
- Show /projects page - Show /projects page
- Show routing - Show routing
- Show ProjectController - Show ProjectController
+ Using PHP 7 return types - Using PHP 7 return types
+ Explain dependency injection - Explain dependency injection
+ Explain about collection - Explain about collection
+ Explain render array - Explain render array
+ Show how to change ordering - Show how to change ordering
- Show ProjectRetriever - Show ProjectRetriever
+ More dependency injection - More dependency injection
+ Show services file - Show services file
- Show settings form - Show settings form
- Add another module (Sophie's simple integrations?) - Add another module (Sophie's simple integrations?)
+ See it loading on projects page - See it loading on projects page
+ See it cached - See it cached
## Drupalversary ## Drupalversary
@ -45,18 +45,18 @@
- Show block - Show block
- Show block form - Show block form
- Show accountretriever - Show accountretriever
+ Highlight caching - Highlight caching
+ Services file - Services file
+ Show cached items in the DB - Show cached items in the DB
- Show routing - Show routing
- Show UserController - Show UserController
+ More dependency injection - More dependency injection
+ Services file - Services file
- Show date parser - Show date parser
+ Show drupalversary model - Show drupalversary model
- Show adding own username via form - Show adding own username via form
+ See it cached - See it cached
+ Show adding uid via form - Show adding uid via form
+ See it cached - See it cached
- Show Dries' because this year drupalversary has passed - Show Dries' because this year drupalversary has passed
- Try with attendee ID - Try with attendee ID

View file

@ -1,5 +1,4 @@
autoscale: true autoscale: true theme: Plain Jane, 1
theme: Plain Jane, 1
# **Taking Flight with <br>Tailwind CSS** # **Taking Flight with <br>Tailwind CSS**
@ -36,10 +35,8 @@ Going to be using Tailwind 1.0 which was released recently (May 13th)
# A **utility-first** CSS framework for rapidly building **custom designs**. # A **utility-first** CSS framework for rapidly building **custom designs**.
^ CSS utility class generator ^ CSS utility class generator PostCSS Make different looking sites using the
PostCSS same class names No "Tailwind looking site" like there is with Bootstrap
Make different looking sites using the same class names
No "Tailwind looking site" like there is with Bootstrap
--- ---
@ -47,11 +44,9 @@ No "Tailwind looking site" like there is with Bootstrap
# Tailwind CSS is a **highly customizable**, **low-level** CSS framework # Tailwind CSS is a **highly customizable**, **low-level** CSS framework
^ No components like Bootstrap or Bulma ^ No components like Bootstrap or Bulma Configure it per project Extendable if
Configure it per project needed via additional plugins Avoids the need to name things prematurely Can
Extendable if needed via additional plugins extract components if needed (reusability)
Avoids the need to name things prematurely
Can extract components if needed (reusability)
--- ---
@ -59,8 +54,10 @@ Can extract components if needed (reusability)
# Tailwind is more than a CSS framework, it's an engine for <br>**creating design systems**. # Tailwind is more than a CSS framework, it's an engine for <br>**creating design systems**.
^ Good default values provided - colours, fonts, padding, widths ^ Good default values provided - colours, fonts, padding, widths Designing with
Designing with constraints. Using inline styles, every value is a magic number. With utilities, you're choosing styles from a predefined design system, which makes it much easier to build visually consistent UIs. constraints. Using inline styles, every value is a magic number. With utilities,
you're choosing styles from a predefined design system, which makes it much
easier to build visually consistent UIs.
--- ---
@ -106,15 +103,22 @@ Designing with constraints. Using inline styles, every value is a magic number.
--- ---
## **Benefits** ## **Benefits**
- You aren't wasting time and energy inventing class names - You aren't wasting time and energy inventing class names
- Your CSS stops growing - Your CSS stops growing
- Making changes feels safer - Making changes feels safer
^ No more adding silly class names like sidebar-inner-wrapper just to be able to style something, and no more agonizing over the perfect abstract name for something that's really just a flex container. ^ No more adding silly class names like sidebar-inner-wrapper just to be able to
style something, and no more agonizing over the perfect abstract name for
something that's really just a flex container.
^ Using a traditional approach, your CSS files get bigger every time you add a new feature. With utilities, everything is reusable so you rarely need to write new CSS. ^ Using a traditional approach, your CSS files get bigger every time you add a
new feature. With utilities, everything is reusable so you rarely need to write
new CSS.
^ CSS is global and you never know what you're breaking when you make a change. Classes in your HTML are local, so you can change them without worrying about something else breaking. ^ CSS is global and you never know what you're breaking when you make a change.
Classes in your HTML are local, so you can change them without worrying about
something else breaking.
--- ---
@ -219,8 +223,9 @@ Designing with constraints. Using inline styles, every value is a magic number.
## **To get the most out of Tailwind, <br>you really should install it via npm.** ## **To get the most out of Tailwind, <br>you really should install it via npm.**
^ - You can't customize Tailwind's default theme ^ - You can't customize Tailwind's default theme
- You can't use any directives like *@apply*, *@variants*, etc.
- You can't enable features like *group-hover* - You can't use any directives like _@apply_, _@variants_, etc.
- You can't enable features like _group-hover_
- You can't install third-party plugins - You can't install third-party plugins
--- ---
@ -244,9 +249,7 @@ Designing with constraints. Using inline styles, every value is a magic number.
[.code-highlight: 2-7] [.code-highlight: 2-7]
```css ```css
# src/css/style.css #src/css/style.css @tailwind base;
@tailwind base;
@tailwind components; @tailwind components;
@ -277,8 +280,7 @@ Designing with constraints. Using inline styles, every value is a magic number.
## **Processing your CSS with Tailwind <br>with the build command** ## **Processing your CSS with Tailwind <br>with the build command**
^ Compile the generated CSS ^ Compile the generated CSS Pass through PostCSS and Tailwind
Pass through PostCSS and Tailwind
--- ---
@ -288,19 +290,19 @@ Pass through PostCSS and Tailwind
```css ```css
.text-left { .text-left {
text-align: left; text-align: left;
} }
.text-center { .text-center {
text-align: center; text-align: center;
} }
.text-right { .text-right {
text-align: right; text-align: right;
} }
.text-justify { .text-justify {
text-align: justify; text-align: justify;
} }
``` ```
@ -317,9 +319,7 @@ Pass through PostCSS and Tailwind
```js ```js
const mix = require('laravel-mix') const mix = require('laravel-mix')
mix.postCss('src/css/app.css', 'dist/css', [ mix.postCss('src/css/app.css', 'dist/css', [require('tailwindcss')()])
require('tailwindcss')()
])
``` ```
^ PostCSS - useful if you're including other PostCSS plugins like PostCSS Nested ^ PostCSS - useful if you're including other PostCSS plugins like PostCSS Nested
@ -331,8 +331,7 @@ const mix = require('laravel-mix')
require('laravel-mix-tailwind') require('laravel-mix-tailwind')
mix.postCss('src/css/app.css', 'dist/css') mix.postCss('src/css/app.css', 'dist/css').tailwind()
.tailwind()
``` ```
--- ---
@ -341,13 +340,11 @@ mix.postCss('src/css/app.css', 'dist/css')
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<title>My new website</title> <title>My new website</title>
<link rel="stylesheet" href="/dist/css/app.css"> <link rel="stylesheet" href="/dist/css/app.css" />
</head> </head>
<body> <body></body>
</body>
</html> </html>
``` ```
@ -359,10 +356,10 @@ mix.postCss('src/css/app.css', 'dist/css')
# `npm run prod` # `npm run prod`
--- ---
# **Interaction states** # **Interaction states**
## hover, focus, group-hover, focus-within ## hover, focus, group-hover, focus-within
^ Start to differ from inline styles ^ Start to differ from inline styles
@ -371,9 +368,9 @@ mix.postCss('src/css/app.css', 'dist/css')
# `.[state][separator][class]` # `.[state][separator][class]`
^ State = hover, focus, group focus, focus within ^ State = hover, focus, group focus, focus within Separator = configurable,
Separator = configurable, colon by default colon by default Class = the same utility class that you would have used
Class = the same utility class that you would have used normally normally
--- ---
@ -594,11 +591,10 @@ colors: {
```js ```js
const mix = require('laravel-mix') const mix = require('laravel-mix')
mix.postCss('src/css/site.css', 'dist/css') mix.postCss('src/css/site.css', 'dist/css').purgeCss({
.purgeCss({ folders: ['templates'],
folders: ['templates'], extensions: ['html', 'php', 'twig'],
extensions: ['html', 'php', 'twig'] })
})
``` ```
--- ---
@ -610,14 +606,14 @@ const mix = require('laravel-mix')
require('laravel-mix-purgecss') require('laravel-mix-purgecss')
mix.postCss('src/css/site.css', 'dist/css') mix.postCss('src/css/site.css', 'dist/css').purgeCss({
.purgeCss({ folders: ['templates'],
folders: ['templates'], extensions: ['html', 'php', 'twig'],
extensions: ['html', 'php', 'twig'] })
})
``` ```
^ Can be tricky using Drupal/WordPress as you don't know where the classes could be coming from, no generated output directory ^ Can be tricky using Drupal/WordPress as you don't know where the classes could
be coming from, no generated output directory
--- ---
@ -631,9 +627,7 @@ mix.postCss('src/css/site.css', 'dist/css')
# Could the duplication <br>**be moved elsewhere**? # Could the duplication <br>**be moved elsewhere**?
^ Twig partials ^ Twig partials Vue components WordPress template parts
Vue components
WordPress template parts
--- ---
@ -672,8 +666,8 @@ WordPress template parts
} %} } %}
``` ```
^ Move the duplicate markup into a partial, so there's only one version ^ Move the duplicate markup into a partial, so there's only one version Pass
Pass data in. data in.
--- ---
@ -689,9 +683,8 @@ a.btn:hover {
} }
``` ```
^ Use utilities as mixins ^ Use utilities as mixins Copy classes from markup Still re-using the same
Copy classes from markup design system and constraints as before
Still re-using the same design system and constraints as before
--- ---
@ -730,12 +723,13 @@ a.btn:hover {
module.exports = { module.exports = {
theme: { theme: {
extend: {} extend: {},
}, },
plugins: [], plugins: [],
variants: {} variants: {},
} }
``` ```
--- ---
[.code-highlight: 5-7] [.code-highlight: 5-7]
@ -746,12 +740,12 @@ module.exports = {
module.exports = { module.exports = {
theme: { theme: {
colors: { colors: {
inherit: 'inherit' inherit: 'inherit',
}, },
extend: {} extend: {},
}, },
plugins: [], plugins: [],
variants: {} variants: {},
} }
``` ```
@ -768,12 +762,12 @@ module.exports = {
theme: { theme: {
extend: { extend: {
colors: { colors: {
inherit: 'inherit' inherit: 'inherit',
} },
} },
}, },
plugins: [], plugins: [],
variants: {} variants: {},
} }
``` ```
@ -790,10 +784,10 @@ module.exports = {
prefix: '', prefix: '',
important: false, important: false,
theme: { theme: {
extend: {} extend: {},
}, },
plugins: [], plugins: [],
variants: {} variants: {},
} }
``` ```
@ -818,12 +812,10 @@ module.exports = {
module.exports = { module.exports = {
theme: { theme: {
extend: {} extend: {},
}, },
plugins: [ plugins: [require('tailwindcss-list-reset')()],
require('tailwindcss-list-reset')() variants: {},
],
variants: {}
} }
``` ```
@ -841,13 +833,16 @@ module.exports = {
```js ```js
// index.js // index.js
module.exports = (variants) => ({ addUtilities }) => { module.exports = variants => ({addUtilities}) => {
addUtilities({ addUtilities(
'.list-reset': { {
listStyle: 'none', '.list-reset': {
padding: 0 listStyle: 'none',
} padding: 0,
}, variants) },
},
variants,
)
} }
``` ```
@ -874,10 +869,11 @@ module.exports = (variants) => ({ addUtilities }) => {
--- ---
# **Thanks!** # **Thanks!**
# opdavi.es/talks/tailwind # opdavi.es/talks/tailwind
## _@opdavies_ <br>_oliverdavies.uk_ ## _@opdavies_ <br>_oliverdavies.uk_
^ Find this talk at opdavi.es/talks/tailwind ^ Find this talk at opdavi.es/talks/tailwind Follow me on Twitter
Follow me on Twitter oliverdavies.uk where I blog about PHP, Drupal, Symfony, automated testing,
oliverdavies.uk where I blog about PHP, Drupal, Symfony, automated testing, Tailwind etc. Tailwind etc. Subscribe to the RSS feed
Subscribe to the RSS feed

View file

@ -1,11 +1,6 @@
theme: poster, 8 theme: poster, 8 autoscale: true build-lists: true header-emphasis: #53B0EB
autoscale: true header: alignment(left) text: alignment(left) text-emphasis: #53B0EB code:
build-lists: true Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.3)
header-emphasis: #53B0EB
header: alignment(left)
text: alignment(left)
text-emphasis: #53B0EB
code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.3)
[.header: alignment(center)] [.header: alignment(center)]
@ -41,10 +36,8 @@ code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.3)
--- ---
[.background-color: #FFFFFF] [.background-color: #FFFFFF][.build-lists: false] [.header:
[.build-lists: false] #111111][.text: #111111, alignment(left)]
[.header: #111111]
[.text: #111111, alignment(left)]
![right 800%](../images/me-phpnw.png) ![right 800%](../images/me-phpnw.png)
@ -57,9 +50,8 @@ code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.3)
- @opdavies - @opdavies
- www.oliverdavies.uk - www.oliverdavies.uk
^ Work at Microserve. ^ Work at Microserve. Maintain Drupal modules, PHP CLI tools and libraries Blog
Maintain Drupal modules, PHP CLI tools and libraries on my website
Blog on my website
--- ---
@ -74,8 +66,7 @@ Blog on my website
--- ---
[.background-color: #FFFFFF] [.background-color: #FFFFFF][.text: #111111, alignment(left)]
[.text: #111111, alignment(left)]
![right 100%](../images/microserve-light.png) ![right 100%](../images/microserve-light.png)
@ -89,10 +80,9 @@ Blog on my website
[.header: alignment(center)] [.header: alignment(center)]
## test_driven_drupal_.com_ ## test*driven_drupal*.com\_
^ Book on automated testing in Drupal 8 ^ Book on automated testing in Drupal 8 Building a conference website
Building a conference website
--- ---
@ -129,12 +119,13 @@ Building a conference website
- Become maintainer in 2012 - Become maintainer in 2012
- Had some existing tests - Had some existing tests
- Used on _11,046 sites_ in October 2012 (_84_ D5, _7,094_ D6, _3,868_ D7) - Used on _11,046 sites_ in October 2012 (_84_ D5, _7,094_ D6, _3,868_ D7)
- Used on _30,572 sites_ in March 2019 (_10_ D5, _1,180_ D6, _24,057_ D7, _5,335_ D8) - Used on _30,572 sites_ in March 2019 (_10_ D5, _1,180_ D6, _24,057_ D7,
_5,335_ D8)
- _#230_ most used module on Drupal.org - _#230_ most used module on Drupal.org
- Crucial to preventing regressions - Crucial to preventing regressions
^ Preventing regressions when adding new features or fixing bugs, but also user submitted patches ^ Preventing regressions when adding new features or fixing bugs, but also user
First module I ported to Drupal 8, aided by tests submitted patches First module I ported to Drupal 8, aided by tests
--- ---
@ -154,9 +145,9 @@ First module I ported to Drupal 8, aided by tests
- Drupal core requirement - _<https://www.drupal.org/core/gates#testing>_ - Drupal core requirement - _<https://www.drupal.org/core/gates#testing>_
- More important with regular D8 releases - More important with regular D8 releases
^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst developing rather than after it's been released) ^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst
Refer to tests when writing implementation code developing rather than after it's been released) Refer to tests when writing
ONO merge conflict implementation code ONO merge conflict
--- ---
@ -164,7 +155,8 @@ ONO merge conflict
- New features should be accompanied by automated tests. - New features should be accompanied by automated tests.
- If the feature does not have an implementation, provide a test implementation. - If the feature does not have an implementation, provide a test implementation.
- Bug fixes should be accompanied by changes to a test (either modifying an existing test case or adding a new one) that demonstrate the bug. - Bug fixes should be accompanied by changes to a test (either modifying an
existing test case or adding a new one) that demonstrate the bug.
[.footer: https://opdavi.es/drupal-core-testing-gate] [.footer: https://opdavi.es/drupal-core-testing-gate]
@ -194,7 +186,7 @@ ONO merge conflict
- PHP class with _.php_ extension - PHP class with _.php_ extension
- _tests/src_ directory within each module - _tests/src_ directory within each module
- Within the *Drupal\Tests\module_name* namespace - Within the _Drupal\Tests\module_name_ namespace
- Class name must match the filename - Class name must match the filename
- Namespace must match the directory structure - Namespace must match the directory structure
- One test class per feature - One test class per feature
@ -206,7 +198,9 @@ ONO merge conflict
[.header: alignment(center)] [.header: alignment(center)]
## _1._ Arrange ## _1._ Arrange
## _2._ Act ## _2._ Act
## _3._ Assert ## _3._ Assert
--- ---
@ -214,7 +208,9 @@ ONO merge conflict
[.header: alignment(center)] [.header: alignment(center)]
## _3._ Assert ## _3._ Assert
## _2._ Act ## _2._ Act
## _1._ Arrange ## _1._ Arrange
--- ---
@ -239,11 +235,8 @@ class ExampleTest extends BrowserTestBase {
} }
``` ```
^ PHP class ^ PHP class Filename matches class name Namespace matches directory structure
Filename matches class name Extend BrowserTestBase Add test method
Namespace matches directory structure
Extend BrowserTestBase
Add test method
--- ---
@ -282,8 +275,8 @@ public function it_does_something() {}
- What provides the most value to the client? - What provides the most value to the client?
- What would you not like to be fixing on a Friday afternoon or after hours? - What would you not like to be fixing on a Friday afternoon or after hours?
^ Payments! Anything related to money. ^ Payments! Anything related to money. What would provide the largest negative
What would provide the largest negative impact to the client if it were to fail? impact to the client if it were to fail?
--- ---
@ -293,7 +286,6 @@ What would provide the largest negative impact to the client if it were to fail?
--- ---
[.header: #53B0EB] [.header: #53B0EB]
## What to test first? ## What to test first?
@ -301,10 +293,9 @@ What would provide the largest negative impact to the client if it were to fail?
- Write a _new test_ when adding any _new functionality_ - Write a _new test_ when adding any _new functionality_
- Write a _regression test_ when _fixing a bug_ - Write a _regression test_ when _fixing a bug_
^ Use tests to replicate the bug ^ Use tests to replicate the bug Could be a new test, or adding to an existing
Could be a new test, or adding to an existing test test Test passes when the bug is fixed That issue cannot be re-added without the
Test passes when the bug is fixed test failing again
That issue cannot be re-added without the test failing again
--- ---
@ -352,9 +343,8 @@ class JobTest extends UnitTestCase {
} }
``` ```
^ Within a Unit directory and namespace ^ Within a Unit directory and namespace Called JobTest because it's testing the
Called JobTest because it's testing the Job class Job class Called testCreate because it's testing the create method
Called testCreate because it's testing the create method
--- ---
@ -404,8 +394,7 @@ class JobTest extends UnitTestCase {
} }
``` ```
^ Retrieve data from the object with getters ^ Retrieve data from the object with getters Asssert that the data is correct.
Asssert that the data is correct.
--- ---
@ -539,8 +528,8 @@ protected function setUp() {
} }
``` ```
^ Because it's a kernel test, we have access to the container ^ Because it's a kernel test, we have access to the container to get the
to get the AdvancedQueue processor service. AdvancedQueue processor service.
--- ---
@ -627,9 +616,7 @@ public function testProcessor() {
- Slower to run - Slower to run
- With/without JavaScript - With/without JavaScript
^ testing profile ^ testing profile Functional/FunctionalJavascript Nightwatch
Functional/FunctionalJavascript
Nightwatch
--- ---
@ -666,8 +653,8 @@ protected function setUp() {
} }
``` ```
^ We have the ability to place blocks ^ We have the ability to place blocks And create users with permissions and log
And create users with permissions and log them in them in
--- ---
@ -710,6 +697,7 @@ public function testQueueDeletion() {
``` ```
--- ---
```php, [.highlight: 12-14] ```php, [.highlight: 12-14]
// tests/src/Functional/QueueTest.php // tests/src/Functional/QueueTest.php
@ -761,21 +749,25 @@ public function testQueueDeletion() {
[.header: #FFFFFF, alignment(left)] [.header: #FFFFFF, alignment(left)]
### _How do I know_ ### _How do I know_
## Which type of test to use? ## Which type of test to use?
--- ---
### _Need a browser?_ ### _Need a browser?_
## Use a functional test ## Use a functional test
--- ---
### _Interact with other services?_ ### _Interact with other services?_
## Use a kernel test ## Use a kernel test
--- ---
### _Isolated PHP code?_ ### _Isolated PHP code?_
## Use a unit test ## Use a unit test
--- ---
@ -786,9 +778,9 @@ public function testQueueDeletion() {
## _Or should you test_ <br>your render array to generate the block? ## _Or should you test_ <br>your render array to generate the block?
^ The answer might be 'both'. ^ The answer might be 'both'. The right type of test to use might not be that
The right type of test to use might not be that obvious. obvious. You may be able to use a different type of test if you take a different
You may be able to use a different type of test if you take a different approach. approach.
--- ---
@ -876,8 +868,7 @@ statusCodeNotEquals()
--- ---
[.background-color: #FFFFFF] [.background-color: #FFFFFF][.footer-style: #2f2f2f]
[.footer-style: #2F2F2F]
![inline 150%](images/broadbean.png) ![inline 150%](images/broadbean.png)
@ -892,7 +883,8 @@ statusCodeNotEquals()
- Jobs need to be linked to offices - Jobs need to be linked to offices
- Job length specified in number of days - Job length specified in number of days
- Path is specified as a field in the API - Path is specified as a field in the API
- Application URL constructed from domain, includes role ID as a GET parameter and optionally UTM parameters - Application URL constructed from domain, includes role ID as a GET parameter
and optionally UTM parameters
--- ---
@ -941,9 +933,10 @@ $data = [
- Added route to accept data from API as XML - Added route to accept data from API as XML
- Added system user with API role to authenticate - Added system user with API role to authenticate
- *active_for* converted from number of days to UNIX timestamp - _active_for_ converted from number of days to UNIX timestamp
- *branch_name* and *locations* converted from plain text to entity reference (job node to office node) - _branch_name_ and _locations_ converted from plain text to entity reference
- *url_alias* property mapped to *path* (job node to office node)
- _url_alias_ property mapped to _path_
--- ---
@ -954,8 +947,7 @@ $data = [
- If no error, create the job node, return OK response to Broadbean - If no error, create the job node, return OK response to Broadbean
- If an Exception is thrown, return an error code and message - If an Exception is thrown, return an error code and message
^ Required field missing ^ Required field missing Incorrect branch name
Incorrect branch name
--- ---
@ -975,9 +967,12 @@ Incorrect branch name
## Types of tests ## Types of tests
- _Unit:_ ensure number of days are converted to timestamps correctly - _Unit:_ ensure number of days are converted to timestamps correctly
- _Kernel:_ job nodes can be added and deleted, expired job nodes are deleted, application URL is generated correctly - _Kernel:_ job nodes can be added and deleted, expired job nodes are deleted,
- _Functional:_ job nodes are created with the correct URL and the correct response code is returned application URL is generated correctly
- _FunctionalJavaScript:_ application URL is updated with JavaScript based on UTM parameters (hosting) - _Functional:_ job nodes are created with the correct URL and the correct
response code is returned
- _FunctionalJavaScript:_ application URL is updated with JavaScript based on
UTM parameters (hosting)
--- ---
@ -998,6 +993,7 @@ Incorrect branch name
--- ---
### _Option 1_ ### _Option 1_
## SimpleTest module (UI) ## SimpleTest module (UI)
--- ---
@ -1031,6 +1027,7 @@ Incorrect branch name
--- ---
### _Option 2_ ### _Option 2_
## Core script ## Core script
--- ---
@ -1046,6 +1043,7 @@ $ php core/scripts/run-tests.sh --class ExampleTest
--- ---
### _Option 3_ ### _Option 3_
## PHPUnit ## PHPUnit
--- ---
@ -1103,8 +1101,8 @@ fin addon install phpunit
fin phpunit modules/custom fin phpunit modules/custom
``` ```
^ Copies a stub phpunit.xml file or copies phpunit.xml.dist ^ Copies a stub phpunit.xml file or copies phpunit.xml.dist Runs the phpunit
Runs the phpunit command within the correct directory command within the correct directory
--- ---
@ -1133,8 +1131,8 @@ Runs the phpunit command within the correct directory
--- ---
[.background-color: #FFFFFF] [.background-color:
[.footer: https://github.com/foundersandcoders/testing-tdd-intro] #FFFFFF][.footer: https://github.com/foundersandcoders/testing-tdd-intro]
[.footer-style: #2F2F2F] [.footer-style: #2F2F2F]
![100%](images/tdd-loop.png) ![100%](images/tdd-loop.png)
@ -1174,6 +1172,7 @@ Runs the phpunit command within the correct directory
[.header: alignment(center)] [.header: alignment(center)]
## [fit] _Building a new Drupal 8 Module with_ ## [fit] _Building a new Drupal 8 Module with_
## [fit] test driven development ## [fit] test driven development
--- ---
@ -1203,12 +1202,14 @@ Runs the phpunit command within the correct directory
## Implementation ## Implementation
- Use views module - Use views module
- Do the mininum amount at each step, make no assumptions, let the tests guide us - Do the mininum amount at each step, make no assumptions, let the tests guide
us
- Start with functional test - Start with functional test
--- ---
### _Step 1_ ### _Step 1_
## Create the module ## Create the module
--- ---
@ -1224,6 +1225,7 @@ type: 'module'
--- ---
### _Step 2_ ### _Step 2_
## Ensure the blog page exists ## Ensure the blog page exists
--- ---
@ -1250,7 +1252,6 @@ class BlogPageTest extends BrowserTestBase {
--- ---
```php, [.highlight: 3] ```php, [.highlight: 3]
// tests/src/Functional/BlogPageTest.php // tests/src/Functional/BlogPageTest.php
@ -1273,7 +1274,6 @@ class BlogPageTest extends BrowserTestBase {
--- ---
```php, [.highlight: 5-7] ```php, [.highlight: 5-7]
// tests/src/Functional/BlogPageTest.php // tests/src/Functional/BlogPageTest.php
@ -1296,7 +1296,6 @@ class BlogPageTest extends BrowserTestBase {
--- ---
```php, [.highlight: 9] ```php, [.highlight: 9]
// tests/src/Functional/BlogPageTest.php // tests/src/Functional/BlogPageTest.php
@ -1319,7 +1318,6 @@ class BlogPageTest extends BrowserTestBase {
--- ---
```php, [.highlight: 11-15] ```php, [.highlight: 11-15]
// tests/src/Functional/BlogPageTest.php // tests/src/Functional/BlogPageTest.php
@ -1342,7 +1340,6 @@ class BlogPageTest extends BrowserTestBase {
--- ---
```bash, [.highlight: 1] ```bash, [.highlight: 1]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1367,7 +1364,6 @@ Tests: 1, Assertions: 3, Errors: 1.
--- ---
```bash, [.highlight: 4] ```bash, [.highlight: 4]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1392,7 +1388,6 @@ Tests: 1, Assertions: 3, Errors: 1.
--- ---
```bash, [.highlight: 5-13] ```bash, [.highlight: 5-13]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1417,7 +1412,6 @@ Tests: 1, Assertions: 3, Errors: 1.
--- ---
```bash, [.highlight: 14-16] ```bash, [.highlight: 14-16]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1442,7 +1436,6 @@ Tests: 1, Assertions: 3, Errors: 1.
--- ---
```bash, [.highlight: 18-19] ```bash, [.highlight: 18-19]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1542,7 +1535,6 @@ Tests: 1, Assertions: 0, Errors: 1.
--- ---
```yml,[.highlight: 1, 7-10] ```yml,[.highlight: 1, 7-10]
# tdd_blog.info.yml # tdd_blog.info.yml
@ -1558,7 +1550,6 @@ dependencies:
--- ---
```[.highlight: 10-13] ```[.highlight: 10-13]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1593,7 +1584,6 @@ Tests: 1, Assertions: 0, Errors: 1.
--- ---
```[.highlight: 5, 9] ```[.highlight: 5, 9]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1619,11 +1609,11 @@ OK (1 test, 3 assertions)
--- ---
### _Step 3_ ### _Step 3_
## Ensure only published articles are shown ## Ensure only published articles are shown
--- ---
```php ```php
public function testOnlyPublishedArticlesAreShown() { public function testOnlyPublishedArticlesAreShown() {
// Given I have a mixture of published and unpublished articles, // Given I have a mixture of published and unpublished articles,
@ -1638,11 +1628,11 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
### _Option 1_ ### _Option 1_
## Functional tests ## Functional tests
--- ---
```php,[.highlight: 1, 4-8] ```php,[.highlight: 1, 4-8]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
@ -1668,7 +1658,6 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
```php,[.highlight: 10-12] ```php,[.highlight: 10-12]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
@ -1692,7 +1681,6 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
```php, [.highlight: 13-17] ```php, [.highlight: 13-17]
// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php
@ -1717,11 +1705,11 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
### _Option 2_ ### _Option 2_
## Kernel tests ## Kernel tests
--- ---
```php ```php
namespace Drupal\Tests\tdd_blog\Kernel; namespace Drupal\Tests\tdd_blog\Kernel;
@ -1743,10 +1731,8 @@ class BlogPageTest extends EntityKernelTestBase {
} }
``` ```
^ Kernel test approach ^ Kernel test approach Dropping down a level No need for the brower, not
Dropping down a level asserting against HTML Faster to run
No need for the brower, not asserting against HTML
Faster to run
--- ---
@ -1819,7 +1805,6 @@ class BlogPageTest extends EntityKernelTestBase {
--- ---
```[.highlight: 9-16] ```[.highlight: 9-16]
docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog/tests/src/Kernel/ docker@cli:/var/www/web$ ../vendor/bin/phpunit -c core modules/custom/tdd_blog/tests/src/Kernel/
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1844,7 +1829,6 @@ Tests: 1, Assertions: 2, Errors: 1.
--- ---
```php, [.highlight: 2] ```php, [.highlight: 2]
public function testOnlyPublishedArticlesAreShown() { public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter']); $this->installConfig(['filter']);
@ -1857,7 +1841,6 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
```php, [.highlight: 8] ```php, [.highlight: 8]
public function testOnlyPublishedArticlesAreShown() { public function testOnlyPublishedArticlesAreShown() {
$this->installConfig(['filter']); $this->installConfig(['filter']);
@ -1872,7 +1855,6 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
```php, [.highlight: 3] ```php, [.highlight: 3]
... ...
@ -1894,7 +1876,6 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
```php, [.highlight: 6] ```php, [.highlight: 6]
... ...
@ -1916,7 +1897,6 @@ public function testOnlyPublishedArticlesAreShown() {
--- ---
```php, [.highlight: 8-15] ```php, [.highlight: 8-15]
... ...
@ -1936,13 +1916,11 @@ public function testOnlyPublishedArticlesAreShown() {
} }
``` ```
^ Assert ^ Assert Should only be one result, should be node 2 Node IDs are reset on each
Should only be one result, should be node 2 test method
Node IDs are reset on each test method
--- ---
``` ```
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1964,7 +1942,6 @@ Tests: 1, Assertions: 4, Failures: 1.
--- ---
```[.highlight: 8-13] ```[.highlight: 8-13]
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -1990,7 +1967,8 @@ Tests: 1, Assertions: 4, Failures: 1.
--- ---
>- _There is no content type filter on the view_ > - _There is no content type filter on the view_
- Add the filter - Add the filter
- Re-export and save the view - Re-export and save the view
@ -2024,11 +2002,11 @@ OK (1 test, 6 assertions)
--- ---
### _Step 4_ ### _Step 4_
## Ensure the articles are ordered by date ## Ensure the articles are ordered by date
--- ---
```php ```php
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -2043,7 +2021,6 @@ public function testArticlesAreOrderedByDate() {
--- ---
```php, [.highlight: 4-9] ```php, [.highlight: 4-9]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -2073,7 +2050,6 @@ $this->createNode([
--- ---
```php, [.highlight: 10-11] ```php, [.highlight: 10-11]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -2116,7 +2092,6 @@ public function testArticlesAreOrderedByDate() {
--- ---
```php, [.highlight: 5-9, 17-18] ```php, [.highlight: 5-9, 17-18]
// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php // modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php
@ -2141,7 +2116,6 @@ public function testArticlesAreOrderedByDate() {
--- ---
``` ```
PHPUnit 6.5.8 by Sebastian Bergmann and contributors. PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
@ -2255,8 +2229,7 @@ OK (1 test, 5 assertions)
![fit](images/tdd-blog-installed.png) ![fit](images/tdd-blog-installed.png)
^ Using the minimal installation profile ^ Using the minimal installation profile Post 3 is unpublished
Post 3 is unpublished
--- ---
@ -2277,45 +2250,49 @@ Post 3 is unpublished
- Writing tests is an _investment_ - Writing tests is an _investment_
- OK to _start small_, introduce tests gradually - OK to _start small_, introduce tests gradually
- Easier to _refactor_ - Easier to _refactor_
- Tests can pass, but things can _still be broken_. Tests only report on what they cover. - Tests can pass, but things can _still be broken_. Tests only report on what
they cover.
^ Made me think about how I'm going to do something more starting to do it ^ Made me think about how I'm going to do something more starting to do it Less
Less cruft, only write code that serves a purpose cruft, only write code that serves a purpose Spending time writing tests pays
Spending time writing tests pays dividends later on dividends later on Start by introducing tests for new features or regression
Start by introducing tests for new features or regression tests when fixing bugs tests when fixing bugs If you know things pass, then you can refactor code
If you know things pass, then you can refactor code knowing if something is broken knowing if something is broken Manual testing is still important
Manual testing is still important
--- ---
[.header: alignment(center)] [.header: alignment(center)]
## [fit] _Having tests does not mean_ ## [fit] _Having tests does not mean_
## [fit] there will be no bugs ## [fit] there will be no bugs
^ Only means that the tests you wrote are passing ^ Only means that the tests you wrote are passing You may not have included a
You may not have included a certain use case certain use case Be sure to test in the UI! We can test what happens in a test
Be sure to test in the UI! when a user has a permission, but in our site we still need to assign the
We can test what happens in a test when a user has a permission, but in our site we still need to assign the permission to a role and the role to a user. permission to a role and the role to a user.
--- ---
### _You might be testing the wrong thing_ ### _You might be testing the wrong thing_
## Maybe it doesn't work the way you think it does ## Maybe it doesn't work the way you think it does
--- ---
### _Have you written enough assertions?_ ### _Have you written enough assertions?_
## Have you only covered the 'happy path' scenarios? ## Have you only covered the 'happy path' scenarios?
^ If your tests are passing but there is an issue, maybe you haven't written enough assertions ^ If your tests are passing but there is an issue, maybe you haven't written
Be sure to check for the negative use cases too enough assertions Be sure to check for the negative use cases too Check that
Check that something is not included as well as what should be included something is not included as well as what should be included What if you pass in
What if you pass in an incorrect value? an incorrect value?
--- ---
### _Other modules can affect things_ ### _Other modules can affect things_
## Tests may pass, but fail when other modules are enabled ## Tests may pass, but fail when other modules are enabled
--- ---
@ -2323,6 +2300,7 @@ What if you pass in an incorrect value?
[.header: alignment(center)] [.header: alignment(center)]
## [fit] _Testing may add time now_ ## [fit] _Testing may add time now_
## [fit] but save more time in the future ## [fit] but save more time in the future
--- ---
@ -2330,20 +2308,21 @@ What if you pass in an incorrect value?
[.header: alignment(center)] [.header: alignment(center)]
## [fit] _How do you get quicker at writing tests?_ ## [fit] _How do you get quicker at writing tests?_
# [fit] By writing more tests # [fit] By writing more tests
^ Practice makes perfect ^ Practice makes perfect Become more familar with and knowledge of recurring
Become more familar with and knowledge of recurring errors errors Find better practices and approaches. Different base classes? Less setup
Find better practices and approaches. Different base classes? Less setup steps. Less time, more productive. steps. Less time, more productive.
--- ---
## _Start small_ ## _Start small_
## Some tests are better than no tests ## Some tests are better than no tests
--- ---
[.background-color: #FFFFFF] [.background-color: #FFFFFF]
![140%](images/tawny-tweet-1.png) ![140%](images/tawny-tweet-1.png)
@ -2371,5 +2350,7 @@ Find better practices and approaches. Different base classes? Less setup steps.
[.header: alignment(center)] [.header: alignment(center)]
# Thanks # Thanks
### _@opdavies_ ### _@opdavies_
### _oliverdavies.uk_ ### _oliverdavies.uk_

View file

@ -1,3 +1,2 @@
- Show composer.json setup - Show composer.json setup
- Add "things you can test" and "things you shouldn't test" - Add "things you can test" and "things you shouldn't test"

View file

@ -1,15 +1,8 @@
theme: poster, 8 theme: poster, 8 autoscale: true build-lists: true header-emphasis: #53B0EB
autoscale: true header: alignment(left) text: alignment(left) text-emphasis: #53B0EB code:
build-lists: true Operator Mono, line-height(1.5)
header-emphasis: #53B0EB
header: alignment(left)
text: alignment(left)
text-emphasis: #53B0EB
code: Operator Mono, line-height(1.5)
[.background-color: #FFFFFF] [.background-color: #FFFFFF][.hide-footer] [.header: #111111, alignment(center)]
[.hide-footer]
[.header: #111111, alignment(center)]
## Using Laravel Collections... <br>Outside Laravel ## Using Laravel Collections... <br>Outside Laravel
@ -21,12 +14,11 @@ code: Operator Mono, line-height(1.5)
## Collections :thumbsup: ## Collections :thumbsup:
^ Became a fan of Collections whilst learning Laravel ^ Became a fan of Collections whilst learning Laravel Powerful object orientated
Powerful object orientated way to interact with arrays way to interact with arrays Store items within the collection, run methods,
Store items within the collection, run methods, chainable chainable More readable, less temporary variables Video on Laracasts, Adam
More readable, less temporary variables Wathan's refactoring to Collections Wanted to use them with different PHP
Video on Laracasts, Adam Wathan's refactoring to Collections projects e.g. Drupal
Wanted to use them with different PHP projects e.g. Drupal
--- ---
@ -36,15 +28,13 @@ collect(['foo', 'bar']); // ['foo', 'bar']
collect('foobar'); // ['foobar'] collect('foobar'); // ['foobar']
$object = new stdClass(); $object = new stdClass();
$object->foo = 'bar'; $object->foo = 'bar';
collect($object); // ['foo' => 'bar'] collect($object); // ['foo' => 'bar']
collect($object)->get('foo'); // bar collect($object)->get('foo'); // bar
``` ```
^ How do you make a collection? ^ How do you make a collection? collect function is provided String, array or
collect function is provided object Stored as items within the Collection object
String, array or object
Stored as items within the Collection object
--- ---
@ -68,10 +58,9 @@ $collection->filter(function ($item) {
}); // [3, 4] }); // [3, 4]
``` ```
^ Once you have a collection, what can you do with it? ^ Once you have a collection, what can you do with it? "contains" - no more
"contains" - no more needle/haystack, haystack/needle needle/haystack, haystack/needle "filter" - filters false, null values Can pass
"filter" - filters false, null values callbacks to `first` and `filter`, return true or false as needed.
Can pass callbacks to `first` and `filter`, return true or false as needed.
--- ---
@ -96,12 +85,12 @@ $collection->filter(function ($person) {
![100%](images/druplicon.png) ![100%](images/druplicon.png)
^ This is great, but how can I do that in my Drupal code? ^ This is great, but how can I do that in my Drupal code? How can I do that?
How can I do that?
--- ---
## Theres a module for that! ## Theres a module for that!
### _- Drupalers_ ### _- Drupalers_
--- ---
@ -109,6 +98,7 @@ How can I do that?
[.text: alignment(center)] [.text: alignment(center)]
## [fit] There's not a module for that. :disappointed: ## [fit] There's not a module for that. :disappointed:
### _- Me_ ### _- Me_
--- ---
@ -119,12 +109,11 @@ How can I do that?
--- ---
### _Version 1.0_ ### _Version 1.0_
## Write my own Collection class ## Write my own Collection class
^ Wrote my own Collection class ^ Wrote my own Collection class Wrote my own tests
Wrote my own tests
--- ---
@ -140,13 +129,14 @@ Wrote my own tests
--- ---
### Collect - Illuminate Collections as a separate package. ### Collect - Illuminate Collections as a separate package.
#### _https://packagist.org/packages/tightenco/collect_ #### _https://packagist.org/packages/tightenco/collect_
--- ---
### Import Laravel's Collections into non-Laravel packages easily, without needing to require the entire Illuminate\Support package. ### Import Laravel's Collections into non-Laravel packages easily, without needing to require the entire Illuminate\Support package.
#### _https://packagist.org/packages/tightenco/collect_ #### _https://packagist.org/packages/tightenco/collect_
--- ---
@ -162,6 +152,7 @@ Wrote my own tests
## _composer require_<br>tightenco/collect ## _composer require_<br>tightenco/collect
--- ---
![](images/drupal-issue-2.png) ![](images/drupal-issue-2.png)
--- ---
@ -171,6 +162,7 @@ Wrote my own tests
--- ---
### _Version 2.0_ ### _Version 2.0_
## Use someone elses Collection class ## Use someone elses Collection class
^ More fully featured, less code to maintain ^ More fully featured, less code to maintain
@ -215,9 +207,8 @@ $collection->each(function ($item) {
}); });
``` ```
^ Require/include autoload.php ^ Require/include autoload.php Start using Collections! `collect` function is
Start using Collections! autoloaded
`collect` function is autoloaded
--- ---
@ -242,5 +233,7 @@ Start using Collections!
[.header: alignment(center)] [.header: alignment(center)]
# Thanks! # Thanks!
### _@opdavies_ ### _@opdavies_
### _oliverdavies.uk_ ### _oliverdavies.uk_