Problem/Motivation

\Drupal\Core\Field\RequiredFieldStorageDefinitionInterface and its only method ::isStorageRequired() have been introduced in #2390495: Support marking field storage definitions as required.
BaseFieldDefinition implements that interface and method and also provides its own setter method ::setStorageRequired().
The method implementation \Drupal\Core\Field\BaseFieldDefinition::isStorageRequired() however falls back to \Drupal\Core\Field\BaseFieldDefinition::isRequired() if the setter has not been used.

This means that defining a field like this:

$field = BaseFieldDefinition::create('string')
        ->setRequired(TRUE);

will result automatically into a field, whose storage is required and the following will return TRUE even without it being explicitly set:
$field->isStorageRequired();

However ::isStorageRequired() is documented like this:

   * If a field storage is required, NOT NULL constraints will be added
   * automatically for the required properties of a field type.

Core is not doing that yet automatically, but there is an issue to implement that, which is in an almost finished state - #2841291: Fix NOT NULL handling in the entity storage and 'primary key' changes when updating the storage definition of an identifier field.

So now we have 2 methods for whether a field is required - isRequired and isStorageRequired, where the first is used for form inputs and validation purposes, while the second is used to flag the storage of the field in a shared table as required - for example by adding the NOT NULL constraint to the schema as described in the method's documentation.

Please note that we even already have an implementation in core, which is checking whether a field is storage required and if so a NOT NULL constraint is being added. From \Drupal\comment\CommentStorageSchema::getSharedTableFieldSchema():

        case 'entity_type':
        case 'field_name':
          assert($storage_definition instanceof RequiredFieldStorageDefinitionInterface);
          if ($storage_definition->isStorageRequired()) {
            // The 'entity_type' and 'field_name' are required so they also need
            // to be marked as NOT NULL.
            $schema['fields'][$field_name]['not null'] = TRUE;
          }
          break;

Unfortunately there are 4 problems with ::isStorageRequired() falling back to ::isRequired():

  1. If we clone a required base field and return it as non-required from an implementation of hook_entity_bundle_field_info() for a specific bundle, then we'll still not be able to save an entity for that bundle without providing a value for the overridden field as the storage might already be created with a NOT NULL constraint for that field.
  2. It is impossible to make the base field non-required after it was installed even if we haven't explicitly requested the NOT NULL constraint.
  3. We cannot yet properly update \Drupal\Core\Field\BaseFieldDefinition::createFromFieldStorageDefinition() and let it inherit the storage_required flag, because it is wrong to set the flag if it wasn't set on the passed field storage definition, but TRUE is returned because of the fallback to ::isRequired().
  4. This issue is also a blocker for #3014760: [PP-2] Create an abstract composite field definition/storage definition and update BaseFieldDefinition to use it.
    The proposal there is that the field storage definition becomes a property on the base field definition in order to achieve a clean separation between a field storage and a field definition similar to configurable fields. As such it is not possible for the storage definition to call its parent - the field definition from within ::isStorageRequired() and access ::isRequired().

As the use cases and meaning of a required and storage required are different a check for storage required should not fall back to required.

It is worth mentioning that regarding bundle fields only FieldConfig is aware of the required property and FieldStorageConfig does not know anything about it.

Only FieldConfigInterface extends the FieldDefinitionInterface where ::isRequired() is defined. The FieldStorageDefinitionInterface does not extend FieldDefinitionInterface.

This does not match BaseFieldDefinition where everything belongs together, but only on bundle fields we have a clear separation between what is a field definition setting and what is a field storage setting.

Currently there is no workaround for allowing a field on a specific bundle to not be storage required, if a field has gotten a NOT NULL constraint as documented just because it has been simply flagged as required but not as storage required. Core might not be adding the NOT NULL constraint automatically yet, but has documented that it should be added if the field is storage required and doing that in custom or contrib code is therefore perfectly valid and according to the core's documentation. Considering the 4 different problems this is not to be confused with simply being a documentation issue.

Steps to reproduce

The test from the attached patch in #2 - \Drupal\KernelTests\Core\Entity\EntityFieldTest::testRequiredChangeOnBundleOverride() is showing an example of how core behaves with and without automatic NOT NULL constraint based on the output of ::isStorageRequired().

There we create a required base field and two bundles, where for the second bundle we return an altered base field definition by flagging the field as non-required.

This represents a perfectly valid use case as we might want something to be optional on one bundle, but required on another.

Then we create and save an entity for the bundle where the field is not required.
First we do that with current behaviour where NOT NULL constraints are not yet added automatically based on the output of ::isStorageRequired(). We assert that the entity is saved properly.
Then we recreate the entity tables by using a different storage schema handler, which adds the NOT NULL constraint to storage required fields. As one can see from the test results we cannot anymore save an entity for the bundle without providing a value for a field which isn't required on that bundle, but is required on the first bundle.

Proposed resolution

As the use cases and meaning of a required and storage required are different a check for storage required should not fall back to required.

Therefore we need to remove the fallback to ::isRequired() from within ::isStorageRequired().

If we want a field storage to be required, then we should explicitly request that by calling ::setStorageRequired(TRUE).

Remaining tasks

Review.

User interface changes

None.

API changes

BaseFieldDefinition::isStorageRequired() does not fall back to isRequired anymore.

If we want a field storage to be required, then we should explicitly request that by calling ::setStorageRequired(TRUE).

Data model changes

None.

Release notes snippet

Comments

hchonov created an issue. See original summary.

hchonov’s picture

StatusFileSize
new8.42 KB
hchonov’s picture

StatusFileSize
new12.52 KB
new2.73 KB

This patch removes the fallback to isRequired from within isStorageRequired.

In #2885809: The 'entity_type' and 'field_name' base fields on Comment are required the entity_type and field_name fields have been flagged as required, but not as storage required, which we should do not explicitly. However even if the fields have been flagged as required only, in the storage schema was checked if they are storage required before adding the NOT NULL constraint.

hchonov’s picture

Issue summary: View changes
hchonov’s picture

Issue summary: View changes
hchonov’s picture

StatusFileSize
new10.55 KB
new13.28 KB
new627 bytes

Adding a unit test to ensure that a required field is not automatically a storage required field.

hchonov’s picture

The last submitted patch, 2: 3083131-2-test-only.patch, failed testing. View results

hchonov’s picture

Issue summary: View changes

The last submitted patch, 6: 3083131-6-test-only.patch, failed testing. View results

hchonov’s picture

I've just created a change record - https://www.drupal.org/node/3083233 .

hchonov’s picture

Issue summary: View changes
darren oh’s picture

Status: Needs review » Reviewed & tested by the community

Patch looks good, tests pass, and fixes an annoying bug.

darren oh’s picture

tstoeckler’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs subsystem maintainer review

Sorry, but I would like to take a look at this first, so moving back to "needs review". In general I think the current fallback is correct and I'm not sure the I agree with problem description. It may be that the patch is in fact correct, but I would like to spend some time reviewing it first. That said it's fine for another Entity API maintainer to sign off as well, so not assigning to me but marking for subsystem maintainer review.

berdir’s picture

+++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
@@ -836,9 +836,7 @@ public function isStorageRequired() {
     if (isset($this->definition['storage_required'])) {
       return (bool) $this->definition['storage_required'];
     }
-
-    // Default to the 'required' property of the base field.
-    return $this->isRequired();
+    return FALSE;
   }

Yes, maybe this was problematic when done initially in 8.3 (IIRC).

But, changing it again now is just as problematic in the opposite direction, as evident by all the update functions and changes you have to do.

I still don't quite follow. The logic above this is an isset(), meaning you *can* set setRequiredStorage(FALSE) explicitly and then setRequired(TRUE)?

> If we clone a required base field and return it as non-required from an implementation of hook_entity_bundle_field_info() for a specific bundle, then we'll still not be able to save an entity for that bundle without providing a value for the overridden field as the storage might already be created with a NOT NULL constraint for that field.

As discussed, the storage-level settings are not *meant* to be changed per-bundle. But the above approach should work fine to override it per bundle?

hchonov’s picture

But, changing it again now is just as problematic in the opposite direction, as evident by all the update functions and changes you have to do.

Could you please elaborate on what you see as problematic? Btw it is only a single update and not multiple update functions.

As discussed, the storage-level settings are not *meant* to be changed per-bundle.

Required is not a storage level setting and it never was. The documentation of setRequired or isRequired also was never updated that they will result into database NOT NULL constraints. Only the documentation of isStorageRequired explains that.

The test explicitly doesn't touch the storage required flag but changes only the required flag. I've also written this in the issue summary that both have different meanings.

Once again from the issue summary:

So now we have 2 methods for whether a field is required - isRequired and isStorageRequired, where the first is used for form inputs and validation purposes, while the second is used to flag the storage of the field in a shared table as required - for example by adding the NOT NULL constraint to the schema as described in the method's documentation.

I see this as a regression and the test demonstrates it. It was possible to make a base field required in a form and for validation purposes on one bundle and non-required on another bundle, which is a perfectly valid use case and I hope others see it like this as well.
Now because of mixing storage with entity and form validation this makes it impossible and therefore it is clearly a regression and not only this but suddenly NOT NULL constraints will be added around without them being explicitly requested (assumed one has implemented storage schema like documented in core).

Please note that the issue and the test deal only with the required and not the storage required flag. I have no intentions of changing a storage setting and core should neither have any intentions of putting a NOT NULL in the database constraints only because I've made a field required for the form and for validation purposes. It should be up to the developer to decide.

But the above approach should work fine to override it per bundle?

As I am not sure if I understand this correctly, I would ask you to describe exactly what you mean, so that there is no confusion :)

hchonov’s picture

Issue tags: +Regression

I still don't quite follow. The logic above this is an isset(), meaning you *can* set setRequiredStorage(FALSE) explicitly and then setRequired(TRUE)?

I am sorry, I've missed that sentence.

It is currently possible to (quoting you) "set setRequiredStorage(FALSE) explicitly and then setRequired(TRUE)". However one should explicitly turn off the storage required and this should happen before the entity schema is installed, because afterwards it will not have any effect and the NOT NULL constraint will be already there.

Quoting @jibran from #3003586-3: [PP-4] Use setStorageRequired() instead of overriding the storage schema to mark fields as NOT NULL in the database:

This is a huge DX improvement IMO but to remeber 'not null' => TRUE to setStorageRequired(TRUE) is not stright forward.

I fully agree with that. Imagine now that it gets much more complicated to remember that ::setRequired(TRUE) leads to ::isStorageRequired() returning TRUE without having called setStorageRequired(TRUE). And on top of that one has to think of that ::setRequired(TRUE) leads to a NOT NULL constraint on the storage level? This is a pure DX nightmare and makes things much harder to fix in the aftermath.

jibran’s picture

I totally understand the edge case and the issue make sense but it is not a critical IMO. There is a clever way to get around this by using setRequiredStorage(FALSE) and then write an update function to update the storage.

BFD is always been a wired mixture of both field storage definition and field definition. Maybe #3014760: [PP-2] Create an abstract composite field definition/storage definition and update BaseFieldDefinition to use it will clear things up in the future.

Personally. I'm kind of indifferent about this issue and the reason behind that is when you say the base field is required what does it really mean?

Does it mean FieldDefinition is required or FieldStorageDefinition is required?
Right now we are making an assumption that if the base field is required then it means storage is required as well. If you don't want storage to be required then set it explicitly to FALSE via setRequiredStorage(FALSE). Maybe we need to document this better.

In #2390495-11: Support marking field storage definitions as required @Berdir said:

What if a base field wants to provide a similar behavior? Make it optionally required per-bundle but not do that on the storage level?

If a base field provider is making this decision that storage is not optional then it should set storage required explicitly instead of relying on field definition.

and then

But, changing it again now is just as problematic in the opposite direction, as evident by all the update functions and changes you have to do.

We are only fixing core here and leaving contrib and every other custom entity which is already using this as default behavior in limbo.

So yeah, I'm neither here nor there for this issue but I do agree with this setRequired and setStorageRequired dance is wired and difficult to understand.

hchonov’s picture

I'm kind of indifferent about this issue and the reason behind that is when you say the base field is required what does it really mean?

Does it mean FieldDefinition is required or FieldStorageDefinition is required?

It is really confusing now. However we have two methods for that - isRequired and isStorageRequired correspondingly.

BaseFieldDefinition and FieldConfig implement FieldDefinitionInterface on which isRequired() is documented:

Returns whether the field can be empty.

If a field is required, an entity needs to have at least a valid, non-empty item in that field's FieldItemList in order to pass validation.

This is what a required field / base field is and the main purpose is the validation.

Then we have RequiredFieldStorageDefinitionInterface which documents isStorageRequired() as

Returns whether the field storage is required.

If a field storage is required, NOT NULL constraints will be added automatically for the required properties of a field type.

RequiredFieldStorageDefinitionInterface is currently implemented only by BaseFieldDefinition.

I hope this clarifies the purpose of required and storage required and that as documented in the corresponding interfaces they have different purpose and therefore we should not implicitly fall back from the one to the other.

If a base field provider is making this decision that storage is not optional then it should set storage required explicitly instead of relying on field definition.

Exactly my point!

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

amateescu’s picture

Priority: Critical » Normal

The documentation for \Drupal\Core\Field\RequiredFieldStorageDefinitionInterface::isStorageRequired(), which contains the confusing part:

If a field storage is required, NOT NULL constraints will be added automatically for the required properties of a field type.

was written with the expectation that this issue would land shortly after it, in the same minor core release. Obviously that didn't happen, so that documentation is wrong at the moment in HEAD, which makes this more a documentation problem rather than a critical bug.

hchonov’s picture

so that documentation is wrong at the moment in HEAD, which makes this more a documentation problem rather than a critical bug.

Well the documentation isn't completely wrong because depending on the output of \Drupal\Core\Field\RequiredFieldStorageDefinitionInterface::isStorageRequired() NOT NULL constraints are already being added in HEAD.

Even if we automatically do this everywhere the current issue remains a real problem and not only a documentation issue. I've explained in the issue summary why I consider this critical.

hchonov’s picture

Issue summary: View changes

It is worth mentioning that regarding bundle fields only FieldConfig is aware of the required property and FieldStorageConfig does not know anything about it.

Only FieldConfigInterface extends the FieldDefinitionInterface where ::isRequired() is defined. The FieldStorageDefinitionInterface does not extend FieldDefinitionInterface.

This does not match BaseFieldDefinition where everything belongs together, but only on bundle fields we have a clear separation between what is a field definition setting and what is a field storage setting.

This issue is also a blocker for #3014760: [PP-2] Create an abstract composite field definition/storage definition and update BaseFieldDefinition to use it.
The proposal there is that the field storage definition is a property on the base field definition and as such it cannot call its parent from within ::isStorageRequired() and access ::isRequired().

hchonov’s picture

Issue summary: View changes
hchonov’s picture

StatusFileSize
new11.71 KB
new645 bytes

Status: Needs review » Needs work

The last submitted patch, 26: 3083131-26.patch, failed testing. View results

hchonov’s picture

Status: Needs work » Needs review
StatusFileSize
new1.16 KB
new13.08 KB

Looks like I forgot to add the schema file...

hchonov’s picture

Issue summary: View changes
mkalkbrenner’s picture

Status: Needs review » Reviewed & tested by the community

I read through the description and all the comments of the issue.
This comment expresses best the "WTF" that came into my mind:

I fully agree with that. Imagine now that it gets much more complicated to remember that ::setRequired(TRUE) leads to ::isStorageRequired() returning TRUE without having called setStorageRequired(TRUE). And on top of that one has to think of that ::setRequired(TRUE) leads to a NOT NULL constraint on the storage level? This is a pure DX nightmare and makes things much harder to fix in the aftermath.

Setting a field to be required in it's definition should not lead to have a NOT NULL constraint at the database level as default.
The default should be that the field exists in the database without a constraint if our API offers an explicit function setStorageRequired(TRUE) to request that constraint.

NOT NULL constraints should never be implicit, but explicitly requested by the developer or architect at some given point.

As a developer for example I don't want to be surprised by database exceptions if I change an application and declare a field to be required for the future. Or if I import existing entities and missing a required field but I want to ensure that it gets added on editing.

Again, adding the NOT NULL constraint at a given point should be an explicit decision. A developer should not be forced to have to suppress it actively. IMHO most contrib developers could deal better with "required" fields and the corresponding checks on higher layers like the form API or entity constraints compared to a database exception. If you get a NOT NULL constraint violation exception from the database layer it would be hard to find out which field caused it and why. And in most cases you want have a chance to deal with it in your business logic.

Therefore this issue and the suggested solution makes totally sense to me. And the tests show that core won't break.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

I don't think #16 has been accounted for. What about code that is relying on the current behaviour. We have code like that in HEAD atm that's why

+++ b/core/modules/comment/comment.install
@@ -260,3 +260,17 @@ function comment_update_8701() {
+/**
+ * Make the 'entity_type' and 'field_name' comment fields storage required.
+ */
+function comment_update_8901() {
+  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+  $field_definition = $definition_update_manager->getFieldStorageDefinition('entity_type', 'comment');
+  $field_definition->setStorageRequired(TRUE);
+  $definition_update_manager->updateFieldStorageDefinition($field_definition);
+
+  $field_definition = $definition_update_manager->getFieldStorageDefinition('field_name', 'comment');
+  $field_definition->setStorageRequired(TRUE);
+  $definition_update_manager->updateFieldStorageDefinition($field_definition);
+}

this update function.

I'm pretty uncomfortable with an change to entity storage that is going to necessitate contrib and custom writing update functions to ensure their expectations around data integrity are maintained. I'm going to ping @catch and @plach as core committers deeply involved in the entity system.

hchonov’s picture

I don't think #16 has been accounted for.

What exactly has not been addressed in my following comments #17 and #18?

I'm pretty uncomfortable with an change to entity storage that is going to necessitate contrib and custom writing update functions to ensure their expectations around data integrity are maintained. I'm going to ping @catch and @plach as core committers deeply involved in the entity system.

I don't think that anyone feels comfortable about this, but we should not forget that the change resolves the introduced regression and mitigates the adverse effects before we start providing NOT NULL constraints automatically for all entity types based on ::isStorageRequired().
We should think about developer reactions when they start receiving NOT NULL constraints in the storage just because they've flagged their fields required for entity and form validation. Or even worse, when they realize that it is impossible to save an entity form for a bundle where the requirement has been disabled.
I think that all this is much more important than the currently proposed change.

Additionally it also prevents a clear separation that is planned in #3014760: [PP-2] Create an abstract composite field definition/storage definition and update BaseFieldDefinition to use it.

hchonov’s picture

The only explanation about the fallback from #2390495-11: Support marking field storage definitions as required is :

What if we make this a new optional interface, with a different method name (isSToragRequired()?). We can implement this in BaseFieldDefinition and actually call isRequired() by default, then someone who needs to do something weird can override it.

Which is not explaining the reason for the fallback in the first place.

In the very same comment you read the following as well, which has not been accounted for with the introduction of the fallback:

For configurable fields, it is now normal for the storage to not be required but the field definition/field config can be required.

What if a base field wants to provide a similar behavior? Make it optionally required per-bundle but not do that on the storage level?

This makes me think that it might have been just an oversight adding the fallback.

darren oh’s picture

I understand that unexpectedly impacting an important site would have a negative effect on future support for Drupal. However, this does appear to have been an unintended behavior that has negative consequences. Is there a way we can deprecate and warn developers who depend on this behavior that they should update before the next release?

hchonov’s picture

Is there a way we can deprecate and warn developers who depend on this behavior that they should update before the next release?

We could trigger a deprecation if the fallback returns TRUE, however how many releases from now should go on with this regression?

I would be fine with deprecating it in 8.8.x, but remove it in 8.9.0 where hopefully the automatic NOT NULL handling will be added.

mkalkbrenner’s picture

... warn developers who depend on this behavior that they should update before the next release?

I bet that there's not a single developer out there in contrib who explicitly set a field to be required using its defentition in order to get a NOT NULL constraint at the database level!
If the constraint won't be there, the code will still work like expected due to the checks on the PHP level.

If we should warn someone, we should warn developers that they might have created NOT NULL constraints by accident.

We could also tell them to revise their database constraints ;-)
But we must not declare this bug(!) as a feature instead of fixing it.

catch’s picture

OK a couple of ideas, I'm not sure what the best course of action is:

It's arguable both ways whether this is a pure bug fix or also includes an API change. I do think we can change the behaviour in 9.0.x to what's in the current patch.

For 8.x there are three options I think:

1. Just make the change, with a change record

2. Deprecate the old behaviour with @trigger_error() (might be able to squeeze that into 8.8.x).

3. Make the change, but trigger_error() if we hit the fallback to alert developers who might be relying on it (an actual notice/warning, no @)

I think #2 is the only approach that could really go into a patch release at all, #1 and #3 we might want to move to an 8.9.x follow-up then to get this fixed in 9.0.x and something into 8.8/8.9 first?

hchonov’s picture

If we deprecate it in 8.8.x then can we remove it in 8.9.x with a change record?

#2841291: Fix NOT NULL handling in the entity storage and 'primary key' changes when updating the storage definition of an identifier field is ready (depends only one other issue which is RTBC) and hopefully can be committed to 8.9.x, however the current issue is a blocker for it as if someone decides to use the new schema they will get NOT NULL constraints unnoticed.

---

I could propose one more solution which might make it easier to commit earlier - next to the deprecation in 8.8.x, write an update that explicitly sets the storage_required flag to TRUE in the installed storage definitions if it has a NOT NULL constraint in the field schema for all tables it is contained in. This will ensure that the flag is kept on the installed storage definition in the cases someone relied on the fallback to ::isRequired(). During the update we could notify through a log message. We could even add a special detection for this in the EntityDefinitionUpdateManager::getChangeList(). This way only new installations will be affected, but not existing ones. Actually even without this existing ones will not be affected as they've already got the NOT NULL constraint in their databases if they relied on ::isStorageRequired().

---

I would therefore propose something like this.

Add the deprecation in 8.8.x if ::isStorageRequired() falls back to ::isRequired() and returns TRUE.
In 8.9.x remove the fallback and through an update set explicitly the storage_required flag to TRUE in the installed field storage definitions for required (::isRequired()) fields which had a NOT NULL constraints in their installed field schema and write a log message for each updated field. For this we should exclude the entity keys which by default get a NOT NULL constraint. Prior the release of 8.9.0 publish a change record about the change.
Additionally add a special detection for storage_required change in base fields in the EntityDefinitionUpdateManager::getChangeList(), which will be useful anyway.

hchonov’s picture

Actually we could detect even better if a NOT NULL constraint is being added because of a fallback to ::isRequired() in ::isStorageRequired():

1. Retrieve all non entity key fields for which ::isStorageRequired() returns TRUE, but haven't being explicitly set as storage required.
2. Intersect those fields with the ones that have a NOT NULL constraint in at least one table in their installed field schema.
3. Retrieve a clone of the original field storage definitions for those fields and turn off the storage requirement - ->setStorageRequired(FALSE).
4. Retrieve the current field schema for the modified storage definition.
5. If a NOT NULL constraint is not added anymore then the fallback was used and we should explicitly update the installed storage definition with ->setStorageRequired(TRUE).

If a NOT NULL constraint is still added then this happens based on some other condition like the field name for example and there is nothing to do.

------
Edit:

I've proposed this as the most safe way, however given the fact that nothing really will break for existing site installations I don't think that such an update is justified.

New installations will simply not get the NOT NULL constraint in the database, but will still work

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new144 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.