Quantcast
Channel: Issues for Drupal core
Viewing all 298251 articles
Browse latest View live

Try to do less in theme_get_settings() on every request

$
0
0

Problem/Motivation

Anonymous user, frontpage, without page_cache (entire request time 94ms).

In there we spend 1ms in theme_get_setting(), which does quite a lot:

Function NameCallsCalls%Incl. Wall Time
(microsec)
IWall%Incl.
MemUse
(bytes)
IMemUse%Incl.
PeakMemUse
(bytes)
IPeakMemUse%
Current Function
theme_get_setting89.4%1,1381.2%175,4961.1%173,3841.0%
Exclusive Metrics for Current Function12110.6%6,8403.9%3,3681.9%
Parent functions
system_page_attachments337.5%1,03691.0%174,12099.2%173,384100.0%
template_preprocess_page337.5%615.4%7360.4%00.0%
_bartik_process_page225.0%413.6%6400.4%00.0%
Child functions
file_create_url22.9%56849.9%118,08867.3%110,76063.9%
Drupal::config22.9%19517.1%10,6086.0%38,37622.1%
Drupal\Core\Config\ConfigBase::get1420.0%12010.5%8,5524.9%2,3761.4%
spl_autoload_call11.4%403.5%10,8966.2%11,1446.4%
Drupal\Core\Config\ConfigBase::setData11.4%332.9%6,4323.7%00.0%
Drupal::theme811.4%181.6%6320.4%5840.3%
Drupal\Core\Config\ConfigBase::set22.9%161.4%4,6482.6%3,9362.3%
drupal_static811.4%90.8%9440.5%9440.5%
file_exists11.4%60.5%6240.4%00.0%
Drupal\Core\Config\Config::get22.9%40.4%6480.4%00.0%
Drupal\Core\Extension\Extension::getPath22.9%40.4%8640.5%00.0%
Drupal::service11.4%30.3%6320.4%00.0%
_system_default_theme_features11.4%10.1%1,8161.0%00.0%
Drupal\Core\Theme\ActiveTheme::getName811.4%00.0%6560.4%6560.4%
Drupal\Core\Extension\ThemeHandler::listInfo11.4%00.0%6640.4%00.0%
Drupal\Core\Theme\ThemeSettings::__construct11.4%00.0%6640.4%5760.3%
in_array710.0%00.0%6240.4%00.0%
Drupal\Core\Theme\ThemeManager::getActiveTheme811.4%00.0%6640.4%6640.4%

Proposed resolution

Try to cache the theme settings not in the request but between requests. One really good place could be the cache entry for the active theme object.
In case we would store it there, we would avoid the call to $themes = \Drupal::service('theme_handler')->listInfo(); in there.

Remaining tasks

User interface changes

API changes

Data model changes


Display an error message if the container needs to be rebuilt

_filter_url() is slow because preg_match() is slow, use strcasecmp() when possible

$
0
0

I have a page where _filter_url() is 30% of the load time. The content has lots of markup and the $chunks array in _filter_url() ends up with over 5000 items. A simple change from preg_match() to strcasecmp() reduces my page load time for _filter_url() to only 20% of the page time, from 190msec to 120msec.

Consider making the non-metadata bits of GeneratedUrl, GeneratedLink and FilterProcessResult only extensible, not overridable

$
0
0

Problem/Motivation

Alex Pott felt it'd be better if Breadcrumb extends CacheableMetadata would not allow its setLinks() method to overwrite $this->links if it wasn't empty anymore.

Therefore, we should also look at the other similar cases, which are GeneratedUrl, GeneratedLink and FilterProcessResult

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Refactor FormBuilderTest::testChildAccessInheritance

$
0
0

While working on #2526326: Update CacheableMetadata & AccessResult to use RefinableCacheableDependency(Interface|Trait), @alexpott noticed that some unit tests didn't pass when doing phpunit -c core --testsuite unit.
I spent some time fixing the tests (PermissionAccessCheckTest, FormBuilderTest and MenuLinkTreeTest).

While the tests pass now, the changes done to FormBuilderTest in https://www.drupal.org/node/2526326#comment-10217859 look like they reduce the test's value or it was doing useless things before.

We need to decide if the removal of the cache contexts from the tests makes an actual difference and if it does, we need to improve the test so it's less fragile.

Tag queue API queries to enable query alteration (and backport it)

$
0
0

For several reasons, I would like to hook_query_alter Queue API claimItem queries:

  • Dequeue items only after some configurable time has elapsed since enqueueing (DelayedQueue use case)
  • Do not return queue items if certain callback prevents it (HookableQueue use case)
  • Other cases I can't remember now...

A possible solution could be to write several Queue Backends that override Drupal's default implementation. But, AFAIK those backends would not be 'stackable'. I mean, be able to pick which features you would like a specific queue to configure via some kind of flexible queue backend. So, I thought that hook_query_alter'ing those could do the trick. I would prefer to write a single module in which I could configure the above settings independently.

Also, this could be an improvement on DX if someone wants ever to do other crazy things with queues (think on sending queue queries to a different, dedicated MySQL instance) that comes at no cost, AFAICT.

So, tagging the DatabaseQueue queries could be an easy and simpe enough way to achieve it. Since tagging will not incur in any performance penalty and would not have any compatibility problems my prpoosal would be:

  • Discuss which tags to add to which queries
  • Add those tags once defined
  • Backport them to Drupal 7, where I need them the most

Note that backporting this change to D7 looks like a backwards compatible change and it's an added value to attract more contributors to work in (myself included).
Edit: As a (working) proof of concept I've created Tagged SystemQueue and implemented DelayedQueue use case successfully. It would be nice to have this in core for convenience.

Fields should support twig iterable

$
0
0

Problem/Motivation
Twig has a feature to check if an object is iterable: http://twig.sensiolabs.org/doc/tests/iterable.html

This would be desirable in relation to fields that may accept multiple values. For example, I might want to write a template like this that would allow to display field items as a list when there are multiple values, but otherwise display a single field item as a div without the wrapper.

<div{{ attributes.addClass(classes) }}>
  {% if not label_hidden %}
    <h3{{ title_attributes.addClass(title_classes) }}>{{ label }}</h3>
  {% endif %}
  {% if items is iterable %}
    <ul{{ content_attributes.addClass('field-items') }}>
      {% for item in items %}
        {{ kint() }}
        <li{{ item.attributes.addClass('field-item') }}>{{ item.content }}</li>
      {% endfor %}
    </ul>
  {% else %}
    <div{{ item.attributes.addClass('field-item') }}>{{ item.content }}</div>
  {% endif %}
</div>

I have tested this in the current beta release (8.0.0-beta14 at time of writing), and while adding this to the template causes no errors, it also does not produce the expected behavior. I suspect that would be because fields end up being iterable objects to twig regardless of how many values they have. I also suspect that being able to support this feature for fields would be non-trivial, so I'm adding it initially as a feature request for 8.1.x.

Add new HTML5 FAPI Element : week


Taxonomy exposed filter needs checkbox option

$
0
0

Exposing a taxonomy filter in views gives two choices of widget, autocomplete and select box.
Why not checkboxes / radios also?
Should be about 10 lines of code in \Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid and will save the need for a contrib module

Allow changing path to search

$
0
0

Currently search is hardcoded to be /search (as per SearchPageRoutes.php).

It would be great if this could be made configurable.

Also I notice there is a todo to, by default, redirect /search to the default search page - this would be great to be a setting to.

JSONAPI filter for reference field by null value OR by string

$
0
0

Problem/Motivation

Once https://www.drupal.org/project/drupal/issues/3025372 was merged I hoped that filtering for reference fields would work correctly.
I'm still not able to select nodes that are NOT tagged with any value OR are tagged with specific value.

Steps to reproduce

Imagine a content type "node_type" with a field: field_reference that is a taxonomy reference.

Doing...
jsonapi/node/node_type?
filter[main][group][conjunction]=OR
filter[condition1][condition][path]=field_reference
filter[condition1][condition][operator]=IS NULL
filter[condition1][condition][memberOf]=main
filter[condition2][condition][path]=field_reference.name
filter[condition2][condition][operator]==
filter[condition2][condition][value]=Test
filter[condition2][condition][memberOf]=main

I would expect to get all nodes that have no tags at all in that field combined with all nodes tagged with "Test" term.

In reality only nodes tagged with Test will be returned.
It seems that two joins are added for node__field_reference table. A LEFT join used to filter data and an INNER join that is used to filter only published taxonomy terms.
That inner join is added only when I filter by value. If I use only the first condition, with IS NULL, the inner join is not added (would be useless).
When that inner join is added all nodes that don't have a tag are excluded.

Is there a way to avoid automatic condition for published terms?
I altered query to remove joins that broke my filtering but I think that first LEFT join should be reused to check term state.

Claro - Views Filter Expose Option Form - Broken HTML

$
0
0

This took me so long to figure out.

So I'm working on a new views filter (the boundary filter in the geolocation module here on d.o). That filter has a value form, but currently no operators. This will be important in a moment.

When you open the settings window in the views admin area, you do see label & description, then the value form, and then nothing. All additional options are invisible. They exist in the HTML, but outside of the modal area and can therefor not be interacted with, except using browser tools. See attached image.

The reason for this is, that Claro in claro_form_views_ui_config_item_form_alter() more or less unconditionnally adds 1 open div before the operator form part, and 1 closing div after the value form part, obviously assuming, they would always both be present.

This IMHO already structures additional option form elements in a weired way, when it works as intended, but when there is no operator to begin with, it just breaks. See attached image to get an idea. The --operator part will not be rendered for lack of content.

[Policy] Define explicit Drupal 10 end of life date of early December 2026 regardless of Drupal 12 release date

$
0
0

Problem/Motivation

Currently, depending on the release of Drupal 12, Drupal 10 may be end of life mid-June, early August or early December in 2026. See #3449806: [12.x] [meta] Release Drupal 12 in 2026 which currently says "Drupal 12 will be released in mid-June, early August, or early December 2026" and https://www.drupal.org/about/core/policies/core-release-cycles/schedule which currently says "Drupal 10 will reach end of life mid-late 2026, when Drupal 12 is released. The exact date is not yet set.".

We have announced this at https://www.drupal.org/blog/drupal-10-will-be-supported-until-the-releas...

The core team would like to get to a stable Drupal 12 by mid-June, but the three windows give an uncertainly to the Drupal 10 EOL timeline. However with a theoretic last Drupal 12 release window in early December 2026, there would nonetheless be a possibility that Drupal 10 would be supported until early December 2026 under the current communicated process.

Steps to reproduce

Proposed resolution

Define early December 2026 as the definite EOL time for Drupal 10.

@catch already consulted the security team and they have agreed to this.

Remaining tasks

When fully agreed, update the release schedule page and add a change record.

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

[Meta] Bug Smash Initiative monthly triage meta commencing 2025-05-13

$
0
0

Meta for triage credit, please note: you only need to add a comment for one issue that was triaged and closed, not every one.

Remember to add the tag 'Bug Smash Initiative' to issues that are triaged.

Uploading files breaks drupal page cache

$
0
0

Problem/Motivation

Not sure if that is really a bug or a feature request, but when an anonymous user uploads a file to a form, the Drupal page cache stops working. This is caused by anonymous_allowed_file_ids being set for the anonymous user session, allowing the anonymous user access to the uploaded file. The created session then breaks the Drupal page cache, since Drupal\Core\PageCache\RequestPolicy\NoSessionOpen automatically denies the page cache for all users that have a session.

Steps to reproduce

  1. Enable the page cache module.
  2. Visit a page and verify the page can be served from the page cache.
  3. Create a form with a file upload field, configured to upload private files.
  4. Upload a file to the form as an anonymous user.
  5. The page that was previously served from the cache, is now no longer cached.

Proposed resolution

Not sure what would be the best way. It seems uploading and submitting the form still works even when the user does not have access to the file. I guess we could:

  1. Add a flag to the file fields to make creating a session optional per field.
  2. Add a generic option the the site to disable creating sessions for users in all file fields.
  3. Maybe create a permission that can be enabled for the anonymous user role: "View own files".

Remaining tasks

  1. Discuss the best way to move forward.
  2. Write a patch
  3. Write tests
  4. Review
  5. Commit

User interface changes

TBD

Introduced terminology

None

API changes

TBD

Data model changes

TBD

Release notes snippet

TBD


[PP-2] JSON-based data storage proposal for component-based page building

$
0
0

Note: I'm opening this issue in the Drupal core queue for discussion, but I think any initial implementation should be done first in contrib, to make sure it's robust and well-tested in the wild before adding to core.

Problem/Motivation

See #3375371: [meta] Improve the page building experience for background discussion on improving Drupal's page building experience.

Layout Builder's data model is based on sections and blocks. You can put blocks into sections, but you can't put sections into sections, sections into blocks, or blocks into blocks. There are some workarounds to this, such as enabling Layout Builder on your block types, which then does let you put sections into those blocks, and then other blocks into those sections, but the UI for this is cumbersome, and the resulting data model when you do this ends up being complex, especially when compared to something like Gutenberg, where you can smoothly add "blocks" (Gutenberg blocks, not Drupal blocks) inside of "blocks", building as deep of a hierarchy as you want, all within a single cohesive UI.

Also, Layout Builder's layout_builder__layout_section column is a serialized PHP array, so can't be queried by the database, and in some cases that serialized PHP array can be quite large, which can lead to huge database sizes when there's lots of nodes, revisions, languages, etc. See #3267444: To reduce database size, convert layout_builder__layout_section column to a hash of the content.

A lot of sites prefer to use Paragraphs over Layout Builder for page building, but Paragraphs has its own scaling challenges, because every time you create a new node revision, a new paragraph revision gets created for every paragraph (and for deep structures, every paragraph's child/descendant paragraphs), including for all the paragraphs unchanged by that particular node revision, and all those new revisions end up writing database records for every translation, even though the revision is only changing the content for one of those languages.

There's also the question of should paragraphs or layout builder inline blocks even be their own entities to begin with. They were modeled that way in order to make them fieldable, and fields can only be added to entities, but modeling them as entities comes with its own baggage (performance issues from them having their own CRUD hooks, highly nested database transactions when saving, having them show up as separate JSON:API resources from the node or needing special code to avoid that, etc.).

Both Paragraphs and Layout Builder were created when Drupal still had to support MySQL versions that lacked JSON support. Their data models are reasonable given the constraints of relational databases. But MySQL, PostgreSQL, and SQLite all support JSON now, which gives us an incredible tool/opportunity to create a more optimal data model.

Requirements

Config vs. content

Layout building needs to support multiple 'modes'. For 'bundle templates', or specific use cases like the navigation module, this only involves writing configuration, not entity data. This issue is primarily concerned when LB/XB is used to create individual entity content.

For individual entity content, layout builder will support both 'fixed' and 'loose' sections. For example the top section of a bundle could have particular, fixed, components source from traditional field API fields - such as a lead image and tags field.

However, underneath, there could be 'loose' content where content editors can choose an arbitrary number of components and populate them with content - this can include some level of nesting, .e.g. a 'side by side' or 'accordion' component which is then populated by further components.

Data structure

The data structure needs to be consumable by JSON:API, it therefore makes sense if the content for 'loose' sections is available in the order that it is entered - e.g. if there are five text paragraphs, then an image figure, then five more text paragraphs, that when rendered by JSON:API these are shown as 5 text -> 1 image -> 5 text, not 1 image -> 10 text.

Alternative rendering modes

Once you have 'loose' sections in layout builder, you have not only layout information, but also 'content', and this content needs to be available in places which are not just the full view mode of the entity.

Examples:

1. Both core search module and search API rely on view modes to define which fields get indexed for full text search. This implies that those view modes will need to present information that was added to 'loose' sections of the full entity layout, because that could be all the content of the article, and not only this, but the 'search' view mode may want to exclude certain elements such as related articles views blocks, field labels, add to cart language and similar.

Simplenews has a very similar model - where a 'newsletter' view mode can be set up, and this controls the rendering of the content when it appears in a newsletter.

2. A university might have a 'course' content type, and in the 'loose' section of the content want to add 'student testimonials' with a student name, image, and quote. Later in their course listing view, they want to pull out one testimonial into that listing too. This also implies different view modes having access to content added via the default/full view mode.

'Loose' content for multiple bundles?

Most of the discussions assume, implicitly, that 'loose' content will only be possible on the default view mode, but there has not been an explicit decision made or documented about this. e.g. would we allow a site builder to configure a content type so that two view modes both allow loose content?

Proposed resolution

A lot of different permutations of data model have been discussed in the issue, trying to summarise some.

I think the proposed resolution explains well why we want to avoid nested entities (either blocks or paragraphs) at least as the default way that components added, due to the data fragmentation and performance issues they involve. The following then concentrate on data models that can be represented by a single entity.

1. Original proposal from effulgentsia and close to the current proof of concept implementation in XB - two single cardinatlity JSON fields

Let's assume that what we want to store is a tree of component instances. Since SDCs are now in Drupal core, let's use its terminology of props and slots.

Props hold the properties of the component. For example, for Layout Builder's inline blocks, each of the block type's fields can be thought of as a prop. Props can also include data that we don't currently model with fields, such as block configuration. Ideally, we'd also be able to use components that aren't Drupal blocks, such as perhaps SDC components directly, Paragraphs content, or who knows, maybe even Gutenberg blocks. I propose that the best common denominator is that each prop value just be something that can be represented with a TypedData object.

Meanwhile, slot values are other components, thus creating the tree. For example, Layout Builder sections can be thought of as components where the section's regions are its slots. But, unlike with Layout Builder today, we want a data storage model that allows slot values to be filled with components that themselves have slots, thereby allowing trees of any depth, enabling the easy creation of pages with complex layouts. Also, we want a data model where a component can have both props and slots, as many of the SDC components in Drupal core already do.

  • Represent the component instance tree as two single-valued fields: a "layout" field and a "components" field. Conceptually, each field would be a JSON field. The layout field would contain the JSON just representing the tree (which component instance IDs are in which slots) but without any of the prop values. The "components" field would contain the JSON object whose top-level keys are the component instance IDs and values are the prop values for that component instance. This separation allows for either symmetric translations (make the "layout" field not translatable) or asymmetric translations (make the "layout" field translatable).
  • However, as an optimization, don't actually store the JSON itself in these field values, but instead have a separate lookup table that maps a short hash (for example, the first 8 characters of a hash) to the JSON value, similar to what is proposed in #3267444: To reduce database size, convert layout_builder__layout_section column to a hash of the content. This way, duplicate values across revisions only duplicate the hash, not the full JSON.
  • For the "components" field, instead of hashing the entire JSON object, hash each component instance separately, so that what's stored in the components field is a JSON object containing each component instance ID mapped to a hash of the JSON-encoded props for just that component instance. This way, if a page has 50 component instances, and a given revision only changes the props on one of them, the hash/lookup for each of the unchanged 49 gets to be reused.

I think the above storage model achieves all of our desired goals:

  • Scalable to many component instances, revisions, and translations.
  • Supports symmetric and asymmetric translations.
  • Supports nesting to any depth.
  • Doesn't require any entities other than the host entity, except where there's a separate reason to need separate entities, such as references to media.
  • Unlike with serialized PHP arrays, all data can be individually queryable thanks to database support for JSON.

Advantages
Content is stored linearly in the order that it is entered.
Allows arbitrary amounts of field data to be supplied as props.
Content of the field is controlled by XB, not the manage fields page.

Disadvantages
- Requires complex SQL JSON queries when retrieving anything other than the full JSON blob, for example checking field type or component usage when validating module uninstall.

- Not clear how alternative view modes (search, or the course testimonials example) would be able to reference content stored in this data model without some kind of JSON tree querying syntax.

- Not clear what happens if two view modes allow 'loose' content, is that another field instance?

2. Relational field union

https://www.drupal.org/project/field_union allows a single field to combine multiple field types. This would allow each component available to be mapped to a field union, and then each set of slots for a component becomes a field union value.

This would require a field-union field to exist per available component. The 'layout tree' JSON field would then need to reference the field union field + delta each time.

Advantages
Field union fields would have all of the features currently available to field API fields (because they are). This would cover the search and course testimonial use cases.

Disadvantages
- There has to be a 101 mapping between components (which allow data entry) and field union fields.
- would bloat the views UI (and possibly elsewhere) with a lot of fields that likely would never need explicit views support
- Content in the field union fields is in an arbitrary order unrelated to its representation in the layout at all.
- field union fields have a fixed number of columns, so hard to do things like have multiple image field references in a single field value

3. Field union JSON

This is conceptually based on the field union module but with an important difference.

In this case a single field union field would be a multiple value field API field, however the field values would be stored in a JSON column. This would allow different 'union types' to be stored in a single field.

The field table would store the usual field columns, plus the 'field union type' to identify which field union is stored, plus a single 'values' JSON column holding the actual entered field values.

For example:
delta 0: 0, paragraph, {text, format}
delta 1: 1, highlighted_ content, {entity reference, text}
delta 2: 2, media_gallery, {media reference, media reference, media reference }
delta 3, 3, course_testimonail {student name, media reference, text, format }

Advantages:
- Content is stored linearly as it is entered.
- Allows nested multiple value columns.
- can be queried without JSON, allowing content dependencies to be calculated efficiently.
- possible to reference the field via other view modes, so handles the search and course testimonial cases

Disadvantages:
- The course and testimonial cases would still require some kind of 'field delta filtering', for example 'render the first occurrence of a testimonial union type from this field'.

- The field configuration would need to control the allowed field union types, this would need to be synced (or controlled by) the XB interface for allowed components.

Data model changes

An entirely new data model. So, we'll need some kind of BC layer for or upgrade path from Layout Builder. I'd like to first get feedback on this proposed data model before thinking about the BC layer / upgrade path though.

Remaining tasks

Discuss and poke holes in this proposal.

Determine if there is a better message for AJAX errors

$
0
0

Problem/Motivation

Before #2987444: Ajax errors are not communicated through the UI there was no way to know via the UI that an Ajax error occurred. The only evidence of it happening was in the JS console.

In #2987444: Ajax errors are not communicated through the UI, functionality was added so if there is an Ajax error, this is made evident in the UI with the following message generated by the messages API.

Oops, something went wrong. Check your browser's developer console for more details.

While the specifics of the error still require opening the JS console, the fact that an error took place is actually apparent, which is a big improvement.
Because it's difficult to find the ideal wording for pretty much anything this issue exists to discuss potential improvements to the content of that message. If a largely-agreed-upon better option emerges here, we can update core to use that phrasing instead. There were clear benefits to getting that functionality into core as soon as possible with acceptable messaging, and deferring the composition of ideal messaging to a followup.

Proposed resolution

Agree on a better default message.

Remaining tasks

Agree on, and then set, a better default message.

User interface changes

API changes

Data model changes

Release notes snippet

Block plugins need to be able to update their settings in multiple different storage implementations

$
0
0

Problem/Motivation

Block plugins are used in core in three different modules:

1. Block module (config entities)
2. Layout builder (config entities and also view mode overrides in content).
3. Navigation (a single config object - navigation.block_layout, but using the layout builder data structure)

Also, in Experience Builder - see #3520484: [META] Production-ready ComponentSource plugins and #3501708: [SPIKE] Prove that it will be possible to apply block settings update paths (assuming #3521221 in core) to stored XB component trees in config/content which inspired this issue.

When a block plugin updates its settings structure, all of these places should be updated, but, this is not the case.

As far as I can tell, there are two reasons this hasn't come up before:
1. We rarely update block plugin settings so have got lucky that we haven't fatally broken any sites yet.
2. We don't validate block plugin settings config in these various places yet.

/**
 * Updates Search Blocks' without an explicit `page_id` from '' to NULL.
 */
function search_post_update_block_with_empty_page_id(&$sandbox = []) {
  $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
  $config_entity_updater->update($sandbox, 'block', function (BlockInterface $block): bool {
    // Only update blocks using the search block plugin.
    // @see search_block_presave()
    if ($block->getPluginId() === 'search_form_block'&& $block->get('settings')['page_id'] === '') {
      $settings = $block->get('settings');
      $settings['page_id'] = NULL;
      $block->set('settings', $settings);
      return TRUE;
    }
    return FALSE;
  });
}

This is updating block config entities, but not layouts or navigation.

Search module theoretically could add additional updates for layouts and navigation, and also update their config with the same changes, but it doesn't. And even if it did do that, search module can't update experience builder, because that's in contrib, or any other theoretical place that consumes block plugins and stores their settings.

Some of this is going to be quite painful to implement, but I think conceptually it ought to work.

We will also need to change the search update to use this new, correct method, and document this very clearly somewhere too. It's like an extra level of update hell on top of normal config entity updates which everyone already gets wrong all the time.

Steps to reproduce

Proposed resolution

I think we need to add an API for updating block plugin settings.

It would look something like this - very rough:

BlockPluginSettingsUpdaterInterface {
  isUpdateNeeded(array $stuff): bool;
  updateStuff(array $stuff): array;
}

This is a kind of formalization/abstraction of what ViewsConfigUpdater does.

Search module's update would then look something like this:

class SearchEmptyPageUpdater implements BlockPluginSettingsUpdaterInterface {
 // logic here
}

<?php
hook_post_update_NAME(&$sandbox) {
\Drupal::service('block_plugin_updater')->updateBlockPluginSettings('search', 'SearchEmptyPageUpdater::class', $sandbox);
}

The new block_plugin_updater service then triggers an event/hook, and... this bit is fuzzy, layout builder, block, navigation, experience builder, return a callback or something, that does what they would normally do in their hook_update_N().

Either they need create a batch that does the update (which would end up as a nested batch inside the post update hook), or return enough information for the block_plugin_updater class to do that.

Conversely, updates are not the only place that this logic needs to run, it also needs to run on presave of all these different config entity types to support shipped config too.

Soo SearchEmptyPageUpdater and its equivalents, as well as implementing the interface, could also be a plugin. Then the various hook_entity_presave() can call another core service, which takes a config entity, discovers all the blocksettingsupdater plugins, then runs that same logic to update the config entity before it's saved. Or maybe not via a service and do it directly since they're going to be responsible for determining where in their config structure the settings live and passing that to the updater plugins.

To try to summarize:

Modules that provide block plugins, when they update the settings structure, need to provide a 'block plugin settings updater' plugin implementing an interface with the logic to detect if an update is needed and also update the data structure. And they also need to implement a hook_post_update that calls a service method, passing the plugin to it.

Modules that consume block plugins and store their settings, need to implement a hook_entity_presave(), and in that presave, call a service (or whatever), that gets all the block plugin settings updater plugins and runs their logic.

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Cannot delete a field which uses JSON type

$
0
0

Problem/Motivation

Discovered in #3487077: Page has Metatag integration.

When trying to uninstall Experience Builder, it crashes with "Unable to parse the column type JSON".

That's because \Drupal\sqlite\Driver\Database\sqlite\Schema::getFieldTypeMap does not contain a mapping for JSON fields. No other driver errors for this. That's because \Drupal\sqlite\Driver\Database\sqlite\Schema::introspectSchema is SQLite specific.

So when deleting the field it crashes.

Steps to reproduce

Install XB or any field using json type. Try to uninstall or delete field. It crashes

'pgsql_type' => 'jsonb',
          'mysql_type' => 'json',
          'sqlite_type' => 'json',
          'not null' => FALSE,

Proposed resolution

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Router.php, "No route found for the specified format html. Supported formats: json, xml."

$
0
0

Problem/Motivation

stack used:
- domain module (with domain_entity on) https://www.drupal.org/project/domain
- drupal/jsonapi_extras https://www.drupal.org/project/jsonapi_extras
- webforms
- Webforms Rest https://www.drupal.org/project/webform_rest

and when I call any REST endpoint, for example webform_rest//fields?_format=json
I get "No route found for the specified format html. Supported formats: json, XML."

The stack looks like below

array(
    0 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Routing\\Router.php',
        'line' => 280,
        'function' => 'filter',
        'class' => 'Drupal\\Core\\Routing\\RequestFormatRouteFilter',
        'type' => '->',
    ),
    1 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Routing\\Router.php',
        'line' => 126,
        'function' => 'applyRouteFilters',
        'class' => 'Drupal\\Core\\Routing\\Router',
        'type' => '->',
    ),
    2 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Routing\\Router.php',
        'line' => 103,
        'function' => 'matchRequest',
        'class' => 'Drupal\\Core\\Routing\\Router',
        'type' => '->',
    ),
    3 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Path\\PathValidator.php',
        'line' => 161,
        'function' => 'match',
        'class' => 'Drupal\\Core\\Routing\\Router',
        'type' => '->',
    ),
    4 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Path\\PathValidator.php',
        'line' => 122,
        'function' => 'getPathAttributes',
        'class' => 'Drupal\\Core\\Path\\PathValidator',
        'type' => '->',
    ),
    5 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Path\\PathValidator.php',
        'line' => 89,
        'function' => 'getUrl',
        'class' => 'Drupal\\Core\\Path\\PathValidator',
        'type' => '->',
    ),
    6 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Url.php',
        'line' => 427,
        'function' => 'getUrlIfValidWithoutAccessCheck',
        'class' => 'Drupal\\Core\\Path\\PathValidator',
        'type' => '->',
    ),
    7 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Url.php',
        'line' => 319,
        'function' => 'fromInternalUri',
        'class' => 'Drupal\\Core\\Url',
        'type' => '::',
    ),
    8 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Url.php',
        'line' => 221,
        'function' => 'fromUri',
        'class' => 'Drupal\\Core\\Url',
        'type' => '::',
    ),
    9 => array(
        'file' => '.\\web\\modules\\contrib\\domain_entity\\src\\HttpKernel\\DomainEntitySourcePathProcessor.php',
        'line' => 147,
        'function' => 'fromUserInput',
        'class' => 'Drupal\\Core\\Url',
        'type' => '::',
    ),
    10 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\PathProcessor\\PathProcessorManager.php',
        'line' => 108,
        'function' => 'processOutbound',
        'class' => 'Drupal\\domain_entity\\HttpKernel\\DomainEntitySourcePathProcessor',
        'type' => '->',
    ),
    11 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Routing\\UrlGenerator.php',
        'line' => 388,
        'function' => 'processOutbound',
        'class' => 'Drupal\\Core\\PathProcessor\\PathProcessorManager',
        'type' => '->',
    ),
    12 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Routing\\UrlGenerator.php',
        'line' => 297,
        'function' => 'processPath',
        'class' => 'Drupal\\Core\\Routing\\UrlGenerator',
        'type' => '->',
    ),
    13 => array(
        'file' => '.\\web\\core\\lib\\Drupal\\Core\\Render\\MetadataBubblingUrlGenerator.php',
        'line' => 105,
        'function' => 'generateFromRoute',
        'class' => 'Drupal\\Core\\Routing\\UrlGenerator',

As you see DomainEntitySourcePathProcessor.php invokes Url::fromUserInput() and what he tries to do is basically detect if user has access to access this route in terms of Domain Entity logic. If for example I instantly return $path value form DomainEntitySourcePathProcessor::processOutbound() not doing any logic - then all works, no error. But I cant do that, the logic must happen.

And what happens later is that Symfony\Component\HttpFoundation\Request is recreated multiple times. But its constructor or factories does not care about _format value passed in any manner, it must be manually set, otherwise Request::duplicate() method must be used.

I have examined all the chain few times (this problem I observe for 10 months and its time to finally solve it, client needs that).
And my suggestion is to do change in web\core\lib\Drupal\Core\Routing\Router.php

  public function match($pathinfo): array {
    $request = Request::create($pathinfo);
    $request->getRequestFormat(\Drupal::request()->getRequestFormat()); // ADD THIS LINE

works good, solves the problem and nothing broken.

I will publish the patch soon.

P.S. I have a feeling like the problem should be solved on some level higher, maybe where getUrlIfValidWithoutAccessCheck() should exist option for full path with ?query support in URL or maybe version with full request. But I cant formulate that right now

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Viewing all 298251 articles
Browse latest View live


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