[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules

  • Published on
    15-Apr-2017

  • View
    510

  • Download
    1

Transcript

  • Ruling Drupal 8 with

    #d8rulesJosef 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

    http://drupalfund.ushttp://drupalfund.us

  • Sponsors

  • Funding state

  • Rules 8.x development status

  • Rules 8.x M1Rules core API fundamentals

    Rules core engine, plugin types Align Rules condition & action APIs with core Parameter configuration & Context mapping

  • Rules 8.x M2Rules 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 M3Rules 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.xRoadmap

    https://www.drupal.org/node/2245015

    https://www.drupal.org/node/2245015https://www.drupal.org/node/2245015

  • Sprints, trainings & sessionsSzeged, Portoroz, Austin, Drupalaton, Amsterdam, Zurich, Bogot, Vienna, Milano, Montpellier, Bratislava, Sunderland, Barcelona, Mumbai, Heidelberg, Granada, ..

    http://d8rules.org/events

    http://d8rules.org/eventshttp://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

    https://github.com/fago/ruleshttps://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: enstatus: truedependencies: {}id: rules_test_default_componentlabel: Rules test default componentmodule: rulesdescription: 'Tests adding Rules component by default.'tag: 'test'core: 8.xexpression_id: rules_ruleconfiguration:

    ...

  • 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 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->creat...

Recommended

View more >