Quantcast
Viewing all 294415 articles
Browse latest View live

Use event system in ModuleHandler

Updated: Comment #N

Problem/Motivation

Look at Drupal\Core\Extension\ModuleHandler class. It's a mess. There are horrors in there like removeCacheBins() that is not something the module handler should ever care about.

Proposed resolution

Inject the event dispatcher into the module handler and fire events for module related hooks.

Remaining tasks

Patch, decide on how to deal with existing hooks.

User interface changes

None

API changes

Addition of module events.

Maybe not deprecation of hooks? Not sure.


Create \Drupal\Component\Utility\ArrayObject

Problem/Motivation

Drupal has arrays.

Drupal has LOTS of arrays.

Arrays are, sometimes, quite painful to manipulate and test.

We need a base object that we can start creating other strongly typed objects on that do nothing but manipulate and extract information from arrays (at their core, no pun intended):

Additional use-cases for existing issues:

Unfortunately, the SPL \ArrayObject isn't really all that "feature rich" with all the various tasks that we commonly do with arrays.

Proposed resolution

Implement our own custom base ArrayObject class, similar to something that resembles:

https://cgit.drupalcode.org/plus/tree/src/Utility/ArrayObject.php?h=8.x-4.x

Remaining tasks

  • Create patch
  • Create tests

User interface changes

None

API changes

Utility/API addition

Data model changes

None

Figure out a way to render fields on top level in templates

Would be nice to be able to:

{{ content.field_name }}

When a node is controlled by lb

Allow off-canvas dialog to be rendered at the top of the page

Problem/Motivation

The settings tray currently uses the dialog system and is always rendered on the right side of the page. Some modules may have a need for the tray to appear at the top of the page.

Proposed resolution

Add a new value off_canvas_topfor the data-dialog-renderer attribute when creating a dialog link.
This will make the off-canvas dialog to render at the top of the page.

Remaining tasks

Fix the bug described in #54, which this patch introduces.

User interface changes

Module will be able to create off-canvas dialog links where the dialog comes down from the top of the page instead of the side.

API changes

There will be a new value off_canvas_topavailable for the data-dialog-renderer attribute when creating a dialog link.

To create a off-canvas-top dialog link us the following

'off_canvas_top_link_1' => [
        '#title' => 'Open top panel 1',
        '#type' => 'link',
        '#url' => Url::fromRoute('off_canvas_test.thing1'),
        '#attributes' => [
          'class' => ['use-ajax'],
          'data-dialog-type' => 'dialog',
          'data-dialog-renderer' => 'off_canvas_top',
        ],
      ],

Note this the same as the current off-canvas dialog except for the off_canvas_top value.

Data model changes

None

Manually testing

To manually test this patch

  1. Enabled the off_canvas_test test module.
  2. Goto /off-canvas-test-links
  3. Click the various links to open the dialog either on the side or on the top.

To reproduce the error mentioned in #16 first open a top dialog and then a side one. The side dialog will be pushed down on the page.

Convey AJAX progress messages to assistive technology.

Problem/Motivation

The AJAX API has a feature to display a progress message, but it isn't conveyed to assisitive tech like screen readers.

'#ajax' => array(
  'callback' => 'Drupal\config_translation\FormElement\DateFormat::ajaxSample',
  'event' => 'keyup',
  'progress' => array(
    'type' => 'throbber',
    'message' => t('Loading more products'),
  ),
),

Proposed resolution

Find a way to convey the progress message to
Possibilities (use one approach only, not both):

  1. Mark the visible AJAX message as an ARIA-live region (preferred?), or
  2. Duplicate the visible message using a Drupal.announce() call.

Other possibilities might be to provide incrementally updated messages, like "Updating... 30%... 80%... finished".

Remaining tasks

tbd.

User interface changes

No visual changes. Format the AJAX message so it is conveyed to assistive technology, e.g. so screen readers can announce it.

API changes

TBD. Maybe we always treat the message as an aria-live region, or maybe we make it an additional option.

Data model changes

TBD.

Commit credits

Please credit @bgrobertson, who reported this issue on the #accessibility channel on Drupal Slack, and researched which bits of the AJAX API were relevant. This issue report is a summary of his comments there.

#states required is not working in form API

Hi There,

I want to use dependant text field with checkbox in drupal form.

I am using form #states with required, but form gets submitted without validating the text field.

Please check below code.

$form['dummy_checkbox'] = array(
    '#type' => 'checkbox',
    '#title' => t('Dummy Checkbox'),
  );

  $form['dummy_checkbox_value'] = array(
    '#type' => 'textfield',
    '#title' => t('Dummy Checkbox Value'),
    '#states' => array(
      'visible' => array(
        ':input[name="dummy_checkbox"]' => array('checked' => TRUE)
      ),
      'required' => array(
        ':input[name="dummy_checkbox"]' => array('checked' => TRUE)
      ),
    )
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );

Note : I have option to write validate function, but my checkbox and text field are multiple. So I need to work with #states only.

Refactor ThemeRegistry and Theme\Registry

Background / current situation

There are two classes in Drupal 8 core which deal with the theme registry:

  • Drupal\Core\Theme\Registry
  • Drupal\Core\Utility\ThemeRegistry - the "runtime" theme registry.

The latter, ThemeRegistry, is created in Drupal\Core\Theme\Registry::getRuntime(), and only there.

On the other hand, ThemeRegistry calls Theme\Registry->get() on cache miss.
To do this, it gets the Theme\Registry object via Drupal::service(), instead of having it injected.
Among other problems, this causes this flaw: #2957215: ThemeRegistry::resolveCacheMiss() might look at wrong theme in some cases

Theme\Registry holds registry arrays for (potentially) all themes.
However, it also has a Registry->themeName and Registry->theme.
This means some of its functionality is for one specific theme, other functionality is for any theme.

The "specific theme" for Theme\Registry is set in the constructor, but it can be modified via ->init($theme_name).

So, in a way, the kind of hypermutable or shapeshifting object that is typical for Drupal.

ThemeRegistry (the "runtime" registry) inherits from CacheCollector, and overwrites half of the methods.
It also inherits CacheCollector::set() and CacheCollector::delete(), which are never called on ThemeRegistry objects (from what I found).
All non-public members of CacheCollector are protected, which means they leak into all inheritors. Protected properties of CacheCollector can be and are read and written in ThemeRegistry methods, which means you really need to look at both classes (parent and child) to see what is going on.

I get the idea that inheriting from CacheCollector and implementing CacheCollectorInterface makes things more complicated rather than simpler.

Proposed change

I am not sure yet, but here are some ideas.
In the spirit of #2956549: Policy: Atomic behavior objects .

Introduce a ThemeRegistryInterface, with methods ->has($key) and ->get($key).

All relevant implementations should be for one specific theme, which is chosen in the constructor and then not changed again.
If you need the same thing for a different theme, you create a new one.

Perhaps there can be one toplevel implementation with a mutable $this->themeName property, which maps all calls to $this->registries[$this->themeName]->FOO();. This will be necessary, if we want to register this thing as a service. Because services cannot be "thrown away" during a request, if the active theme name changes.

The following implementations and other classes could be useful, which would be combined as layers in a decorator stack:

  • ThemeRegistryDiscovery.
    I am not even sure if this should implement the same interface. Because here we don't need ->has($key) and ->get($key), but rather a -->getAll() method.
  • ThemeRegistryCache
    A decorator which caches the full registry for the specified theme, with $cid = 'theme_registry:' . $this->themeName.
  • ThemeRegistryRuntimeCache
    The runtime registry, which only remembers those theme hooks which are actually used.
  • ThemeRegistryProxy
    This can lazy-create another ThemeRegistry implementation with heavy dependencies or initialization logic, and delegate all methods onto this lazy-created proxy instance.
    I am not sure yet at which layer we would use a proxy like this.
  • ThemeRegistryDispatcher
    This does NOT implement ThemeRegistryInterface. It has a method ->getForTheme($theme_name) which returns a ThemeRegistryInterface instance for the specified theme.
  • ThemeRegistryCurrent
    This implements ThemeRegistryInterface, has a mutable ->currentThemeName variable, and an ->dispatcher object, and maps every call FOO() to $this->dispatcher->getForTheme($this->currentThemeName)->FOO().
    Or, maybe smarter: It subscribes to a ThemeChangeEvent, which causes it to change the $this->currentRegistry. Every call ->FOO() is then delegated to $this->currentRegistry->FOO().
    This last one can be registered as a service.

This still leaves some open questions. I simply have not thought about it long enough.

We need some objects that return a full array of theme implementations, and other objects which return specific entries for specific keys. So maybe we need two interfaces: ThemeRegistryAllInterface and ThemeRegistryLookupInterface (names open for debate).

I think trying to implement this would bring clarity.

Why not plugins?

See #2869859: [PP-1] Refactor theme hooks/registry into plugin managers

A lot of the above looks like functionality that already exists for the plugin system.
But the plugin system might also introduce unnecessary clutter and overhead, and some functionality might not be suitable for the theme registry.

We could try this with and without the plugin system, and then see which looks and works better.

Theme hooks as objects?

Currently, theme registry entries are arrays.

it was proposed in #2863819: Convert theme hooks (defined by hook_theme()) to be objects to replace those arrays with objects.
I am personally skeptical about this.
It would mean that we pass mutable objects to various places where they can be modified (but shouldn't), and also serialize those objects into the database.

If we do something like this, or something similar, then the ThemeRegistryInterface would have to be modified to return those objects instead of arrays.
The basic implementation would not change.

What about BC?

The existing class Drupal\Core\Theme\Registry is marked as "@internal", so in theory we are allowed to mess with it.
Unfortunately, this does not stop some contrib modules from accessing it. E.g. devel via theme_get_registry().

We could turn the class into a shallow adapter for BC support.

The Drupal\Core\Utility\ThemeRegistry is not marked as "@internal", but is (afaik) only used in a few places in core.
So, can we modify this?
And are we allowed to strip interfaces from this class?
Those places that I found do not depend on ThemeRegistry being an implementation of CacheCollectorInterface. But can we rely on that?

Refactor out theme hook suggestion building from ThemeManager::render() into a separate function.

I am proposing a straightforward refactoring.

Currently, theme hook suggestions are collected within ThemeManager::render().
I propose to split this out into a separate function.

Let's start with a private function within the same class. Later we can decide to move this elsewhere, make it protected, or whatever else.
Let's really keep it private for now to allow future refactoring.


Fix Drupal.Array.Array.ArrayClosingIndentation' coding standard

Part of #2571965: [meta] Fix coding standards in core.

Approach

We are testing coding standards with PHP CodeSniffer, using the Drupal coding standards from the Coder module. We need to do a couple of steps in order to download and configure them so we can run a coding standards check.

Step 1: Add the coding standard to the whitelist

Every coding standard is identified by a "sniff". For example, an imaginary coding standard that would require all llamas to be placed inside a square bracket fence would be called the "Drupal.AnimalControlStructure.BracketedFence sniff". There are dozens of such coding standards, and to make the work easier we have started by only whitelisting the sniffs that pass. For the moment all coding standards that are not yet fixed are simply skipped during the test.

Open the file core/phpcs.xml.dist and add a line for the sniff of this ticket. The sniff name is in the issue title. Make sure your patch will include the addition of this line.

Step 2: Install PHP CodeSniffer and the ruleset from the Coder module

$ composer install
$ ./vendor/bin/phpcs --config-set installed_paths ../../drupal/coder/coder_sniffer

Once you have installed the phpcs package, you can list all the sniffs available to you like this:

$ ./vendor/bin/phpcs --standard=Drupal -e

This will give you a big list of sniffs, and the Drupal-based ones should be present.

Step 3: Prepare the phpcs.xml file

To speed up the testing you should make a copy of the file phpcs.xml.dist (in the core/ folder) and save it as phpcs.xml. This is the configuration file for PHP CodeSniffer.

We only want this phpcs.xml file to specify the sniff we're interested in. So we need to remove all the rule items, and add only our own sniff's rule. Rule items look like this:

<rule ref="Drupal.Classes.UnusedUseStatement"/>

Remove all of them, and add only the sniff from this issue title. This will make sure that our tests run quickly, and are not going to contain any output from unrelated sniffs.

Step 4: Run the test

Now you are ready to run the test! From within the core/ folder, run the following command to launch the test:

$ cd core/
$ ../vendor/bin/phpcs -ps

This takes a couple of minutes. The -p flag shows the progress, so you have a bunch of nice dots to look at while it is running. The -s flag shows the sniffs when displaying results.

Step 5: Fix the failures

When the test is complete it will present you a list of all the files that contain violations of your sniff, and the line numbers where the violations occur. You could fix all of these manually, but thankfully phpcbf can fix many of them. You can call phpcbf like this:

$ ../vendor/bin/phpcbf

This will fix the errors in place. You can then make a diff of the changes using git. You can also re-run the test with phpcs and determine if that fixed all of them.

UI for publishing/unpublishing block_content blocks

Problem/Motivation

In #2820848: Make BlockContent entities publishable blocks got a publishing status field, but no UI. We should provide a way for users to (un)publish blocks when editing/creating them.

Changes to the block library page have been split off to to #2909435: Update block library page to adapt publishable block content implementation

Proposed resolution

Add the published checkbox to the block edit form like on other editorial content entities.

Remaining tasks

  • Implement it
  • Provide upgrade path & test

User interface changes

Yes.

Status checkbox on the block content form

Image may be NSFW.
Clik here to view.

API changes

None.

Data model changes

None.

Implement media source plugin for remote video via oEmbed

Problem/Motivation

One of the main reasons to adopt Media Entity in core was the need to be able to work with remote media (especially videos). We need to provide a base implementation of this in core Media that supports the most popular online video providers, ideally in a very extensible way.

Proposed resolution

Implement support for oEmbed in the Media module, supporting a subset of popular video providers by default (specifically, Vimeo and YouTube). Supporting oEmbed generally will give us, and contrib, the latitude to easily support other remote media assets in the future (e.g., Twitter, Instagram, other video providers).

Security considerations

From https://oembed.com/#section3

When a consumer displays HTML (as with video embeds), there's a vector for XSS attacks from the provider. To avoid this, it is recommended that consumers display the HTML in an iframe, hosted from another domain. This ensures that the HTML cannot access cookies from the consumer domain.

Drupal does not require multiple domains so it is not possible for oEmbed video fields to be secure out-of-the-box. Since #2522002: Do not strip www. from cookie domain by default because that leaks session cookies to subdomains has been committed to Drupal 8 it is possible to use a subdomain, for example: video.example.com, as long as example.com is redirected to www.example.com. We need make it simple to configure a different domain to serve the oEmbed content from and we need to have sufficient security warnings to inform users that their configuration is not secure.

Additionally we need to ensure that content creators can not enter arbitrary URLs. A content creator should only be able to link to sources from a list configured by someone with a trusted permission. The defaults for this configuration need to be sensible and restrictive. Plus the configuration field needs documentation about the security implications of adding sources.

(related comments: #139#137#132)

Remaining tasks

  • decide between specific provider or oEmbed based solution
  • implement plugin and extensive tests

Image may be NSFW.
Clik here to view.

[PP-1] Extension System, Part III: Properly register installed extension namespaces in container

Problem/Motivation

Since the release of 8.x, themes have had the ability to use PSR autoloading and create OO class-based themes.

With nearly 40k+ reported 8.x installs (at time of writing), the Drupal Bootstrap base theme has maintained and continues to grow as the #1 theme on d.o.

The popularity in D8 alone is probably attributed to the fact that it imploys a comprehensive OO class-based Plugin System.

However, over the years, certain bugs have become apparent, namely in the form unregistered theme namespaces.

In an effort to "fix" this, the base theme implements a file which can be included in certain AJAX/batch callbacks so that it invokes \Drupal::service('theme_handler')->listInfo(); during the request.

The main reason this needs to be done in the kernel is because certain requests only bootstrap so far. If a theme provides a static #pre_render, #ajax, or #lazy_builder callback to a method in one of its classes, this lives in a render array which can become cached. Because of this caching, the entire theme system does not neccessarily need to be loaded just to execute a callback. Thus, the namespaces are never registered and the classes cannot be found.

This service/method is what intantiates and registers all installed theme namespaces.

It is a common misnomer that extension namespaces are registered on install.

DrupalKernel::compileContainer automatically registers module namespaces, simply because can provide services (not themes). But these namespaces are done after the service providers have been determined and effectively cut all other installed extension types out of being properly registered.

There are also no significant tests to ensure that these namespaces are registered properly and whether or not they would in fact break contrib.

Proposed resolution

Register all installed extension namespaces as separate parameters in the container, with equivalent services:

  • container.namespaces.core - Drupal specific ['Core', 'Component'] namespaces.
  • container.namespaces.module
  • container.namespaces.profile
  • container.namespaces.theme
  • container.namespaces.theme_engine
  • container.namespaces.all - all of the above namespaces

For BC reasons, the existing container.namespaces parameter/service needs to be aliased to the following namespaces:

  • container.namespaces.core
  • container.namespaces.module
  • container.namespaces.profile

And then deprecated when #2954562: [PP-1] Create provider type based plugin managers makes it way in to allow plugin managers to choose which namespaces to allow.

Remaining tasks

  • Create tests
  • Create a patch

User interface changes

None

API changes

Addition of extension specific namespace services.

Data model changes

None

entity query nested conditions must use LEFT joins when any of the parent condition groups is using OR

Problem/Motivation

There are two issues when using an EFQ with an Or condition on the top level of the Where condition and a nested And condition as a sub condition of the Or condition: for example:

    $query = \Drupal::entityQuery('node');
    $and_group = $query->andConditionGroup()
      ->condition('type', 'a')
      ->condition('status', 1);
    $or_group = $query->orConditionGroup()
      ->condition('type', 'b')
      ->condition($and_group);

    $query->condition($or_group);
          ->execute();

Problems are:

  1. Conditions are set on the global sql_query object instead of the current condition container, so the Or condition on the top level is overridden by the nested And condition. Already fixed by #2527064: Nested condition groups in entity queries are broken
  2. Parent conditions are not considered while determining whether to use an INNER or a LEFT join. Currently, an INNER join is used for tables required by AND conditions and a LEFT join is used for tables required by OR conditions. However, once an AND condition is nested inside of a top-level OR condition, it's incorrect to use INNER join - even for AND conditions - because that will incorrectly limit the result set, if the other "branch" of the OR condition is TRUE.

Proposed resolution

  1. Already fixed by #2527064: Nested condition groups in entity queries are broken.
  2. Pass down the information about existing Or conditions when working with nested conditions.

Entity Links fields does not have translation support

Problem/Motivation

The Entity link field uses the wrong translation of the entity. It always uses the original language which is not always desired.
This applies to both deletion and editing.
You can use the Entity operations field instead but that is not always desired to do so.

To reproduce:

  1. I have downloaded latest 8.4.x-dev release
  2. I have installed Drupal 8.4 with the Standard profile
  3. I have added a new language "Swedish" and then enabled that language for the "Article" content type
  4. I have created a new node Article example and then translating it to Swedish Artikel exempel.
  5. I have created a new View "Articles" that lists content type articles for both languages
  6. I have configured the view to use table format. I add "Link to edit Content" and "Link to delete Content" fields

The exported view:

uuid: b6c259e3-3fbc-46b9-9979-8df90333fff2
langcode: en
status: true
dependencies:
  config:
    - node.type.article
  module:
    - node
    - user
id: articles
label: Articles
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
core: 8.x
display:
  default:
    display_plugin: default
    id: default
    display_title: Master
    position: 0
    display_options:
      access:
        type: perm
        options:
          perm: 'access content'
      cache:
        type: tag
        options: {  }
      query:
        type: views_query
        options:
          disable_sql_rewrite: false
          distinct: false
          replica: false
          query_comment: ''
          query_tags: {  }
      exposed_form:
        type: basic
        options:
          submit_button: Apply
          reset_button: false
          reset_button_label: Reset
          exposed_sorts_label: 'Sort by'
          expose_sort_order: true
          sort_asc_label: Asc
          sort_desc_label: Desc
      pager:
        type: mini
        options:
          items_per_page: 10
          offset: 0
          id: 0
          total_pages: null
          expose:
            items_per_page: false
            items_per_page_label: 'Items per page'
            items_per_page_options: '5, 10, 25, 50'
            items_per_page_options_all: false
            items_per_page_options_all_label: '- All -'
            offset: false
            offset_label: Offset
          tags:
            previous: ‹‹
            next: ››
      style:
        type: table
      row:
        type: fields
      fields:
        title:
          id: title
          table: node_field_data
          field: title
          entity_type: node
          entity_field: title
          alter:
            alter_text: false
            make_link: false
            absolute: false
            trim: false
            word_boundary: false
            ellipsis: false
            strip_tags: false
            html: false
          hide_empty: false
          empty_zero: false
          settings:
            link_to_entity: true
          plugin_id: field
          relationship: none
          group_type: group
          admin_label: ''
          label: Title
          exclude: false
          element_type: ''
          element_class: ''
          element_label_type: ''
          element_label_class: ''
          element_label_colon: true
          element_wrapper_type: ''
          element_wrapper_class: ''
          element_default_classes: true
          empty: ''
          hide_alter_empty: true
          click_sort_column: value
          type: string
          group_column: value
          group_columns: {  }
          group_rows: true
          delta_limit: 0
          delta_offset: 0
          delta_reversed: false
          delta_first_last: false
          multi_type: separator
          separator: ', '
          field_api_classes: false
        edit_node:
          id: edit_node
          table: node
          field: edit_node
          relationship: none
          group_type: group
          admin_label: ''
          label: 'Link to edit Content'
          exclude: false
          alter:
            alter_text: false
            text: ''
            make_link: false
            path: ''
            absolute: false
            external: false
            replace_spaces: false
            path_case: none
            trim_whitespace: false
            alt: ''
            rel: ''
            link_class: ''
            prefix: ''
            suffix: ''
            target: ''
            nl2br: false
            max_length: 0
            word_boundary: true
            ellipsis: true
            more_link: false
            more_link_text: ''
            more_link_path: ''
            strip_tags: false
            trim: false
            preserve_tags: ''
            html: false
          element_type: ''
          element_class: ''
          element_label_type: ''
          element_label_class: ''
          element_label_colon: true
          element_wrapper_type: ''
          element_wrapper_class: ''
          element_default_classes: true
          empty: ''
          hide_empty: false
          empty_zero: false
          hide_alter_empty: true
          text: edit
          entity_type: node
          plugin_id: entity_link_edit
        delete_node:
          id: delete_node
          table: node
          field: delete_node
          relationship: none
          group_type: group
          admin_label: ''
          label: 'Link to delete Content'
          exclude: false
          alter:
            alter_text: false
            text: ''
            make_link: false
            path: ''
            absolute: false
            external: false
            replace_spaces: false
            path_case: none
            trim_whitespace: false
            alt: ''
            rel: ''
            link_class: ''
            prefix: ''
            suffix: ''
            target: ''
            nl2br: false
            max_length: 0
            word_boundary: true
            ellipsis: true
            more_link: false
            more_link_text: ''
            more_link_path: ''
            strip_tags: false
            trim: false
            preserve_tags: ''
            html: false
          element_type: ''
          element_class: ''
          element_label_type: ''
          element_label_class: ''
          element_label_colon: true
          element_wrapper_type: ''
          element_wrapper_class: ''
          element_default_classes: true
          empty: ''
          hide_empty: false
          empty_zero: false
          hide_alter_empty: true
          text: delete
          entity_type: node
          plugin_id: entity_link_delete
      filters:
        status:
          value: '1'
          table: node_field_data
          field: status
          plugin_id: boolean
          entity_type: node
          entity_field: status
          id: status
          expose:
            operator: ''
          group: 1
        type:
          id: type
          table: node_field_data
          field: type
          value:
            article: article
          entity_type: node
          entity_field: type
          plugin_id: bundle
      sorts:
        created:
          id: created
          table: node_field_data
          field: created
          order: DESC
          entity_type: node
          entity_field: created
          plugin_id: date
          relationship: none
          group_type: group
          admin_label: ''
          exposed: false
          expose:
            label: ''
          granularity: second
      title: Articles
      header: {  }
      footer: {  }
      empty: {  }
      relationships: {  }
      arguments: {  }
      display_extenders: {  }
    cache_metadata:
      max-age: 0
      contexts:
        - 'languages:language_content'
        - 'languages:language_interface'
        - url.query_args
        - 'user.node_grants:view'
        - user.permissions
      tags: {  }
  page_1:
    display_plugin: page
    id: page_1
    display_title: Page
    position: 1
    display_options:
      display_extenders: {  }
      path: articles
    cache_metadata:
      max-age: 0
      contexts:
        - 'languages:language_content'
        - 'languages:language_interface'
        - url.query_args
        - 'user.node_grants:view'
        - user.permissions
      tags: {  }

Expected behaviour

When clicking on Edit on the Swedish Article exempel node I should be taken to the Edit form for that translation (Swedish)
When clicking on Delete on the Swedish Article exempel node I should be taken to the Delete form for that translation (Swedish)

Current behaviour

I am taken to the edit form for the english (original translation).
I am taken to delete form to delete both translations.

Proposed solution/idea

Use the EntityTranslationRenderTrait trait to properly render entity row links in the right language.
Add Kernel test for the fields to ensure they work as expected.

Proposed follow ups

Use Rendering language in the view configuration for untranslated entities
Fix translations for \Drupal\comment\Plugin\views\field\EntityLink if needed

Ask for privacy consent when a user registers an account

For the GDPR, users should be asked for consent we start processing a person's information. There are other ways in Drupal that this is done, but the user.module is leveraged by most Drupal sites that collect personal information.

GDPR Article 7 – Conditions for consent states "Where processing is based on consent, the controller shall be able to demonstrate that the data subject has consented to processing of his or her personal data."

From https://techblog.bozho.net/gdpr-practical-guide-developers/

Consent checkboxes – “I accept the terms and conditions” would no longer be sufficient to claim that the user has given their consent for processing their data. So, for each particular processing activity there should be a separate checkbox on the registration (or user profile) screen. You should keep these consent checkboxes in separate columns in the database, and let the users withdraw their consent (by unchecking these checkboxes from their profile page – see the previous point). Ideally, these checkboxes should come directly from the register of processing activities (if you keep one). Note that the checkboxes should not be preselected, as this does not count as “consent”. Another important thing here is machine learning/AI. If you are going to use the user’s data to train your ML models, you should get consent for that as well (unless it’s for scientific purposes, which have special treatment in the regulation). Note here the so called “legitimate interest”. It is for the legal team to decide what a legitimate interest is, but direct marketing is included in that category, as well as any common sense processing relating to the business activity – e.g. if you collect addresses for shipping, it’s obviously a legitimate interest. So not all processing activities need consent checkboxes.

https://gdpr-info.eu/art-7-gdpr/


Track Layout override revisions on entities which support revisioning

Problem/Motivation

Revisionable entities with custom layout override only track layout changes incidentally when an entity is saved via the entity's edit form. In order to provide full layout revisioning, we should check that the entity type's bundle is revisionable and whether or not a new revision should be created before calling entity save in the Section Storage object.

Proposed resolution

Section storage for the field should determine if the entity's bundle is RevisionableEntityBundleInterface and check shouldCreateNewRevision(). If this is "true" then a new revision should be set on the entity before saving.

Remaining tasks

Write a patch
Write tests
Convince people

User interface changes

No direct changes to the UI. Layout saves for entity override would prompt the creation of new revision which would display the entity's revision tab. That "ui change" is incidental and expected.

API changes

None

Data model changes

None

MediaThumbnailFormatter produces unhelpful text alternative for image media items.

We have trouble with alt text for Thumbnail formatter. It is very similar to Media entity bug, but we use module Media in core.

In core/modules/media/src/Plugin/Field/FieldFormatter/MediaThumbnailFormatter.php is code

$media_items = $this->getEntitiesToView($items, $langcode);

I was inspect in Xdebug variable $items and I found, that there are using Thumbnail as alt ($items->list[0]->properties['entity']->target->entity->values['thumbnail']['x-default'])

I don't know, where is source of $items. How can I fix it?

Do not create field revisions when field data hasn't changed

The problem

Database performance degrades with the exponential increase in revisions generated by Entity Reference Revisions fields (commonly used for Paragraphs). Each new node revision means a new revision of each paragraph, which means a new revision of each field on the paragraph... Things can get out of hand pretty quick on sites that aren't even ginormous.

Note that the general problem of revision bloat and the proposed resolution are not specific to ERR or Paragraphs. I have zero hard performance data on hand at the moment, but if that is needed I'm sure they could be gotten.

Not a solution?

On sites with frequent, small changes to entities, we end up with tons of field revision table rows with identical values, their only difference being the revision ID. #2083451: Reconsider the separate field revision data tables aims to improve things by avoiding revisions entirely, which is not my goal.

I'm pretty sure this would be absurd and break some fundamental law of relational databasing, but would it be possible to somehow not duplicate field data when creating a new revision of an entity? Let me 'splain: In #2297817: Do not attempt field storage write when field content did not change, we made it possible to prevent unnecessary db writes when updating an existing revision with field data that has not changed. But when creating a new revision, we, of course, need a new table row with that revision ID. But what if we somehow said "Hey, I'm an entity revision collecting all my associated field data OH WAIT THAT FIELD TABLE DOESN'T HAVE AN ENTRY FOR MY REVISION WTF oh hmmm maybe that just means the field data hasn't changed since the last revision... Lemme just grab the data for that field from the last available revision." E.g., say the current revision of node X is 99, but the latest row in node_revision__field_foo for Node X is 95, so Entity API "magically" grabs that row when populating field data on node X.

Now, even if what I'm trying to explain makes sense, is there any sort of "magic" we could do in Entity API to make it (a) not suck from a performance standpoint and/or (b) not break lots of unintended things?

Remove render caching?

Problem/Motivation

Render caching made sense when it was introduced in Drupal 7, and even when it was expanded to be used for many more things in Drupal 8.

But since then, Dynamic Page Cache was added in #2429617: Make D8 2x as fast: Dynamic Page Cache: context-dependent page caching (for *all* users!). It's enabled by default. The benefit is that there's a single cache hit to render most of the page, rather than many fragments to retrieve from render cache. This saves a lot of I/O. And has a lower complexity.

Also important: there have been zero noteworthy bug reports during the 19 months that Drupal 8 has been out. In that time, Dynamic Page Cache has accelerated millions of page views.

That begs the question: do we still need render cache? Dynamic Page Cache is caching at a coarser level, so avoids lots of work. Maybe we don't need the granular caching layers as much anymore. That also greatly improves understandability/maintainability/DX. And the render cache bin is the one that has hundreds of thousands of cache items on big sites: #2526150-155: Database cache bins allow unlimited growth: cache DB tables of gigabytes!, so that'd go away too.

Can we remove render caching altogether? Or do we just disable it for e.g. blocks & entities, but keep it for Views, where it's likely most impactful?

Proposed resolution

TBD

Remaining tasks

TBD

User interface changes

TBD

API changes

TBD

Data model changes

TBD

Date parts are not translatable in Datelist::validateDatelist()

Problem/Motivation

If a part of datelist is not filled, you see a translatable error with a description which parts are not filled.
However, the names of the parts are not translatable because they are pasted as simple string literal parameters:

// The $value might be either "year", "month" or "day".
$form_state->setError($element[$value], t('A value must be selected for %part.', ['%part' => $value]));

Proposed resolution

Wrap the $value variable with t() function.

Remaining tasks

None.

User interface changes

Fully translatable error messages for invalid datetime fields.

API changes

None.

Data model changes

None.

Viewing all 294415 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>