SlideShare uma empresa Scribd logo
1 de 119
Baixar para ler offline
Ruling Drupal 8
with
#d8rules
Josef Dabernig, Amazee Labs
@dasjo
• Facet API Pretty Paths
• Geocluster
• Drupal Centroamerica,
Austria, Switzerland, ++
• Deputy Head Technology
@ Amazee Labs
twitter.com/dasjo
• fago (Rules creator)
• klausi (co-maintainer)
• dasjo (communication)
• fubhy (developer)
• nico grienauer (design)
• steve purkiss
(developer)
#d8rules team
Rules
Rules
Rules
Rules
• Build flexible workflows
using events, condition &
actions
• Send customized mails to
notify your users
• Create custom redirections,
system messages,
breadcrumbs
Rules
• Build flexible workflows
using events, condition &
actions
• Send customized mails to
notify your users
• Create custom redirections,
system messages,
breadcrumbs
• 300.000+ reported installs
(30% of all Drupal 7 sites)
• Hundreds of integration
modules
• Entity API, Fields, Views,
Webform, Context, Features,
Search API, Tokens, Paths,
Menus, Queue,
Field formatter conditions, ...
Drupal 8 wins
Drupal 8 wins
• OOP, Dependency
Injection
• APIs
• PHPUnit
• Symfony2
• Removed legacy
modules
• Web services built in
• Front-end, responsive,
...
Drupal 8 for Rules
• Plug-in API
• Entity & Typed Data API
• Conditions API
• (Actions API -> forked)
• Context API shared w/ Core, Page Manager
• Configuration Management (CMI, YAML)
Reusable components (“rtools”)
• Tokens (automatic, based on typed data)
• Typed data widgets & formatters
• Extended Context API
• Embeddable Rules UI components
• Actions & Conditions
• Rules data selector for tokens, contexts
Reusable components (“rtools”)
Site building
• Admin UI usability improvements
• (Simple Views Bulk operations in core)
• “Inline Rules” instead of Rule sets / Rules
conditional
• Deployable configuration
Campaign
#d8rules goals
• Accelerate Drupal 8 uptake by ensuring that
Rules as a key contributed module is ready,
early enough.
• Enable flexible workflows in Drupal 8 sites
that are easily configurable & reusable.
• Make Drupal contributions sustainable by
funding contributed code used on hundreds
of thousands of sites.
drupalfund.us
Sponsors
Funding state
Rules 8.x
development status
Rules 8.x M1
Rules core API fundamentals
✓ Rules core engine, plugin types
✓ Align Rules condition & action APIs with core
✓ Parameter configuration & Context mapping
Rules 8.x M2
Rules core completion with basic UI
✓ Completed Rules engine features
✓ Completed Rules plugins (Events, Loops, API)
✓ Configuration entity, CMI and integrity checks
✓ Basic UI and autocomplete functionality
✓ API for embedding the Rules UI
✓ Twig-style token replacements
Rules 8.x M3
Rules release
❏ Stable Rules 8.x-3.0 Release
❏ Rules Engine follow-ups
❏ Complete Rules UI
❏ Rules scheduler port
❏ Port existing integrations (almost done!)
Rules 8.x
Roadmap
https://www.drupal.org/node/2245015
Sprints, trainings & sessions
Szeged, Portoroz, Austin, Drupalaton, Amsterdam,
Zurich, BogotĂĄ, Vienna, Milano, Montpellier, Bratislava,
Sunderland, Barcelona, Mumbai, Heidelberg, Granada, ..
http://d8rules.org/events
Contribution
• 114 forks, 40 contributors
• paranoik, stevepurkiss, scuts, jibran, chindris,
omissis, ndewhurst, jzavrl, MegaChriz, bbujisic,
dawehner, torenware, bartfeenstra, M1r1k, rinasek,
joashuataylor, lokapujya, icanblink, bojanz, a.
milkovsky, mariancalinro, pjezek,czigor, mikl, nlisgo,
nielsdefeyter, ...
• 427 closed pull requests, Thank you all!
Getting started
• Setup Drupal 8
• Fork Rules 8.x on github:
• https://github.com/fago/rules
Diving into Rules 8.x
Writing
Conditions, Actions &
Events
Plug-ins
• OOP
• Annotations
• Auto-loading
• Discovery
• Derivatives
Provide conditions
• hook_rules_condition_info()
-> ?
Provide conditions
• hook_rules_condition_info
-> Implement a Condition plug-in
/**
* Provides a 'Node is sticky' condition.
*
* @Condition(
* id = "rules_node_is_sticky",
* label = @Translation("Node is sticky"),
* category = @Translation("Node"),
* context = {…}
* )
*/
class NodeIsSticky extends RulesConditionBase {
/**
* {@inheritdoc}
*/
public function evaluate() {
$node = $this->getContextValue('node');
return $node->isSticky();
}
}
Provide actions
• hook_rules_action_info
-> Implement an Action plug-in
/**
* Provides a 'Delete entity' action.
*
* @Action(
* id = "rules_entity_delete",
* label = @Translation("Delete entity"),
* category = @Translation("Entity"),
* context = {…}
* )
*/
class EntityDelete extends RulesActionBase {
/**
* {@inheritdoc}
*/
public function execute() {
$entity = $this->getContextValue('entity');
$entity->delete();
}
}
Provide events
• hook_rules_event_info
-> Specify Symfony event metadata in *.
rules.events.yml
rules_user_login:
label: 'User has logged in'
category: 'User'
context:
account:
type: 'entity:user'
label: 'Logged in user'
Event example from rules.rules.events.yml
Event invocation
/**
* Implements hook_user_login().
*/
function rules_user_login($account) {
// Set the account twice on the event: as the main subject but also in the
// list of arguments.
$event = new UserLoginEvent($account, ['account' => $account]);
$event_dispatcher = Drupal::service('event_dispatcher');
$event_dispatcher->dispatch(UserLoginEvent::EVENT_NAME, $event);
}
Event invocation
/**
* Implements hook_user_login().
*/
function rules_user_login($account) {
// Set the account twice on the event: as the main subject but also in the
// list of arguments.
$event = new UserLoginEvent($account, ['account' => $account]);
$event_dispatcher = Drupal::service('event_dispatcher');
$event_dispatcher->dispatch(UserLoginEvent::EVENT_NAME, $event);
}
Context
Context
● Defining context for a plug-in
/**
* Provides a 'Delete entity' action.
*
* @Action(
* id = "rules_entity_delete",
* label = @Translation("Delete entity"),
* category = @Translation("Entity"),
* context = {…}
* )
*/
class EntityDelete extends RulesActionBase {
/**
* {@inheritdoc}
*/
public function execute() {
$entity = $this->getContextValue('entity');
$entity->delete();
}
}
/**
* Provides a 'Delete entity' action.
*
* @Action(
* id = "rules_entity_delete",
* label = @Translation("Delete entity"),
* category = @Translation("Entity"),
* context = {
* "entity" = @ContextDefinition("entity",
* label = @Translation("Entity"),
* description = @Translation("Specifies the entity,
which should be deleted permanently.")
* )
* }
* )
*/
class EntityDelete extends RulesActionBase {...}
Context
● Defining context for a plug-in
● Using context within a plug-in
class EntityDelete extends RulesActionBase {
/**
* Executes the action with the given context.
*/
public function doExecute(EntityInterface $entity) {
$entity->delete();
}
}
class EntityDelete extends RulesActionBase {
/**
* Executes the action with the given context.
*/
public function doExecute(EntityInterface $entity) {
$entity->delete();
}
}
class FetchEntityById extends RulesActionBase implements
ContainerFactoryPluginInterface {
/**
* Executes the action with the given context.
*/
public function doExecute($entity_type, $entity_id) {
$storage = $this->entityManager->getStorage($entity_type);
$entity = $storage->load($entity_id);
$this->setProvidedValue('entity', $entity);
}
}
class FetchEntityById extends RulesActionBase implements
ContainerFactoryPluginInterface {
/**
* Executes the action with the given context.
*/
public function doExecute($entity_type, $entity_id) {
$storage = $this->entityManager->getStorage($entity_type);
$entity = $storage->load($entity_id);
$this->setProvidedValue('entity', $entity);
}
}
Context
● Defining context for a plug-in
● Using context within a plug-in
● Passing context to the plug-in
class ListCountIsTest extends RulesIntegrationTestBase {
/**
* Tests evaluating the condition.
*
* @covers ::evaluate()
*/
public function testConditionEvaluation() {
// Test that the list count is greater than 2.
$this->condition
->setContextValue('list', [1, 2, 3, 4])
->setContextValue('operator', '>')
->setContextValue('value', '2');
$this->assertTrue($condition->evaluate());
}
}
class ListCountIsTest extends RulesIntegrationTestBase {
/**
* Tests evaluating the condition.
*
* @covers ::evaluate()
*/
public function testConditionEvaluation() {
// Test that the list count is greater than 2.
$this->condition
->setContextValue('list', [1, 2, 3, 4])
->setContextValue('operator', '>')
->setContextValue('value', '2');
$this->assertTrue($condition->evaluate());
}
}
Storing configuration
Storing configuration
• D7: Entity exportables
• Rules:
• RulesPlugin->export()
-> ?
• RulesEntityController->import()
-> ?
Storing configuration
• D7: Entity exportables
• Rules:
• RulesPlugin->export()
-> RulesExpression::getConfiguration()
• RulesEntityController->import()
-> RulesExpression::setConfiguration()
Drupal 8: CMI
● Rules leverages the Config System
● Two types of config entities:
○ Reaction Rules (WIP)
○ Components
● Inherit features from CMI
○ Config deployment / import&export / sync
○ Config Translation (instead of Entity i18n)
○ Default config
Provide default rule configs
• hook_default_rules_configuration()
-> ?
Provide default rule configs
• hook_default_rules_configuration()
-> rules.reaction.*.yml
-> rules.component.*.yml
langcode: en
status: true
dependencies: {}
id: rules_test_default_component
label: Rules test default component
module: rules
description: 'Tests adding Rules component by
default.'
tag: 'test'
core: 8.x
expression_id: rules_rule
configuration:
...
configuration:
id: rules_rule
context:
user:
type: 'entity:user'
label: User
conditions:
id: rules_and
conditions: {}
actions:
id: rules_action_set
actions:
- id: rules_action
action_id: rules_system_message
context_mapping:
message: 'user:mail:value'
Executing the component
$config_entity = RulesComponent::load
('rules_test_default_component');
$expression = $config_entity->getExpression();
$expression
->setContextValue('user', Drupal::currentUser())
->execute();
Describe data to Rules
Drupal 7
• hook_rules_data_info()
-> ?
• hook_entity_property_info_alter
-> ?
Typed Data API
• Consistent way of interacting
with any data based on metadata
• Part of Drupal 8 & Entity Fields
• Defines a type system for PHP:
○ Primitive types (integer, float, string, dates, ..)
○ Complex types
○ Lists (with items of a specified type)
Data types
● any
● string, integer,
uri, float, ...
○ email
○ timestamp,
datetime_iso8601
○ timespan,
duration_iso8601
● entity
○ entity:node
○ entity:comment
● field_item
○ field_item:string
○ field_item:text
○ field_item:image
/**
* The float data type.
*
* The plain value of a float is a regular PHP float. For setting the value
* any PHP variable that casts to a float may be passed.
*
* @DataType(
* id = "float",
* label = @Translation("Float")
* )
*/
class FloatData extends PrimitiveBase implements FloatInterface {
/**
* {@inheritdoc}
*/
public function getCastedValue() {
return (float) $this->value;
}
}
/**
* The float data type.
*
* The plain value of a float is a regular PHP float. For setting the value
* any PHP variable that casts to a float may be passed.
*
* @DataType(
* id = "float",
* label = @Translation("Float")
* )
*/
class FloatData extends PrimitiveBase implements FloatInterface {
/**
* {@inheritdoc}
*/
public function getCastedValue() {
return (float) $this->value;
}
}
/**
* Plugin implementation of the 'link' field type.
*
* @FieldType(
* id = "link",
* label = @Translation("Link"),
* description = @Translation(“..."),
* default_widget = "link_default",
* default_formatter = "link",
* constraints = {"LinkType" = {}}
* )
*/
class LinkItem extends FieldItemBase implements LinkItemInterface {
public static function propertyDefinitions(
FieldStorageDefinitionInterface $field_definition) {
$properties['url'] = DataDefinition::create('string')
->setLabel(t('URL'));
…
return $properties;
}
/**
* Plugin implementation of the 'link' field type.
*
* @FieldType(
* id = "link",
* label = @Translation("Link"),
* description = @Translation(“..."),
* default_widget = "link_default",
* default_formatter = "link",
* constraints = {"LinkType" = {}}
* )
*/
class LinkItem extends FieldItemBase implements LinkItemInterface {
public static function propertyDefinitions(
FieldStorageDefinitionInterface $field_definition) {
$properties['url'] = DataDefinition::create('string')
->setLabel(t('URL'));
…
return $properties;
}
Describe data to rules
• hook_rules_data_info()
-> ?
• hook_entity_property_info_alter
-> ?
Describe data to rules
• hook_rules_data_info()
-> Data type plugins, Typed Data
• hook_entity_property_info_alter
-> hook_data_type_info_alter()
-> hook_entity_base_field_info/alter()
-> hook_entity_bundle_field_info/alter()
-> FieldItem::propertyDefintions()
Every content entity & field type
in Drupal 8 is supported
by Rules out-of-the box!
[META] Rules 8.x UI
Lists & Multiple values
● list<foo> notation is gone
● “list” data type & per data type class
● Separate data definitions for lists vs. list
items
● Mark context as “multiple”
Creating a Rule with context
$rule = $this->expressionManager->createRule([
'context_definitions' => [
'test' => [
'type' => 'string',
'label' => 'Test string',
],
],
]);
$rule = $this->expressionManager->createRule([
'context_definitions' => [
'test' => [
'type' => 'string',
'label' => 'Test string',
],
],
]);
$rule->addCondition('rules_test_string_condition',
ContextConfig::create()
->map('text', 'test')
);
$rule = $this->expressionManager->createRule([
'context_definitions' => [
'test' => [
'type' => 'string',
'label' => 'Test string',
],
],
]);
$rule->addCondition('rules_test_string_condition',
ContextConfig::create()
->map('text', 'test')
);
$rule->addAction('rules_test_log');
$rule = $this->expressionManager->createRule([
'context_definitions' => [
'test' => [
'type' => 'string',
'label' => 'Test string',
],
],
]);
$rule->addCondition('rules_test_string_condition',
ContextConfig::create()
->map('text', 'test')
);
$rule->addAction('rules_test_log');
$rule->setContextValue('test', 'test value');
$rule = $this->expressionManager->createRule([
'context_definitions' => [
'test' => [
'type' => 'string',
'label' => 'Test string',
],
],
]);
$rule->addCondition('rules_test_string_condition',
ContextConfig::create()
->map('text', 'test')
);
$rule->addAction('rules_test_log');
$rule->setContextValue('test', 'test value');
$rule->execute();
Mapping required and provided
context
$rule = $this->expressionManager->createRule();
$rule = $this->expressionManager->createRule();
// Condition provides a "provided_text" variable.
$rule->addCondition('rules_test_provider');
$rule = $this->expressionManager->createRule();
// Condition provides a "provided_text" variable.
$rule->addCondition('rules_test_provider');
// Action provides a "concatenated" variable.
$rule->addAction('rules_test_string',
ContextConfig::create()
->provideAs('text', 'provided_text')
);
$rule = $this->expressionManager->createRule();
// Condition provides a "provided_text" variable.
$rule->addCondition('rules_test_provider');
// Action provides a "concatenated" variable.
$rule->addAction('rules_test_string',
ContextConfig::create()
->provideAs('text', 'provided_text')
);
// Same action again now provides "concatenated2"
$rule->addAction('rules_test_string',
ContextConfig::create()
->map(text, 'concatenated')
->provideAs('concatenated', 'concatenated2')
);
$rule = $this->expressionManager->createRule();
// Condition provides a "provided_text" variable.
$rule->addCondition('rules_test_provider');
// Action provides a "concatenated" variable.
$rule->addAction('rules_test_string',
ContextConfig::create()
->provideAs('text', 'provided_text')
);
// Same action again now provides "concatenated2"
$rule->addAction('rules_test_string',
ContextConfig::create()
->map(text, 'concatenated')
->provideAs('concatenated', 'concatenated2')
);
Advanced / under the hood
Provide other Rules plugins
• hook_rules_plugin_info
-> Implement a RulesExpression plugin
Provide input evaluators
• hook_rules_evaluator_info
-> Implement a RulesDataProcessor
plugin
/**
* A data processor for applying numerical offsets.
*
* The plugin configuration must contain the following entry:
* - offset: the value that should be added.
*
* @RulesDataProcessor(
* id = "rules_numeric_offset",
* label = @Translation("Apply numeric offset")
* )
*/
class NumericOffset extends PluginBase implements
RulesDataProcessorInterface {
/**
* {@inheritdoc}
*/
public function process($value) {
return $value + $this->configuration['offset'];
}
Automated testing
Automated testing
• RulesUnitTestBase extends UnitTestCase
• Internal unit tests such as RuleTest, RulesAndTest,
RulesContextTraitTest, …
Automated testing
• RulesUnitTestBase extends UnitTestCase
• Internal unit tests such as RuleTest, RulesAndTest,
RulesContextTraitTest, …
• RulesIntegrationTestBase
• use ActionManager, ConditionManager,
TypedDataManager, …
class DataListCountIs extends RulesConditionBase {
/**
* {@inheritdoc}
*/
public function evaluate() {
$list = $this->getContextValue('list');
$operator = $this->getContextValue('operator');
$value = $this->getContextValue('value');
switch ($operator) {
case '==':
return count($list) == $value;
case '<';
return count($list) < $value;
case '>';
return count($list) > $value;
}
/**
* Tests evaluating the condition.
*
* @covers ::evaluate()
*/
public function testConditionEvaluation() {
// Test that the list count is greater than 2.
$condition = $this->condition
->setContextValue('list', [1, 2, 3, 4])
->setContextValue('operator', '>')
->setContextValue('value', '2');
$this->assertTrue($condition->evaluate());
// Test that the list count is not equal to 0.
$condition = $this->condition
->setContextValue('list', [1, 2, 3])
->setContextValue('operator', '==')
->setContextValue('value', '0');
$this->assertFalse($condition->evaluate());
}
Automated testing
• RulesUnitTestBase extends UnitTestCase
• Internal unit tests such as RuleTest, RulesAndTest,
RulesContextTraitTest, …
• RulesIntegrationTestBase
• use ActionManager, ConditionManager,
TypedDataManager, …
Automated testing
• RulesUnitTestBase extends UnitTestCase
• Internal unit tests such as RuleTest, RulesAndTest,
RulesContextTraitTest, …
• RulesIntegrationTestBase
• use ActionManager, ConditionManager,
TypedDataManager, …
• RulesEntityIntegrationTestBase
* @Condition(
* id = "rules_entity_is_of_type",
* label = @Translation("Entity is of type"),
* category = @Translation("Entity"),
* context = {
* "entity" = @ContextDefinition("entity",
* label = @Translation("Entity"),
* ),
* "type" = @ContextDefinition("string",
* label = @Translation("Type"),
* )
* }
* )
*/
class EntityIsOfType extends RulesConditionBase {
public function evaluate() {
$provided_entity = $this->getContextValue('entity');
$specified_type = $this->getContextValue('type');
$entity_type = $provided_entity->getEntityTypeId();
/**
* Tests evaluating the condition.
*
* @covers ::evaluate()
*/
public function testConditionEvaluation() {
$entity = $this->getMock('DrupalCoreEntityEntityInterface');
$entity->expects($this->exactly(2))
->method('getEntityTypeId')
->will($this->returnValue('node'));
// Add the test node to our context as the evaluated entity.
// First, test with a value that should evaluate TRUE.
$this->condition->setContextValue('entity', $entity)
->setContextValue('type', 'node');
$this->assertTrue($this->condition->evaluate());
// Then test with values that should evaluate FALSE.
$this->condition->setContextValue('type', 'taxonomy_term');
$this->assertFalse($this->condition->evaluate());
/**
* Tests evaluating the condition.
*
* @covers ::evaluate()
*/
public function testConditionEvaluation() {
$entity = $this->getMock('DrupalCoreEntityEntityInterface');
$entity->expects($this->exactly(2))
->method('getEntityTypeId')
->will($this->returnValue('node'));
// Add the test node to our context as the evaluated entity.
// First, test with a value that should evaluate TRUE.
$this->condition->setContextValue('entity', $entity)
->setContextValue('type', 'node');
$this->assertTrue($this->condition->evaluate());
// Then test with values that should evaluate FALSE.
$this->condition->setContextValue('type', 'taxonomy_term');
$this->assertFalse($this->condition->evaluate());
/**
* Tests evaluating the condition.
*
* @covers ::evaluate()
*/
public function testConditionEvaluation() {
$entity = $this->getMock('DrupalCoreEntityEntityInterface');
$entity->expects($this->exactly(2))
->method('getEntityTypeId')
->will($this->returnValue('node'));
// Add the test node to our context as the evaluated entity.
// First, test with a value that should evaluate TRUE.
$this->condition->setContextValue('entity', $entity)
->setContextValue('type', 'node');
$this->assertTrue($this->condition->evaluate());
// Then test with values that should evaluate FALSE.
$this->condition->setContextValue('type', 'taxonomy_term');
$this->assertFalse($this->condition->evaluate());
/**
* Tests evaluating the condition.
*
* @covers ::evaluate()
*/
public function testConditionEvaluation() {
$entity = $this->getMock('DrupalCoreEntityEntityInterface');
$entity->expects($this->exactly(2))
->method('getEntityTypeId')
->will($this->returnValue('node'));
// Add the test node to our context as the evaluated entity.
// First, test with a value that should evaluate TRUE.
$this->condition->setContextValue('entity', $entity)
->setContextValue('type', 'node');
$this->assertTrue($this->condition->evaluate());
// Then test with values that should evaluate FALSE.
$this->condition->setContextValue('type', 'taxonomy_term');
$this->assertFalse($this->condition->evaluate());
RulesState
RulesState
• variables
• applyDataSelector
• autoSave
Traits
trait StringTranslationTrait {
/**
* The string translation service.
*
* @var DrupalCoreStringTranslationTranslationInterface
*/
protected $stringTranslation;
/**
* Translates a string to the current language or to a given language.
*
* See the t() documentation for details.
*/
protected function t($string, …) {
return $this->getStringTranslation()->translate($string, …);
}
}
class MyClass {
use StringTranslationTrait;
public function __construct(
TranslationInterface $string_translation) {
$this->stringTranslation = $string_translation;
}
/**
* Does something.
*/
public function doSth() {
// ...
$string = $this->t('Something');
// ...
}
}
Traits
• RulesContextTrait
• in addition to ContextAwarePluginBase
• used in RulesActionBase and RulesConditionBase
Outro
Sprint with us!
• Port actions & conditions
• https://www.drupal.org/node/2245015
Sprint with us!
• Port actions & conditions
• https://www.drupal.org/node/2245015
https://www.youtube.com/watch?v=gEH291mq48Y
Fluxkraft UI proposals
Rules Transformers
• https://www.drupal.org/node/2251267
NoFlo

Mais conteĂşdo relacionado

Mais procurados

Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionPhilip Norton
 
«От экспериментов с инфраструктурой до внедрения в продакшен»​
«От экспериментов с инфраструктурой до внедрения в продакшен»​«От экспериментов с инфраструктурой до внедрения в продакшен»​
«От экспериментов с инфраструктурой до внедрения в продакшен»​FDConf
 
Drupal 8 Services
Drupal 8 ServicesDrupal 8 Services
Drupal 8 ServicesPhilip Norton
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejsNick Lee
 
Planbox Backbone MVC
Planbox Backbone MVCPlanbox Backbone MVC
Planbox Backbone MVCAcquisio
 
Viking academy backbone.js
Viking academy  backbone.jsViking academy  backbone.js
Viking academy backbone.jsBert Wijnants
 
Why Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebWhy Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebBryan Helmig
 
IndexedDB - Querying and Performance
IndexedDB - Querying and PerformanceIndexedDB - Querying and Performance
IndexedDB - Querying and PerformanceParashuram N
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of DjangoJacob Kaplan-Moss
 
An Introduction To Testing In AngularJS Applications
An Introduction To Testing In AngularJS Applications An Introduction To Testing In AngularJS Applications
An Introduction To Testing In AngularJS Applications Rohan Chandane
 
AngularJS - $http & $resource Services
AngularJS - $http & $resource ServicesAngularJS - $http & $resource Services
AngularJS - $http & $resource ServicesEyal Vardi
 
The JavaFX Ecosystem
The JavaFX EcosystemThe JavaFX Ecosystem
The JavaFX EcosystemAndres Almiray
 
Geodaten & Drupal 7
Geodaten & Drupal 7Geodaten & Drupal 7
Geodaten & Drupal 7Michael Milz
 
Redux vs Alt
Redux vs AltRedux vs Alt
Redux vs AltUldis Sturms
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS ArchitectureEyal Vardi
 
Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Ivan Chepurnyi
 
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commandsDrupal8Day: Demystifying Drupal 8 Ajax Callback commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commandsMichael Miles
 
Django Celery - A distributed task queue
Django Celery - A distributed task queueDjango Celery - A distributed task queue
Django Celery - A distributed task queueAlex Eftimie
 

Mais procurados (20)

Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency Injection
 
«От экспериментов с инфраструктурой до внедрения в продакшен»​
«От экспериментов с инфраструктурой до внедрения в продакшен»​«От экспериментов с инфраструктурой до внедрения в продакшен»​
«От экспериментов с инфраструктурой до внедрения в продакшен»​
 
Drupal 8 Services
Drupal 8 ServicesDrupal 8 Services
Drupal 8 Services
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 
Planbox Backbone MVC
Planbox Backbone MVCPlanbox Backbone MVC
Planbox Backbone MVC
 
Backbone
BackboneBackbone
Backbone
 
Viking academy backbone.js
Viking academy  backbone.jsViking academy  backbone.js
Viking academy backbone.js
 
Spring 4 - A&BP CC
Spring 4 - A&BP CCSpring 4 - A&BP CC
Spring 4 - A&BP CC
 
Why Task Queues - ComoRichWeb
Why Task Queues - ComoRichWebWhy Task Queues - ComoRichWeb
Why Task Queues - ComoRichWeb
 
IndexedDB - Querying and Performance
IndexedDB - Querying and PerformanceIndexedDB - Querying and Performance
IndexedDB - Querying and Performance
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of Django
 
An Introduction To Testing In AngularJS Applications
An Introduction To Testing In AngularJS Applications An Introduction To Testing In AngularJS Applications
An Introduction To Testing In AngularJS Applications
 
AngularJS - $http & $resource Services
AngularJS - $http & $resource ServicesAngularJS - $http & $resource Services
AngularJS - $http & $resource Services
 
The JavaFX Ecosystem
The JavaFX EcosystemThe JavaFX Ecosystem
The JavaFX Ecosystem
 
Geodaten & Drupal 7
Geodaten & Drupal 7Geodaten & Drupal 7
Geodaten & Drupal 7
 
Redux vs Alt
Redux vs AltRedux vs Alt
Redux vs Alt
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS Architecture
 
Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)
 
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commandsDrupal8Day: Demystifying Drupal 8 Ajax Callback commands
Drupal8Day: Demystifying Drupal 8 Ajax Callback commands
 
Django Celery - A distributed task queue
Django Celery - A distributed task queueDjango Celery - A distributed task queue
Django Celery - A distributed task queue
 

Semelhante a [Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules

Web automation with #d8rules (European Drupal Days 2015)
Web automation with #d8rules (European Drupal Days 2015)Web automation with #d8rules (European Drupal Days 2015)
Web automation with #d8rules (European Drupal Days 2015)Eugenio Minardi
 
Php on the Web and Desktop
Php on the Web and DesktopPhp on the Web and Desktop
Php on the Web and DesktopElizabeth Smith
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenchesLukas Smith
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineYared Ayalew
 
Developing your first application using FI-WARE
Developing your first application using FI-WAREDeveloping your first application using FI-WARE
Developing your first application using FI-WAREFermin Galan
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
Staying Sane with Drupal NEPHP
Staying Sane with Drupal NEPHPStaying Sane with Drupal NEPHP
Staying Sane with Drupal NEPHPOscar Merida
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the TrenchesJonathan Wage
 
Developing your first application using FIWARE
Developing your first application using FIWAREDeveloping your first application using FIWARE
Developing your first application using FIWAREFIWARE
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - TryoutMatthias Noback
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 3camp
 
droidQuery: The Android port of jQuery
droidQuery: The Android port of jQuerydroidQuery: The Android port of jQuery
droidQuery: The Android port of jQueryPhDBrown
 
Practical AngularJS
Practical AngularJSPractical AngularJS
Practical AngularJSWei Ru
 
Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...
Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...
Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...Miguel Gallardo
 
Do you know what your drupal is doing? Observe it!
Do you know what your drupal is doing? Observe it!Do you know what your drupal is doing? Observe it!
Do you know what your drupal is doing? Observe it!Luca Lusso
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Hugo Hamon
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
Building AOL's High Performance, Enterprise Wide Mail Application With Silver...
Building AOL's High Performance, Enterprise Wide Mail Application With Silver...Building AOL's High Performance, Enterprise Wide Mail Application With Silver...
Building AOL's High Performance, Enterprise Wide Mail Application With Silver...goodfriday
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
 
Staying Sane with Drupal (A Develper's Survival Guide)
Staying Sane with Drupal (A Develper's Survival Guide)Staying Sane with Drupal (A Develper's Survival Guide)
Staying Sane with Drupal (A Develper's Survival Guide)Oscar Merida
 

Semelhante a [Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules (20)

Web automation with #d8rules (European Drupal Days 2015)
Web automation with #d8rules (European Drupal Days 2015)Web automation with #d8rules (European Drupal Days 2015)
Web automation with #d8rules (European Drupal Days 2015)
 
Php on the Web and Desktop
Php on the Web and DesktopPhp on the Web and Desktop
Php on the Web and Desktop
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
GDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App EngineGDG Addis - An Introduction to Django and App Engine
GDG Addis - An Introduction to Django and App Engine
 
Developing your first application using FI-WARE
Developing your first application using FI-WAREDeveloping your first application using FI-WARE
Developing your first application using FI-WARE
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Staying Sane with Drupal NEPHP
Staying Sane with Drupal NEPHPStaying Sane with Drupal NEPHP
Staying Sane with Drupal NEPHP
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Developing your first application using FIWARE
Developing your first application using FIWAREDeveloping your first application using FIWARE
Developing your first application using FIWARE
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2
 
droidQuery: The Android port of jQuery
droidQuery: The Android port of jQuerydroidQuery: The Android port of jQuery
droidQuery: The Android port of jQuery
 
Practical AngularJS
Practical AngularJSPractical AngularJS
Practical AngularJS
 
Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...
Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...
Code decoupling from Symfony (and others frameworks) - PHP Conference Brasil ...
 
Do you know what your drupal is doing? Observe it!
Do you know what your drupal is doing? Observe it!Do you know what your drupal is doing? Observe it!
Do you know what your drupal is doing? Observe it!
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Building AOL's High Performance, Enterprise Wide Mail Application With Silver...
Building AOL's High Performance, Enterprise Wide Mail Application With Silver...Building AOL's High Performance, Enterprise Wide Mail Application With Silver...
Building AOL's High Performance, Enterprise Wide Mail Application With Silver...
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Staying Sane with Drupal (A Develper's Survival Guide)
Staying Sane with Drupal (A Develper's Survival Guide)Staying Sane with Drupal (A Develper's Survival Guide)
Staying Sane with Drupal (A Develper's Survival Guide)
 

Mais de Srijan Technologies

[Srijan Wednesday Webinar] How to Run Stateless and Stateful Services on K8S ...
[Srijan Wednesday Webinar] How to Run Stateless and Stateful Services on K8S ...[Srijan Wednesday Webinar] How to Run Stateless and Stateful Services on K8S ...
[Srijan Wednesday Webinar] How to Run Stateless and Stateful Services on K8S ...Srijan Technologies
 
[Srijan Wednesday Webinars] How to Set Up a Node.js Microservices Architectur...
[Srijan Wednesday Webinars] How to Set Up a Node.js Microservices Architectur...[Srijan Wednesday Webinars] How to Set Up a Node.js Microservices Architectur...
[Srijan Wednesday Webinars] How to Set Up a Node.js Microservices Architectur...Srijan Technologies
 
[Srijan Wednesday Webinars] How to Build a Cloud Native Platform for Enterpri...
[Srijan Wednesday Webinars] How to Build a Cloud Native Platform for Enterpri...[Srijan Wednesday Webinars] How to Build a Cloud Native Platform for Enterpri...
[Srijan Wednesday Webinars] How to Build a Cloud Native Platform for Enterpri...Srijan Technologies
 
[Srijan Wednesday Webinars] Using Drupal as Data Pipeline for Digital Signage
[Srijan Wednesday Webinars] Using Drupal as Data Pipeline for Digital Signage[Srijan Wednesday Webinars] Using Drupal as Data Pipeline for Digital Signage
[Srijan Wednesday Webinars] Using Drupal as Data Pipeline for Digital SignageSrijan Technologies
 
[Srijan Wednesday Webinars] New Recipe of Decoupling: Drupal 8, Symfony and S...
[Srijan Wednesday Webinars] New Recipe of Decoupling: Drupal 8, Symfony and S...[Srijan Wednesday Webinars] New Recipe of Decoupling: Drupal 8, Symfony and S...
[Srijan Wednesday Webinars] New Recipe of Decoupling: Drupal 8, Symfony and S...Srijan Technologies
 
[Srijan Wednesday Webinars] Let’s Take the Best Route - Exploring Drupal 8 Ro...
[Srijan Wednesday Webinars] Let’s Take the Best Route - Exploring Drupal 8 Ro...[Srijan Wednesday Webinars] Let’s Take the Best Route - Exploring Drupal 8 Ro...
[Srijan Wednesday Webinars] Let’s Take the Best Route - Exploring Drupal 8 Ro...Srijan Technologies
 
[Srijan Wednesday Webinars] Is Your Business Ready for GDPR
[Srijan Wednesday Webinars] Is Your Business Ready for GDPR[Srijan Wednesday Webinars] Is Your Business Ready for GDPR
[Srijan Wednesday Webinars] Is Your Business Ready for GDPRSrijan Technologies
 
[Srijan Wednesday Webinars] Artificial Intelligence & the Future of Business
[Srijan Wednesday Webinars] Artificial Intelligence & the Future of Business[Srijan Wednesday Webinars] Artificial Intelligence & the Future of Business
[Srijan Wednesday Webinars] Artificial Intelligence & the Future of BusinessSrijan Technologies
 
[Srijan Wednesday Webinars] How to Design a Chatbot that Works
[Srijan Wednesday Webinars] How to Design a Chatbot that Works[Srijan Wednesday Webinars] How to Design a Chatbot that Works
[Srijan Wednesday Webinars] How to Design a Chatbot that WorksSrijan Technologies
 
[Srijan Wednesday Webinars] Simplifying Migration to Drupal 8
[Srijan Wednesday Webinars] Simplifying Migration to Drupal 8[Srijan Wednesday Webinars] Simplifying Migration to Drupal 8
[Srijan Wednesday Webinars] Simplifying Migration to Drupal 8Srijan Technologies
 
Final dependency presentation.odp
Final dependency presentation.odpFinal dependency presentation.odp
Final dependency presentation.odpSrijan Technologies
 
[Srijan Wednesday Webinar] Leveraging the OGD Platform and Visualization Engine
[Srijan Wednesday Webinar] Leveraging the OGD Platform and Visualization Engine[Srijan Wednesday Webinar] Leveraging the OGD Platform and Visualization Engine
[Srijan Wednesday Webinar] Leveraging the OGD Platform and Visualization EngineSrijan Technologies
 
[Srijan Wednesday Webinars] Why Adopt Analytics Driven Testing
[Srijan Wednesday Webinars] Why Adopt Analytics Driven Testing [Srijan Wednesday Webinars] Why Adopt Analytics Driven Testing
[Srijan Wednesday Webinars] Why Adopt Analytics Driven Testing Srijan Technologies
 
[Srijan Wednesday Webinar] Key ingredients of a Powerful Test Automation System
[Srijan Wednesday Webinar] Key ingredients of a Powerful Test Automation System[Srijan Wednesday Webinar] Key ingredients of a Powerful Test Automation System
[Srijan Wednesday Webinar] Key ingredients of a Powerful Test Automation SystemSrijan Technologies
 
[Srijan Wednesday Webinar] Building BPMN Web Portals with Camunda and Drupal
[Srijan Wednesday Webinar] Building BPMN Web Portals with Camunda and Drupal[Srijan Wednesday Webinar] Building BPMN Web Portals with Camunda and Drupal
[Srijan Wednesday Webinar] Building BPMN Web Portals with Camunda and DrupalSrijan Technologies
 
[Srijan Wednesday Webinar] Decoupled Demystified: The Present & Future of Dr...
 [Srijan Wednesday Webinar] Decoupled Demystified: The Present & Future of Dr... [Srijan Wednesday Webinar] Decoupled Demystified: The Present & Future of Dr...
[Srijan Wednesday Webinar] Decoupled Demystified: The Present & Future of Dr...Srijan Technologies
 
[Srijan Wednesday Webinars] Automating Visual Regression using ‘Galen’
[Srijan Wednesday Webinars] Automating Visual Regression using ‘Galen’[Srijan Wednesday Webinars] Automating Visual Regression using ‘Galen’
[Srijan Wednesday Webinars] Automating Visual Regression using ‘Galen’Srijan Technologies
 
[Srijan Wednesday Webinars] NASA, Netflix, Tinder: Digital Transformation and...
[Srijan Wednesday Webinars] NASA, Netflix, Tinder: Digital Transformation and...[Srijan Wednesday Webinars] NASA, Netflix, Tinder: Digital Transformation and...
[Srijan Wednesday Webinars] NASA, Netflix, Tinder: Digital Transformation and...Srijan Technologies
 
[Srijan Wednesday Webinars] Building a High Performance QA Team
[Srijan Wednesday Webinars] Building a High Performance QA Team[Srijan Wednesday Webinars] Building a High Performance QA Team
[Srijan Wednesday Webinars] Building a High Performance QA TeamSrijan Technologies
 
[Srijan Wednesday Webinar] Mastering Mobile Test Automation with Appium
[Srijan Wednesday Webinar] Mastering Mobile Test Automation with Appium[Srijan Wednesday Webinar] Mastering Mobile Test Automation with Appium
[Srijan Wednesday Webinar] Mastering Mobile Test Automation with AppiumSrijan Technologies
 

Mais de Srijan Technologies (20)

[Srijan Wednesday Webinar] How to Run Stateless and Stateful Services on K8S ...
[Srijan Wednesday Webinar] How to Run Stateless and Stateful Services on K8S ...[Srijan Wednesday Webinar] How to Run Stateless and Stateful Services on K8S ...
[Srijan Wednesday Webinar] How to Run Stateless and Stateful Services on K8S ...
 
[Srijan Wednesday Webinars] How to Set Up a Node.js Microservices Architectur...
[Srijan Wednesday Webinars] How to Set Up a Node.js Microservices Architectur...[Srijan Wednesday Webinars] How to Set Up a Node.js Microservices Architectur...
[Srijan Wednesday Webinars] How to Set Up a Node.js Microservices Architectur...
 
[Srijan Wednesday Webinars] How to Build a Cloud Native Platform for Enterpri...
[Srijan Wednesday Webinars] How to Build a Cloud Native Platform for Enterpri...[Srijan Wednesday Webinars] How to Build a Cloud Native Platform for Enterpri...
[Srijan Wednesday Webinars] How to Build a Cloud Native Platform for Enterpri...
 
[Srijan Wednesday Webinars] Using Drupal as Data Pipeline for Digital Signage
[Srijan Wednesday Webinars] Using Drupal as Data Pipeline for Digital Signage[Srijan Wednesday Webinars] Using Drupal as Data Pipeline for Digital Signage
[Srijan Wednesday Webinars] Using Drupal as Data Pipeline for Digital Signage
 
[Srijan Wednesday Webinars] New Recipe of Decoupling: Drupal 8, Symfony and S...
[Srijan Wednesday Webinars] New Recipe of Decoupling: Drupal 8, Symfony and S...[Srijan Wednesday Webinars] New Recipe of Decoupling: Drupal 8, Symfony and S...
[Srijan Wednesday Webinars] New Recipe of Decoupling: Drupal 8, Symfony and S...
 
[Srijan Wednesday Webinars] Let’s Take the Best Route - Exploring Drupal 8 Ro...
[Srijan Wednesday Webinars] Let’s Take the Best Route - Exploring Drupal 8 Ro...[Srijan Wednesday Webinars] Let’s Take the Best Route - Exploring Drupal 8 Ro...
[Srijan Wednesday Webinars] Let’s Take the Best Route - Exploring Drupal 8 Ro...
 
[Srijan Wednesday Webinars] Is Your Business Ready for GDPR
[Srijan Wednesday Webinars] Is Your Business Ready for GDPR[Srijan Wednesday Webinars] Is Your Business Ready for GDPR
[Srijan Wednesday Webinars] Is Your Business Ready for GDPR
 
[Srijan Wednesday Webinars] Artificial Intelligence & the Future of Business
[Srijan Wednesday Webinars] Artificial Intelligence & the Future of Business[Srijan Wednesday Webinars] Artificial Intelligence & the Future of Business
[Srijan Wednesday Webinars] Artificial Intelligence & the Future of Business
 
[Srijan Wednesday Webinars] How to Design a Chatbot that Works
[Srijan Wednesday Webinars] How to Design a Chatbot that Works[Srijan Wednesday Webinars] How to Design a Chatbot that Works
[Srijan Wednesday Webinars] How to Design a Chatbot that Works
 
[Srijan Wednesday Webinars] Simplifying Migration to Drupal 8
[Srijan Wednesday Webinars] Simplifying Migration to Drupal 8[Srijan Wednesday Webinars] Simplifying Migration to Drupal 8
[Srijan Wednesday Webinars] Simplifying Migration to Drupal 8
 
Final dependency presentation.odp
Final dependency presentation.odpFinal dependency presentation.odp
Final dependency presentation.odp
 
[Srijan Wednesday Webinar] Leveraging the OGD Platform and Visualization Engine
[Srijan Wednesday Webinar] Leveraging the OGD Platform and Visualization Engine[Srijan Wednesday Webinar] Leveraging the OGD Platform and Visualization Engine
[Srijan Wednesday Webinar] Leveraging the OGD Platform and Visualization Engine
 
[Srijan Wednesday Webinars] Why Adopt Analytics Driven Testing
[Srijan Wednesday Webinars] Why Adopt Analytics Driven Testing [Srijan Wednesday Webinars] Why Adopt Analytics Driven Testing
[Srijan Wednesday Webinars] Why Adopt Analytics Driven Testing
 
[Srijan Wednesday Webinar] Key ingredients of a Powerful Test Automation System
[Srijan Wednesday Webinar] Key ingredients of a Powerful Test Automation System[Srijan Wednesday Webinar] Key ingredients of a Powerful Test Automation System
[Srijan Wednesday Webinar] Key ingredients of a Powerful Test Automation System
 
[Srijan Wednesday Webinar] Building BPMN Web Portals with Camunda and Drupal
[Srijan Wednesday Webinar] Building BPMN Web Portals with Camunda and Drupal[Srijan Wednesday Webinar] Building BPMN Web Portals with Camunda and Drupal
[Srijan Wednesday Webinar] Building BPMN Web Portals with Camunda and Drupal
 
[Srijan Wednesday Webinar] Decoupled Demystified: The Present & Future of Dr...
 [Srijan Wednesday Webinar] Decoupled Demystified: The Present & Future of Dr... [Srijan Wednesday Webinar] Decoupled Demystified: The Present & Future of Dr...
[Srijan Wednesday Webinar] Decoupled Demystified: The Present & Future of Dr...
 
[Srijan Wednesday Webinars] Automating Visual Regression using ‘Galen’
[Srijan Wednesday Webinars] Automating Visual Regression using ‘Galen’[Srijan Wednesday Webinars] Automating Visual Regression using ‘Galen’
[Srijan Wednesday Webinars] Automating Visual Regression using ‘Galen’
 
[Srijan Wednesday Webinars] NASA, Netflix, Tinder: Digital Transformation and...
[Srijan Wednesday Webinars] NASA, Netflix, Tinder: Digital Transformation and...[Srijan Wednesday Webinars] NASA, Netflix, Tinder: Digital Transformation and...
[Srijan Wednesday Webinars] NASA, Netflix, Tinder: Digital Transformation and...
 
[Srijan Wednesday Webinars] Building a High Performance QA Team
[Srijan Wednesday Webinars] Building a High Performance QA Team[Srijan Wednesday Webinars] Building a High Performance QA Team
[Srijan Wednesday Webinars] Building a High Performance QA Team
 
[Srijan Wednesday Webinar] Mastering Mobile Test Automation with Appium
[Srijan Wednesday Webinar] Mastering Mobile Test Automation with Appium[Srijan Wednesday Webinar] Mastering Mobile Test Automation with Appium
[Srijan Wednesday Webinar] Mastering Mobile Test Automation with Appium
 

Último

Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelDeepika Singh
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024The Digital Insurer
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024The Digital Insurer
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbuapidays
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vĂĄzquez
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 

Último (20)

Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 

[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules

  • 1. Ruling Drupal 8 with #d8rules Josef Dabernig, Amazee Labs @dasjo
  • 2. • Facet API Pretty Paths • Geocluster • Drupal Centroamerica, Austria, Switzerland, ++ • Deputy Head Technology @ Amazee Labs twitter.com/dasjo
  • 3.
  • 4. • fago (Rules creator) • klausi (co-maintainer) • dasjo (communication) • fubhy (developer) • nico grienauer (design) • steve purkiss (developer) #d8rules team
  • 8. Rules • Build flexible workflows using events, condition & actions • Send customized mails to notify your users • Create custom redirections, system messages, breadcrumbs
  • 9. Rules • Build flexible workflows using events, condition & actions • Send customized mails to notify your users • Create custom redirections, system messages, breadcrumbs • 300.000+ reported installs (30% of all Drupal 7 sites) • Hundreds of integration modules • Entity API, Fields, Views, Webform, Context, Features, Search API, Tokens, Paths, Menus, Queue, Field formatter conditions, ...
  • 11. Drupal 8 wins • OOP, Dependency Injection • APIs • PHPUnit • Symfony2 • Removed legacy modules • Web services built in • Front-end, responsive, ...
  • 12. Drupal 8 for Rules • Plug-in API • Entity & Typed Data API • Conditions API • (Actions API -> forked) • Context API shared w/ Core, Page Manager • Configuration Management (CMI, YAML)
  • 13. Reusable components (“rtools”) • Tokens (automatic, based on typed data) • Typed data widgets & formatters • Extended Context API • Embeddable Rules UI components • Actions & Conditions • Rules data selector for tokens, contexts
  • 15. Site building • Admin UI usability improvements • (Simple Views Bulk operations in core) • “Inline Rules” instead of Rule sets / Rules conditional • Deployable configuration
  • 17. #d8rules goals • Accelerate Drupal 8 uptake by ensuring that Rules as a key contributed module is ready, early enough. • Enable flexible workflows in Drupal 8 sites that are easily configurable & reusable. • Make Drupal contributions sustainable by funding contributed code used on hundreds of thousands of sites.
  • 22. Rules 8.x M1 Rules core API fundamentals ✓ Rules core engine, plugin types ✓ Align Rules condition & action APIs with core ✓ Parameter configuration & Context mapping
  • 23. Rules 8.x M2 Rules core completion with basic UI ✓ Completed Rules engine features ✓ Completed Rules plugins (Events, Loops, API) ✓ Configuration entity, CMI and integrity checks ✓ Basic UI and autocomplete functionality ✓ API for embedding the Rules UI ✓ Twig-style token replacements
  • 24. Rules 8.x M3 Rules release ❏ Stable Rules 8.x-3.0 Release ❏ Rules Engine follow-ups ❏ Complete Rules UI ❏ Rules scheduler port ❏ Port existing integrations (almost done!)
  • 26. Sprints, trainings & sessions Szeged, Portoroz, Austin, Drupalaton, Amsterdam, Zurich, BogotĂĄ, Vienna, Milano, Montpellier, Bratislava, Sunderland, Barcelona, Mumbai, Heidelberg, Granada, .. http://d8rules.org/events
  • 27. Contribution • 114 forks, 40 contributors • paranoik, stevepurkiss, scuts, jibran, chindris, omissis, ndewhurst, jzavrl, MegaChriz, bbujisic, dawehner, torenware, bartfeenstra, M1r1k, rinasek, joashuataylor, lokapujya, icanblink, bojanz, a. milkovsky, mariancalinro, pjezek,czigor, mikl, nlisgo, nielsdefeyter, ... • 427 closed pull requests, Thank you all!
  • 28. Getting started • Setup Drupal 8 • Fork Rules 8.x on github: • https://github.com/fago/rules
  • 29.
  • 32. Plug-ins • OOP • Annotations • Auto-loading • Discovery • Derivatives
  • 35. /** * Provides a 'Node is sticky' condition. * * @Condition( * id = "rules_node_is_sticky", * label = @Translation("Node is sticky"), * category = @Translation("Node"), * context = {…} * ) */ class NodeIsSticky extends RulesConditionBase { /** * {@inheritdoc} */ public function evaluate() { $node = $this->getContextValue('node'); return $node->isSticky(); } }
  • 37. /** * Provides a 'Delete entity' action. * * @Action( * id = "rules_entity_delete", * label = @Translation("Delete entity"), * category = @Translation("Entity"), * context = {…} * ) */ class EntityDelete extends RulesActionBase { /** * {@inheritdoc} */ public function execute() { $entity = $this->getContextValue('entity'); $entity->delete(); } }
  • 38. Provide events • hook_rules_event_info -> Specify Symfony event metadata in *. rules.events.yml
  • 39. rules_user_login: label: 'User has logged in' category: 'User' context: account: type: 'entity:user' label: 'Logged in user' Event example from rules.rules.events.yml
  • 40. Event invocation /** * Implements hook_user_login(). */ function rules_user_login($account) { // Set the account twice on the event: as the main subject but also in the // list of arguments. $event = new UserLoginEvent($account, ['account' => $account]); $event_dispatcher = Drupal::service('event_dispatcher'); $event_dispatcher->dispatch(UserLoginEvent::EVENT_NAME, $event); }
  • 41. Event invocation /** * Implements hook_user_login(). */ function rules_user_login($account) { // Set the account twice on the event: as the main subject but also in the // list of arguments. $event = new UserLoginEvent($account, ['account' => $account]); $event_dispatcher = Drupal::service('event_dispatcher'); $event_dispatcher->dispatch(UserLoginEvent::EVENT_NAME, $event); }
  • 44. /** * Provides a 'Delete entity' action. * * @Action( * id = "rules_entity_delete", * label = @Translation("Delete entity"), * category = @Translation("Entity"), * context = {…} * ) */ class EntityDelete extends RulesActionBase { /** * {@inheritdoc} */ public function execute() { $entity = $this->getContextValue('entity'); $entity->delete(); } }
  • 45. /** * Provides a 'Delete entity' action. * * @Action( * id = "rules_entity_delete", * label = @Translation("Delete entity"), * category = @Translation("Entity"), * context = { * "entity" = @ContextDefinition("entity", * label = @Translation("Entity"), * description = @Translation("Specifies the entity, which should be deleted permanently.") * ) * } * ) */ class EntityDelete extends RulesActionBase {...}
  • 46. Context ● Defining context for a plug-in ● Using context within a plug-in
  • 47. class EntityDelete extends RulesActionBase { /** * Executes the action with the given context. */ public function doExecute(EntityInterface $entity) { $entity->delete(); } }
  • 48. class EntityDelete extends RulesActionBase { /** * Executes the action with the given context. */ public function doExecute(EntityInterface $entity) { $entity->delete(); } }
  • 49. class FetchEntityById extends RulesActionBase implements ContainerFactoryPluginInterface { /** * Executes the action with the given context. */ public function doExecute($entity_type, $entity_id) { $storage = $this->entityManager->getStorage($entity_type); $entity = $storage->load($entity_id); $this->setProvidedValue('entity', $entity); } }
  • 50. class FetchEntityById extends RulesActionBase implements ContainerFactoryPluginInterface { /** * Executes the action with the given context. */ public function doExecute($entity_type, $entity_id) { $storage = $this->entityManager->getStorage($entity_type); $entity = $storage->load($entity_id); $this->setProvidedValue('entity', $entity); } }
  • 51. Context ● Defining context for a plug-in ● Using context within a plug-in ● Passing context to the plug-in
  • 52. class ListCountIsTest extends RulesIntegrationTestBase { /** * Tests evaluating the condition. * * @covers ::evaluate() */ public function testConditionEvaluation() { // Test that the list count is greater than 2. $this->condition ->setContextValue('list', [1, 2, 3, 4]) ->setContextValue('operator', '>') ->setContextValue('value', '2'); $this->assertTrue($condition->evaluate()); } }
  • 53. class ListCountIsTest extends RulesIntegrationTestBase { /** * Tests evaluating the condition. * * @covers ::evaluate() */ public function testConditionEvaluation() { // Test that the list count is greater than 2. $this->condition ->setContextValue('list', [1, 2, 3, 4]) ->setContextValue('operator', '>') ->setContextValue('value', '2'); $this->assertTrue($condition->evaluate()); } }
  • 55. Storing configuration • D7: Entity exportables • Rules: • RulesPlugin->export() -> ? • RulesEntityController->import() -> ?
  • 56. Storing configuration • D7: Entity exportables • Rules: • RulesPlugin->export() -> RulesExpression::getConfiguration() • RulesEntityController->import() -> RulesExpression::setConfiguration()
  • 57. Drupal 8: CMI ● Rules leverages the Config System ● Two types of config entities: ○ Reaction Rules (WIP) ○ Components ● Inherit features from CMI ○ Config deployment / import&export / sync ○ Config Translation (instead of Entity i18n) ○ Default config
  • 58. Provide default rule configs • hook_default_rules_configuration() -> ?
  • 59. Provide default rule configs • hook_default_rules_configuration() -> rules.reaction.*.yml -> rules.component.*.yml
  • 60. langcode: en status: true dependencies: {} id: rules_test_default_component label: Rules test default component module: rules description: 'Tests adding Rules component by default.' tag: 'test' core: 8.x expression_id: rules_rule configuration: ...
  • 61. configuration: id: rules_rule context: user: type: 'entity:user' label: User conditions: id: rules_and conditions: {} actions: id: rules_action_set actions: - id: rules_action action_id: rules_system_message context_mapping: message: 'user:mail:value'
  • 62. Executing the component $config_entity = RulesComponent::load ('rules_test_default_component'); $expression = $config_entity->getExpression(); $expression ->setContextValue('user', Drupal::currentUser()) ->execute();
  • 63. Describe data to Rules Drupal 7 • hook_rules_data_info() -> ? • hook_entity_property_info_alter -> ?
  • 64. Typed Data API • Consistent way of interacting with any data based on metadata • Part of Drupal 8 & Entity Fields • Defines a type system for PHP: ○ Primitive types (integer, float, string, dates, ..) ○ Complex types ○ Lists (with items of a specified type)
  • 65. Data types ● any ● string, integer, uri, float, ... ○ email ○ timestamp, datetime_iso8601 ○ timespan, duration_iso8601 ● entity ○ entity:node ○ entity:comment ● field_item ○ field_item:string ○ field_item:text ○ field_item:image
  • 66. /** * The float data type. * * The plain value of a float is a regular PHP float. For setting the value * any PHP variable that casts to a float may be passed. * * @DataType( * id = "float", * label = @Translation("Float") * ) */ class FloatData extends PrimitiveBase implements FloatInterface { /** * {@inheritdoc} */ public function getCastedValue() { return (float) $this->value; } }
  • 67. /** * The float data type. * * The plain value of a float is a regular PHP float. For setting the value * any PHP variable that casts to a float may be passed. * * @DataType( * id = "float", * label = @Translation("Float") * ) */ class FloatData extends PrimitiveBase implements FloatInterface { /** * {@inheritdoc} */ public function getCastedValue() { return (float) $this->value; } }
  • 68. /** * Plugin implementation of the 'link' field type. * * @FieldType( * id = "link", * label = @Translation("Link"), * description = @Translation(“..."), * default_widget = "link_default", * default_formatter = "link", * constraints = {"LinkType" = {}} * ) */ class LinkItem extends FieldItemBase implements LinkItemInterface { public static function propertyDefinitions( FieldStorageDefinitionInterface $field_definition) { $properties['url'] = DataDefinition::create('string') ->setLabel(t('URL')); … return $properties; }
  • 69. /** * Plugin implementation of the 'link' field type. * * @FieldType( * id = "link", * label = @Translation("Link"), * description = @Translation(“..."), * default_widget = "link_default", * default_formatter = "link", * constraints = {"LinkType" = {}} * ) */ class LinkItem extends FieldItemBase implements LinkItemInterface { public static function propertyDefinitions( FieldStorageDefinitionInterface $field_definition) { $properties['url'] = DataDefinition::create('string') ->setLabel(t('URL')); … return $properties; }
  • 70. Describe data to rules • hook_rules_data_info() -> ? • hook_entity_property_info_alter -> ?
  • 71. Describe data to rules • hook_rules_data_info() -> Data type plugins, Typed Data • hook_entity_property_info_alter -> hook_data_type_info_alter() -> hook_entity_base_field_info/alter() -> hook_entity_bundle_field_info/alter() -> FieldItem::propertyDefintions()
  • 72. Every content entity & field type in Drupal 8 is supported by Rules out-of-the box!
  • 74.
  • 75.
  • 76.
  • 77. Lists & Multiple values ● list<foo> notation is gone ● “list” data type & per data type class ● Separate data definitions for lists vs. list items ● Mark context as “multiple”
  • 78. Creating a Rule with context
  • 79. $rule = $this->expressionManager->createRule([ 'context_definitions' => [ 'test' => [ 'type' => 'string', 'label' => 'Test string', ], ], ]);
  • 80. $rule = $this->expressionManager->createRule([ 'context_definitions' => [ 'test' => [ 'type' => 'string', 'label' => 'Test string', ], ], ]); $rule->addCondition('rules_test_string_condition', ContextConfig::create() ->map('text', 'test') );
  • 81. $rule = $this->expressionManager->createRule([ 'context_definitions' => [ 'test' => [ 'type' => 'string', 'label' => 'Test string', ], ], ]); $rule->addCondition('rules_test_string_condition', ContextConfig::create() ->map('text', 'test') ); $rule->addAction('rules_test_log');
  • 82. $rule = $this->expressionManager->createRule([ 'context_definitions' => [ 'test' => [ 'type' => 'string', 'label' => 'Test string', ], ], ]); $rule->addCondition('rules_test_string_condition', ContextConfig::create() ->map('text', 'test') ); $rule->addAction('rules_test_log'); $rule->setContextValue('test', 'test value');
  • 83. $rule = $this->expressionManager->createRule([ 'context_definitions' => [ 'test' => [ 'type' => 'string', 'label' => 'Test string', ], ], ]); $rule->addCondition('rules_test_string_condition', ContextConfig::create() ->map('text', 'test') ); $rule->addAction('rules_test_log'); $rule->setContextValue('test', 'test value'); $rule->execute();
  • 84. Mapping required and provided context
  • 86. $rule = $this->expressionManager->createRule(); // Condition provides a "provided_text" variable. $rule->addCondition('rules_test_provider');
  • 87. $rule = $this->expressionManager->createRule(); // Condition provides a "provided_text" variable. $rule->addCondition('rules_test_provider'); // Action provides a "concatenated" variable. $rule->addAction('rules_test_string', ContextConfig::create() ->provideAs('text', 'provided_text') );
  • 88. $rule = $this->expressionManager->createRule(); // Condition provides a "provided_text" variable. $rule->addCondition('rules_test_provider'); // Action provides a "concatenated" variable. $rule->addAction('rules_test_string', ContextConfig::create() ->provideAs('text', 'provided_text') ); // Same action again now provides "concatenated2" $rule->addAction('rules_test_string', ContextConfig::create() ->map(text, 'concatenated') ->provideAs('concatenated', 'concatenated2') );
  • 89. $rule = $this->expressionManager->createRule(); // Condition provides a "provided_text" variable. $rule->addCondition('rules_test_provider'); // Action provides a "concatenated" variable. $rule->addAction('rules_test_string', ContextConfig::create() ->provideAs('text', 'provided_text') ); // Same action again now provides "concatenated2" $rule->addAction('rules_test_string', ContextConfig::create() ->map(text, 'concatenated') ->provideAs('concatenated', 'concatenated2') );
  • 90. Advanced / under the hood
  • 91. Provide other Rules plugins • hook_rules_plugin_info -> Implement a RulesExpression plugin
  • 92. Provide input evaluators • hook_rules_evaluator_info -> Implement a RulesDataProcessor plugin
  • 93. /** * A data processor for applying numerical offsets. * * The plugin configuration must contain the following entry: * - offset: the value that should be added. * * @RulesDataProcessor( * id = "rules_numeric_offset", * label = @Translation("Apply numeric offset") * ) */ class NumericOffset extends PluginBase implements RulesDataProcessorInterface { /** * {@inheritdoc} */ public function process($value) { return $value + $this->configuration['offset']; }
  • 95. Automated testing • RulesUnitTestBase extends UnitTestCase • Internal unit tests such as RuleTest, RulesAndTest, RulesContextTraitTest, …
  • 96. Automated testing • RulesUnitTestBase extends UnitTestCase • Internal unit tests such as RuleTest, RulesAndTest, RulesContextTraitTest, … • RulesIntegrationTestBase • use ActionManager, ConditionManager, TypedDataManager, …
  • 97. class DataListCountIs extends RulesConditionBase { /** * {@inheritdoc} */ public function evaluate() { $list = $this->getContextValue('list'); $operator = $this->getContextValue('operator'); $value = $this->getContextValue('value'); switch ($operator) { case '==': return count($list) == $value; case '<'; return count($list) < $value; case '>'; return count($list) > $value; }
  • 98. /** * Tests evaluating the condition. * * @covers ::evaluate() */ public function testConditionEvaluation() { // Test that the list count is greater than 2. $condition = $this->condition ->setContextValue('list', [1, 2, 3, 4]) ->setContextValue('operator', '>') ->setContextValue('value', '2'); $this->assertTrue($condition->evaluate()); // Test that the list count is not equal to 0. $condition = $this->condition ->setContextValue('list', [1, 2, 3]) ->setContextValue('operator', '==') ->setContextValue('value', '0'); $this->assertFalse($condition->evaluate()); }
  • 99. Automated testing • RulesUnitTestBase extends UnitTestCase • Internal unit tests such as RuleTest, RulesAndTest, RulesContextTraitTest, … • RulesIntegrationTestBase • use ActionManager, ConditionManager, TypedDataManager, …
  • 100. Automated testing • RulesUnitTestBase extends UnitTestCase • Internal unit tests such as RuleTest, RulesAndTest, RulesContextTraitTest, … • RulesIntegrationTestBase • use ActionManager, ConditionManager, TypedDataManager, … • RulesEntityIntegrationTestBase
  • 101. * @Condition( * id = "rules_entity_is_of_type", * label = @Translation("Entity is of type"), * category = @Translation("Entity"), * context = { * "entity" = @ContextDefinition("entity", * label = @Translation("Entity"), * ), * "type" = @ContextDefinition("string", * label = @Translation("Type"), * ) * } * ) */ class EntityIsOfType extends RulesConditionBase { public function evaluate() { $provided_entity = $this->getContextValue('entity'); $specified_type = $this->getContextValue('type'); $entity_type = $provided_entity->getEntityTypeId();
  • 102. /** * Tests evaluating the condition. * * @covers ::evaluate() */ public function testConditionEvaluation() { $entity = $this->getMock('DrupalCoreEntityEntityInterface'); $entity->expects($this->exactly(2)) ->method('getEntityTypeId') ->will($this->returnValue('node')); // Add the test node to our context as the evaluated entity. // First, test with a value that should evaluate TRUE. $this->condition->setContextValue('entity', $entity) ->setContextValue('type', 'node'); $this->assertTrue($this->condition->evaluate()); // Then test with values that should evaluate FALSE. $this->condition->setContextValue('type', 'taxonomy_term'); $this->assertFalse($this->condition->evaluate());
  • 103. /** * Tests evaluating the condition. * * @covers ::evaluate() */ public function testConditionEvaluation() { $entity = $this->getMock('DrupalCoreEntityEntityInterface'); $entity->expects($this->exactly(2)) ->method('getEntityTypeId') ->will($this->returnValue('node')); // Add the test node to our context as the evaluated entity. // First, test with a value that should evaluate TRUE. $this->condition->setContextValue('entity', $entity) ->setContextValue('type', 'node'); $this->assertTrue($this->condition->evaluate()); // Then test with values that should evaluate FALSE. $this->condition->setContextValue('type', 'taxonomy_term'); $this->assertFalse($this->condition->evaluate());
  • 104. /** * Tests evaluating the condition. * * @covers ::evaluate() */ public function testConditionEvaluation() { $entity = $this->getMock('DrupalCoreEntityEntityInterface'); $entity->expects($this->exactly(2)) ->method('getEntityTypeId') ->will($this->returnValue('node')); // Add the test node to our context as the evaluated entity. // First, test with a value that should evaluate TRUE. $this->condition->setContextValue('entity', $entity) ->setContextValue('type', 'node'); $this->assertTrue($this->condition->evaluate()); // Then test with values that should evaluate FALSE. $this->condition->setContextValue('type', 'taxonomy_term'); $this->assertFalse($this->condition->evaluate());
  • 105. /** * Tests evaluating the condition. * * @covers ::evaluate() */ public function testConditionEvaluation() { $entity = $this->getMock('DrupalCoreEntityEntityInterface'); $entity->expects($this->exactly(2)) ->method('getEntityTypeId') ->will($this->returnValue('node')); // Add the test node to our context as the evaluated entity. // First, test with a value that should evaluate TRUE. $this->condition->setContextValue('entity', $entity) ->setContextValue('type', 'node'); $this->assertTrue($this->condition->evaluate()); // Then test with values that should evaluate FALSE. $this->condition->setContextValue('type', 'taxonomy_term'); $this->assertFalse($this->condition->evaluate());
  • 108. Traits
  • 109. trait StringTranslationTrait { /** * The string translation service. * * @var DrupalCoreStringTranslationTranslationInterface */ protected $stringTranslation; /** * Translates a string to the current language or to a given language. * * See the t() documentation for details. */ protected function t($string, …) { return $this->getStringTranslation()->translate($string, …); } }
  • 110. class MyClass { use StringTranslationTrait; public function __construct( TranslationInterface $string_translation) { $this->stringTranslation = $string_translation; } /** * Does something. */ public function doSth() { // ... $string = $this->t('Something'); // ... } }
  • 111. Traits • RulesContextTrait • in addition to ContextAwarePluginBase • used in RulesActionBase and RulesConditionBase
  • 112. Outro
  • 113.
  • 114. Sprint with us! • Port actions & conditions • https://www.drupal.org/node/2245015
  • 115. Sprint with us! • Port actions & conditions • https://www.drupal.org/node/2245015
  • 119. NoFlo