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

Fix "does not exists" in comments and test error messages

$
0
0

There are several instances of the same error throughout core where it says "does not exists" instead of "does not exist".


EntityResource should add _entity_access requirement to REST routes

$
0
0

Problem/Motivation

Currently EntityResource manually checks entity access e.g. in get() etc.

Proposed resolution

Instead it could override getBaseRouteRequirements() to add appropriate _entity_access requirements to the routes.

Add the label of the entity type to the error message when there are outstanding entity changes in UpdatePathTestBase

$
0
0

Problem/Motivation

When a UpdatePathTestBase-based test fails because there is an outstanding change to a field definition of an entity type it fails with an error message that doesn't contain the entity type, for example:

The Published field needs to be updated.

This is not super helpful.

Proposed resolution

Add the entity type label to the error message:

Custom block: The Published field needs to be updated.

datetime date views filter: DateTime object not set

$
0
0

Problem/Motivation

Using datetime views filter and filtering with an invalid date, there is no validation and fatal error occured.

To reproduce:

  • Add a datetime field in an entity bundle.
  • Create a view to list this entities and add a filter on this datetime field
  • Search for a date with wrong format or for example day in french: lun 2018-04-27. The following error occur:
    <em class="placeholder">Exception</em>: DateTime object not set. in <em class="placeholder">Drupal\Component\Datetime\DateTimePlus-&gt;__call()</em> (line <em class="placeholder">355</em> of <em class="placeholder">core/lib/Drupal/Component/Datetime/DateTimePlus.php</em>). <pre class="backtrace">Drupal\datetime\Plugin\views\filter\Date-&gt;opSimple(&#039;sesame_quota_option__field_sesame_opt_date.field_sesame_opt_date_value&#039;) (Line: 314)
    Drupal\views\Plugin\views\filter\NumericFilter-&gt;query() (Line: 1370)
    Drupal\views\ViewExecutable-&gt;_build(&#039;filter&#039;) (Line: 1259)
    Drupal\views\ViewExecutable-&gt;build() (Line: 390)
    Drupal\views\Plugin\views\display\PathPluginBase-&gt;execute() (Line: 180)
    Drupal\views\Plugin\views\display\Page-&gt;execute() (Line: 1627)
    Drupal\views\ViewExecutable-&gt;executeDisplay(&#039;page_1&#039;, Array) (Line: 77)
    Drupal\views\Element\View::preRenderViewElement(Array)
    call_user_func(Array, Array) (Line: 378)
    Drupal\Core\Render\Renderer-&gt;doRender(Array, ) (Line: 195)
    Drupal\Core\Render\Renderer-&gt;render(Array, ) (Line: 226)
    Drupal\Core\Render\MainContent\HtmlRenderer-&gt;Drupal\Core\Render\MainContent\{closure}() (Line: 582)
    Drupal\Core\Render\Renderer-&gt;executeInRenderContext(Object, Object) (Line: 227)
    Drupal\Core\Render\MainContent\HtmlRenderer-&gt;prepare(Array, Object, Object) (Line: 117)
    Drupal\Core\Render\MainContent\HtmlRenderer-&gt;renderResponse(Array, Object, Object) (Line: 90)
    Drupal\Core\EventSubscriber\MainContentViewSubscriber-&gt;onViewRenderArray(Object, &#039;kernel.view&#039;, Object) (Line: 76)
    Drupal\webprofiler\EventDispatcher\TraceableEventDispatcher-&gt;dispatch(&#039;kernel.view&#039;, Object) (Line: 156)
    Symfony\Component\HttpKernel\HttpKernel-&gt;handleRaw(Object, 1) (Line: 68)
    Symfony\Component\HttpKernel\HttpKernel-&gt;handle(Object, 1, 1) (Line: 57)
    Drupal\Core\StackMiddleware\Session-&gt;handle(Object, 1, 1) (Line: 47)
    Drupal\Core\StackMiddleware\KernelPreHandle-&gt;handle(Object, 1, 1) (Line: 99)
    Drupal\page_cache\StackMiddleware\PageCache-&gt;pass(Object, 1, 1) (Line: 78)
    Drupal\page_cache\StackMiddleware\PageCache-&gt;handle(Object, 1, 1) (Line: 47)
    Drupal\Core\StackMiddleware\ReverseProxyMiddleware-&gt;handle(Object, 1, 1) (Line: 38)
    Drupal\webprofiler\StackMiddleware\WebprofilerMiddleware-&gt;handle(Object, 1, 1) (Line: 50)
    Drupal\Core\StackMiddleware\NegotiationMiddleware-&gt;handle(Object, 1, 1) (Line: 23)
    Stack\StackedHttpKernel-&gt;handle(Object, 1, 1) (Line: 664)
    Drupal\Core\DrupalKernel-&gt;handle(Object) (Line: 19)
  • Search for the same date with day in english works: mon 2018-04-27. Same for date only: 2018-04-27

Proposed resolution

Mimic the date filter validation from views module.

Remaining tasks

  1. Add tests
  2. Review

UI for publishing/unpublishing block_content blocks

$
0
0

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

API changes

None.

Data model changes

None.

After 8.5.0 upgrade: Unknown column revision.revision_default

$
0
0

Hey folks. Any idea on where to start looking to debug the following? I'm getting this on one of my sites after the 8.5.0 upgrade. I tried disabling all my contrib modules, yet this error still persists.

[Thu Mar 08 09:41:03.880667 2018] [:error] [pid 22584] [client 69.162.124.237:24151] Uncaught PHP Exception Drupal\\Core\\Database\\DatabaseExceptionWrapper: "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'revision.revision_default' in 'field list': SELECT revision.revision_id AS revision_id, revision.langcode AS langcode, revision.revision_user AS revision_user, revision.revision_created AS revision_created, revision.revision_log AS revision_log, revision.revision_default AS revision_default, base.id AS id, base.type AS type, base.uuid AS uuid, CASE base.revision_id WHEN revision.revision_id THEN 1 ELSE 0 END AS isDefaultRevision\nFROM \n{block_content} base\nINNER JOIN {block_content_revision} revision ON revision.revision_id = base.revision_id; Array\n(\n)\n" at /var/www/drupal8/www.MYSITE.com/public_html/core/lib/Drupal/Core/Database/Connection.php line 686, referer: http://www.MYSITE.com/

Update block library page to adapt publishable block content implementation

$
0
0

Problem/Motivation

Custom blocks are now publishable, but the Custom block library page (/admin/structure/block/block-content) doesn't not reflect this change. Since the custom blocks as publish-able, make the UI close to node admin page (/admin/content):

This work was started In #2834546: UI for publishing/unpublishing block_content blocks, but it was decided to split the changes to block_content view and related into a follow up issue, because this requires an upgrade path.#2834546: UI for publishing/unpublishing block_content blocks should be committed before this issue gets in.

Proposed resolution

Introduce below changes:
1. Bulk operation form
2. Add published column
3. Add publish status filter

and write the upgrade path in this issue.

Remaining tasks

- Implementation - Done
- Manual testing - Done
- More reviews
- Commit!

User interface changes

Adds a bulk publish / unpublish actions and a new "published" column to the Custom block library page /admin/structure/block/block-content

API changes

None

Data model changes

None

Convey AJAX progress messages to assistive technology.

$
0
0

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.


Follow-up for #2910211: fix all deprecation warnings

$
0
0

Problem/Motivation

Since #2910211: Allow computed exposed properties in ComplexData to support cacheability., implicit cacheability bubbling is deprecated, because there now finally is a way for normalizers to bubble cacheability metadata of the data they're normalizing.

As of #2870194: Ensure that process-isolated tests can use Symfony's PHPunit bridge to catch usages of deprecated code, deprecation errors result in test failures. But any deprecation errors that result in core test failures are ignored, for now.

Proposed resolution

Let's fix all deprecation errors for the deprecation that #2910211 added. This is then also fixing REST/Serialization technical debt. That deprecation is:

Implicit cacheability metadata bubbling (onto the global render context) in normalizers is deprecated since Drupal 8.5.0 and will be removed in Drupal 9.0.0. Use the "cacheability" serialization context instead, for explicit cacheability metadata bubbling. See https://www.drupal.org/node/2918937

Remaining tasks

  1. Find all the places.
  2. Fix them.

User interface changes

None.

API changes

None.

Data model changes

None.

EntityViewsData assumes BaseFieldDefinitions where it should use FieldDefinitionInterface

$
0
0

Problem/Motivation

EntityViewsData has the following code around line 252:

    // Load all typed data definitions of all fields. This should cover each of
    // the entity base, revision, data tables.
    $field_definitions = $this->entityManager->getBaseFieldDefinitions($this->entityType->id());
    /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
    if ($table_mapping = $this->storage->getTableMapping($field_definitions)) {

The problem is that it asks for FieldDefinitionInterface[] and immediately treats it as FieldStorageDefinitionInterface[] by calling $this->storage->getTableMapping() which expects the latter. Further down the code it correctly treats the retrieved data as FDI[] when it calls $this->mapFieldDefinition().

So why is this a problem? Because it is only working by happy accident. We know that we are getting BaseFieldDefinition objects, which we know implement both FDI and FSDI. The problem becomes clear when we try to patch EntityViewsData to actually take care of bundle fields as well, as demonstrated in #2898635: bundleFieldDefinitions() are not added in EntityViewsData

Consider the following code be inserted right after the setting of $field_definitions:

// Add any bundle fields defined in code.
if (isset($this->entityType->getKeys()['bundle'])) {
  $bundle_field_definitions = [];
  foreach ($this->entityManager->getBundleInfo($this->entityType->id()) as $bundle_id => $bundle_info) {
    $bundle_field_definitions += $this->entityManager->getFieldDefinitions($this->entityType->id(), $bundle_id);
  }
  $field_definitions += $bundle_field_definitions;
}

Now we might get BaseFieldDefinitions from the above, but we could also get FieldConfig items. Which is perfectly fine because both getFieldDefinitions() and getBaseFieldDefinitions() should return FDI[] and then be treated as such. Except, because we treat the returned data as both FDI[] and FSDI[], the above addition will lead to a crash because FieldConfig (among others) does not implement FSDI.

Proposed resolution

Properly treat the base field definitions as FDI[] only and rewrite EntityViewsData to properly retrieve the FSDI when needed.

Remaining tasks

  • Write a patch
  • Figure out whether this breaks BC

API changes

None, unless we have to change function signatures to ask for the right interface.

Data model changes

None.

Issue priority explanation

Marked as major because it is both a massive code smell and it blocks a useful patch that would allow bundle fields to show up in views.

Clean up superfluous use of "additional_base_field_definitions" in the entity_test module

$
0
0

Problem/Motivation

In some of the test entity types in the entity_test module additional base fields are loaded from state. This allows us to dynamically define base fields in the test environment.

In #2961986: The ContentEntityBase entity key cache is purged incorrectly when two keys exist for one field., we added this capability to EntityTest like so:

  return $fields + \Drupal::state()->get($entity_type->id() . '.additional_base_field_definitions', []);

We are now able to clear up all sub-classes of EntityTest that also merge in these fields from state.

Proposed resolution

Remove instances of \Drupal::state()->get($entity_type->id() . '.additional_base_field_definitions', []); from the following test entity classes:

  • \Drupal\entity_test\Entity\EntityTestMul
  • \Drupal\entity_test\Entity\EntityTestMulRev
  • \Drupal\entity_test\Entity\EntityTestRev

Remaining tasks

Write and review a patch.

User interface changes

None.

API changes

None.

Data model changes

None.

[PP-1] Fix NOT NULL handling in the entity storage and 'primary key' changes when updating the storage definition of an identifier field

$
0
0

Problem/Motivation

Currently, only a few entity keys are automatically marked as NOT NULL, which is a problem because it gives the impression that entity keys are somehow special and leads to bugs like #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior.

Also, developers have to know about this limitation of entity API and override \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::getSharedTableFieldSchema() in order to mark fields as NOT NULL.

An additional (major) problem found is that when we are updating the storage definition of an identifier field (e.g. 'id' or 'revision_id'), the primary keys are not updated properly in the SQL schema.

This patch also uncovered a another bug:

- The entity storage schema stores incorrect field schema data for the identifier fields: both the 'id' and 'revision_id' fields are of type int in their base tables, when they should be serial instead

Proposed resolution

Since we can now mark field storages as required (#2390495: Support marking field storage definitions as required) we can also add the NOT NULL database constraint automatically. This will also improve the performance of indexes that are using those required fields.

Pass the new 'primary key' definition when re-adding the identifier field in \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::createSharedTableSchema().

Fix the field storage schema data for the identifier fields for all entity types.

Remaining tasks

Review.

User interface changes

Nope.

API changes

Nope.

Data model changes

Nope.

Deprecate system_rebuild_module_data() and remove usages in core

$
0
0

Problem/Motivation

#2208429: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList makes it possible to deprecate system_rebuild_module_data() and replace it with calls to \Drupal::service('extension.list.module')->reset()

Proposed resolution

Replace all usages and deprecate system_rebuild_module_data() and trigger a silenced error. Also, when replacing the usages we should ensure that we don't unnecessarily rebuild the module list.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Uploaded files are impossible to replace

$
0
0

Problem/Motivation

(/admin/content/files allows only to browse the files.

There seems to be no way in Drupal to overwrite a file, and keeping the same filename.

Deleting the file and replacing it with a new version while retaining the same filename does not work, as the new version would automatically get a prefix ("_0") attached to it each time a new version is uploaded (for example: "filename_0.pdf"; "filename_1.pdf", etc.).

"/admin/content/file/fiiename.pdf" seems to allow the file to be replaced when it is saved, but it still does not automatically replace it with the new version.

Proposed resolution

It should be possible to overwrite a file and keeping the same filename.

Original report by [dupal.user]

(There seems to be no way in Drupal 8 to to manually delete a file, other than waiting for some automatic cleanup of orphaned files.

Primitive solution: /admin/content/files may allow deleting files just as /admin/content allows deleting content.

Better solution: It should be possible to choose between deleting or unlinking previously uploaded file field attachments when editing a node.

Deleting is required in order to replace a file with a new version.)

Ajax is broken in forms built within an Ajax callback

$
0
0

This could be a bug, or it could be working as designed and my methodology is wrong.

Summary:
I have a form with a checkbox. The checkbox has an ajax callback. The ajax callback prepares a separate second form, and opens it in a modal. The problem is the second form's ajax is broken.

Here is a basic setup:

First Form buildForm:

public function buildForm(array $form, FormStateInterface $form_state) {
    $form['my_checkbox'] = array(
      '#type' => 'checkbox',
      '#title' => 'my checkbox',
      '#ajax' => array(
        'callback' => array($this, 'clickMyCheckbox'),
        'event' => 'change',
        'progress' => 'throbber',
      ),
    );
    return $form;
  }

First Form "clickMyCheckbox" AJAX Callback:

public static function clickMyCheckbox(array &$form, FormStateInterface $form_state) {
    $second_form = \Drupal::formBuilder()->getForm('Drupal\my_project\Form\SecondForm');
    $response = new AjaxResponse();
    $response->addCommand(new OpenModalDialogCommand('Second Form', $second_form, array('width' => '600')));
    return $response;
}

Second Form buildForm:

public function buildForm(array $form, FormStateInterface $form_state) {
    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
    $form['my_actions'] = array('#type' => 'actions');
    $form['my_actions']['cancel'] = array(
      '#type' => 'button',
      '#value' => t('Cancel'),
      '#ajax' => array(
        'callback' => array($this, 'cancelForm'),
        'event' => 'click',
        'progress' => FALSE,
      ),
    );
    $form['my_actions']['submit'] = array(
      '#type' => 'button',
      '#value' => t('Confirm'),
      '#ajax' => array(
        'callback' => array($this, 'submitForm'),
        'event' => 'click',
        'progress' => FALSE,
      ),
    );
    return $form;
  }

Second Form "cancelForm" AJAX Callback:

public function cancelForm(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response->addCommand(new CloseModalDialogCommand());
    return $response;
  }

In the above example, clicking the checkbox opens the second form in a modal, however, the Cancel button doesn't close the modal; none of the AJAX works.

From what I can tell working with this issue, it seems the second form is built using data from and being wrapped in the first form, instead of being a standalone form. The ajaxTrustedUrl being passed also includes the _wrapper_format=html query, when it should be ajax. If I build the second form on its own, the AJAX works, so I know it has to be due to building the form in the AJAX callback for another form.

Am I going about this the correct way? Is there a way to unset/reset these settings when building the second form? I've found two issues which appear to be somewhat related:

https://www.drupal.org/project/drupal/issues/2504709
https://www.drupal.org/project/drupal/issues/2504115


AJAX forms should submit to $form['#action'] instead of <current>

$
0
0

Follow-up to #2263569: Bypass form caching by default for forms using #ajax..

There, in RenderElement::preRenderAjaxForm() we changed the default URL of an AJAX submission from Url::fromRoute('system.ajax') to Url::fromRoute('<current>'). Most of the time, this is the same as $form['#action'], but not always. For example, comment forms sometimes set the action to a separate page.

For the cases where the action is not the current page, let's discuss which one AJAX should submit to, and then add docs and test coverage for that. In most cases, since the AJAX response is built solely out of what's in $form and $form_state at the end of form processing, which route we submit to probably doesn't result in any difference, if both the current route and action route end up calling $form_builder->buildForm() with the same arguments, and if there aren't alter hooks that modify differently based on the route. But, since it is possible to write routes and alter implementations that result in differences, we should take a stance here.

Reasons for AJAX to submit to $form['#action']:

  • All #ajax elements fall back to submitting to the form action when JS is disabled, so this would bring more consistency for what server-side form processing code runs, regardless of whether JS is enabled in the browser.

Reasons for AJAX to submit to the current page:

  • The purpose of the AJAX response is to update the current page, so shouldn't it do so with content meant for that page? When JS is disabled, an entire new page is returned, so it matters less whether that's the same or different than the current one.

Allow users to translate content they can edit

$
0
0

Problem/Motivation

#253157: Add "Translate own content" permission, rename "Translate content" to "Translate all content" was committed in earlier versions of Drupal 8 which allowed users to translate their own content. However, this feature was later removed from the core and it made https://www.drupal.org/node/1776752 obsolete.

Nowadays, multilingual community sites still have a requirement to allow users to translate their own content.

Proposed resolution

Based on @Berdir's feedback:

Options are:

  • New permissions: "translate own entities", "translate own {entity_type}", "translate own {bundle} {entity_type}"
  • Single global permission: "allow translating content that the user can edit"

Remaining tasks

Discuss.

User interface changes

API changes

Data model changes

Ajax form submit from entity page causes full entity rendering

$
0
0

Problem/Motivation

When send any ajax form request, you need only form response, but actually request calls some route and it's controller renders page content. And only after rendering of content Drupal "understands", that it is ajax-form request, and starts to process form. This is very big penalty for performance, because this big render array from controller will never used anywhere and will not included in ajax-response.

Way to reproduce this

1. Just place any AJAX-form in block and render this block at entity page.
2. Place XDebug breakpoint at 'core/lib/Drupal/Core/Entity/Controller/EntityViewController.php' at line 94 (first line of view() method).
3. Submit ajax form.
4. Step over each line in view() method, and you will see, that whole entity was rendered.

Proposed resolution

Check AJAX-specific headers in controllers to prevent this unnecessary rendering. I tried to do this in controllers of my custom modules and it works good.

Allow both AJAX and non-AJAX forms to POST to dedicated URLs

$
0
0

This is the successor of #2367555: Deprecate EnforcedResponseException support, which is the issue that several @todos in Drupal core are referring to.

Follow-up to #2263569: Bypass form caching by default for forms using #ajax.

Problem/Motivation

In #2263569: Bypass form caching by default for forms using #ajax. forms have been setup to POST ajax requests to their original paths instead of system/ajax.

The form is then 'searched for' on the page during the rendering pipeline and once found an Exception is thrown, the rendering aborted and the ajax callback called.

The reason _why_ a form needs to be searched is that the form is displayed in context of a block, a controller or whatever.

e.g

// deep down somewhere in the code

$some_form = new SomeForm();

$build['my_form'] = $this->formBuilder->getForm($some_form);

As long as $some_form defines FormInterface and has appropriate getFormId(), buildForm(), validateForm() and submitForm() options that works.

However what now happens is that someone does:

// deep down somewhere in the code

$some_form = new SomeForm($some_entity, $some_service_to_use);

$build['my_form'] = $this->formBuilder->getForm($some_form);

that means that SomeForm can hold _state_, which is similar to the default parameters provided in Drupal 7. (drupal_get_form('form_id', $some_value, $some_entity, ...))

But what is worse is that SomeForm also might depend on FormState containing some of that external state and then it gets difficult.

Also consider this form living in a block plugin somewhere in the code base.

Proposed resolution

"Interfaces are the answer to the life, the universe and everything." (or was that 42?)

Add a new IndependentFormInterface / ReconstructableFormInterface / LazyBuilderInterface ...

and provide the means for the form to re-create itself.

e.g.

class ReconstructibleSomeForm extends SomeForm implements LazyBuilderInterface {

  public static function lazyBuild(ContainerInterface $container, $entity_type, $entity_id) {
     $entity = Entity::load($entity_type, $entity_id);
     return new static(
        $entity,
        $container->get('some_service'),
     );
  }

  public function getLazyBuilderArguments() {
     return [ $this->entity->entityType(), $this->entity->id() ]; // Must only be scalar values or null.
  }
}

When the form builder encounters a form implementing that interface AND this is a GET request, then it calls the getReconstructContext() method, ensures it only contains scalar values (very similar to #lazy_builder's) and creates the following render array:


$key = NULL;

if ($form instanceof LazyBuilderInterface) {
  $args = $form->getLazyBuilderArguments();

  // Put real callback to the start of the arguments.
  array_unshift($args, get_class($form) . '::lazyBuild');

  $fast_path_renderable = [
    '#lazy_builder' => [ 'lazy_form_builder:buildForm', $args ],
  ];

  $key = 'lazy_form_builder_' . hash('sha1', serialize($fast_path_renderable));

  // Same as we fixed the autocomplete issue ...
  if (!$this->keyValue->get($key)) {
    $this->keyValue->set($key, $fast_path_renderable);
  }
}

if ($key) {
  // Set the _form_ajax GET argument to $key.
}

Then in onController (pseudo-code):

if (isset($_GET['_form_ajax']) && $_GET['_form_ajax'] != 1) {
  $fast_path_renderable = $this->keyValue->get($_GET['_form_ajax']);
  $controller = 'lazy_builder_controller:execute';
  $arguments = $fast_path_renderable;
}

Then in LazyBuilderController:


class LazyBuilderController extends Controller {

  public function __construct(Renderer $renderer) {
    $this->renderer = $renderer;
  }

  public function execute($fast_path_renderable) {
     return $this->renderer->render($fast_path_renderable);
  }
}

class LazyFormBuilder {

  public function buildForm() {
     $args = func_get_args();
     $executable = array_shift($args);
     $form = call_user_func_array($executable, $args);
     return $this->formBuilder->getForm($form);
  }
}

Note: This is idealized from what I plan for ESI (as its the exact same mechanism), so for this issue _could_ e.g. combine LazyFormBuilder and LazyBuilderController.

The idea however remains the same.

Remaining tasks

- Discuss
- Do it

User interface changes

- None

API changes

- New Interface

Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON API

$
0
0

Problem/Motivation

#2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX fixed the normalization of "Time fields" aka the TimestampItem. But it did so by adding a normalizer for the @FieldType level. It could have been implemented just as well at the @DataType level, but this simply didn't cross anybody's mind AFAICT. At least it wasn't discussed on the issue. (And I was very active on it too, so my bad!)

IOW: not a normalizer with

use Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem;
…
protected $supportedInterfaceOrClass = TimestampItem::class;

but with

\Drupal\Core\TypedData\Plugin\DataType\Timestamp
…
protected $supportedInterfaceOrClass = Timestamp::class;

The benefit is that the normalizers are then no longer format-specific: we'll need only one and it'll work for both the default normalization (serialization module: json + xml formats) and the HAL normalization (hal module: hal_json format). But also for contrib's jsonapi normalization/format!

Note: this will also fix #2870609: [PP-1] Core Date field is serialized as String instead of timestamp/long.

Proposed resolution

  1. Add serializer.normalizer.timestamp
  2. Add \Drupal\serialization\Normalizer\TimestampNormalizer
  3. Deprecate \Drupal\serialization\Normalizer\TimestampItemNormalizer
  4. Deprecate \Drupal\serialization\Normalizer\TimeStampItemNormalizerTrait
  5. Deprecate \Drupal\hal\Normalizer\TimestampItemNormalizer
  6. Deprecate serializer.normalizer.timestamp_item
  7. Deprecate serializer.normalizer.timestamp_item.hal

See #72 for a clear overview of the patch.

Remaining tasks

None.

User interface changes

None.

API changes

  1. @FieldType=timestamp: no changes!
  2. @FieldType=datetime fields configured to store date + time:
    Before
    '2017-03-01T20:02:00'

    Note: timezone information is absent!

    After
    '2017-03-01T20:02:00+11:00'

    Note: the site's timezone is present! This is now a valid RFC3339

  3. @FieldType=datetime fields configured to store date only:
    Before
    '2017-03-01T20:02:00'

    Note: time information is present despite this being a date-only field!

    After
    '2017-03-01'

    RFC3339 only covers combined date and time representations. For date-only representations, we need to use ISO 8601. There isn't a particular name for this date-only format, so we have to hardcode the format. See https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates.

Data model changes

None.

Viewing all 291491 articles
Browse latest View live


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