Account created on 20 July 2009, over 15 years ago
#

Merge Requests

More

Recent comments

🇷🇺Russia Chi

We might need to update this method in LocalReadOnlyStream as well.

🇷🇺Russia Chi

Do we really need to check the operation ourselves?

Well, that actually was already noted many years ago.
https://www.drupal.org/project/drupal/issues/1308054#comment-6772280

🇷🇺Russia Chi

Facing same issue when trying to acquire non-blocking lock.

Change unrecognized operations in LocalStream::stream_lock() to return FALSE;

Do we really need to check the operation ourselves? flock will return the correct error message if the operation is not permitted.

> \flock(\fopen('/tmp/test', 'wb'), LOCK_NB);

   ValueError  flock(): Argument #2 ($operation) must be one of LOCK_SH, LOCK_EX, or LOCK_UN.
🇷🇺Russia Chi

Re: #18

This snippet works for me.

try {
  $lock_exists = (bool) $this->database
    ->select('semaphore')
    ->condition('name', $name)
    ->countQuery()
    ->execute()
    ->fetchField();
  if (!$lock_exists) {
    $this->database->insert('semaphore')
      ->fields([
        'name' => $name,
        'value' => $this->getLockId(),
        'expire' => $expire,
      ])
      ->execute();
  }
}
finally {
  unset($transaction);
}

Overall, I think the default lock implementation should use flock backend instead of database.

🇷🇺Russia Chi

This needs to be fixed in 4.x branch first.

🇷🇺Russia Chi

@niklan That patch prints absolute paths to the HTML files, not URLs.

🇷🇺Russia Chi

I think it needs a more generic follow-up not focused only on Symfony Form component. Something like "Modernize Drupal Form API".

🇷🇺Russia Chi

Right. That note was mostly for custom projects that override cache backends like follows.

$settings['cache']['bins']['bootstrap'] = 'cache.backend.apcu';
$settings['cache']['bins']['config'] = 'cache.backend.apcu';
$settings['cache']['bins']['container'] = 'cache.backend.apcu';
$settings['cache']['bins']['discovery'] = 'cache.backend.apcu';
$settings['cache']['bins']['menu'] = 'cache.backend.apcu';
$settings['cache']['bins']['toolbar'] = 'cache.backend.apcu';
🇷🇺Russia Chi

It worth noting that prewarming data cached in APCu backend does not make mush sense.

🇷🇺Russia Chi

The patch may cause BC break on existing sites. However, I think it is acceptable in RC.

🇷🇺Russia Chi

Actually #3 is wrong. The snippet in issue summary looks correct.
As of feature request I don't think it worth implementing. It looks more clear when checking for emptiness expensively. Function like drupal_view_if_not_empty() would look wierd.

🇷🇺Russia Chi

It looks good. If the problem is only about rendering empty HTML markup you can also consider using CSS has selector to hide it.

🇷🇺Russia Chi

but even when the View is empty, it contains empty HTML elements

That's a known issue in Drupal theming system.

🇷🇺Russia Chi

Re #20. Turns out all implementations in Drupal core use void instead of null. Given, can only be used as a standalone type we have to update them. Otherwise we will never be able to add native return type hint to this hook. I agree, that needs to be done in a follow-up.

🇷🇺Russia Chi

It doesn't return anything if the if condition is not met (void).

Right. Needs to be fixed.

I think we should add a :?array|int

Union types and the nullable type notation cannot be mixed. Anyway, as this issue is about @return tag I propose we don't add the typehint here. This is managed in other issue. 📌 [META] Add return types to hook implementations Active .

🇷🇺Russia Chi

Re #9.
The documentation for the @return tag consists of two parts: the type hint and a free-form description. I believe the issue is that they contradict each other.

🇷🇺Russia Chi

I wonder if we can explicitly document -1 in return type. PHPStan allows specifying scalar values as types in PHPDocs.

https://phpstan.org/writing-php-code/phpdoc-types#literals-and-constants

🇷🇺Russia Chi

This is still relevant.

Can you clarify why? The issue summary points to Drupal 7 lock implementation. If it's still relevant can you describe remaining tasks that need to be done?

🇷🇺Russia Chi

Possible solution is execution SELECT query before the INSERT in the same transaction. Though it may behave differently depending on configured transaction isolation level.

We can also consider using some third party lock implementation, for instance symfony/lock.

🇷🇺Russia Chi

Re #7 Writing a test requires concurrent requests and reading PostgreSQL log. That's not what Drupal testing system is capable of. To reproduce the issue manually you can run simultaneously a couple CLI scripts which acquire a lock with the same ID.
The root reason of this error is explained well in #14.

🇷🇺Russia Chi

Wonder if we could go with LFU cache instead. Will the implementation be more complex?

🇷🇺Russia Chi

PHPStan currently does not have a rule for checking less specific return types. Psalm does.
I'v just created a feature request for PHPStan project.
https://github.com/phpstan/phpstan/issues/12442

🇷🇺Russia Chi

I think that because Boolean is the data type, not false or true. https://www.php.net/manual/en/language.types.php.

@quietone true and false are covered there in value types section.

🇷🇺Russia Chi

Re #36. That's correct. And if we should probably emit some notice when assertions are in production mode when running tests.

🇷🇺Russia Chi

The logic for loading default image is in the image formatter. You may invoke it like follows node.field_image|view.
However, if you only need a raw image URI you have to use preprocess hook to fetch default image from field storage settings.

🇷🇺Russia Chi

I also concerned about how to find the instances that this is suggesting be changed. A simple grep will not work.

Instances found with grep needs to be filtered manually by comment referring to false.
Like this.

The new temporary filename, or FALSE on failure.

🇷🇺Russia Chi

I checked core code. Found 162 occurrences of false in PHPDoc tags. FALSE is not used at all.

🇷🇺Russia Chi

@quietone Why do you think this violates Drupal coding standards?

 * @return string|false
 *   The new temporary filename, or FALSE on failure.
🇷🇺Russia Chi

Well, there are a few other cases like this. I suppose the issue needs to be expanded to fix all of them.

🇷🇺Russia Chi

Asking Composer runtime API every page load is potentially a performance hit, but it's simple to have Composer write a file containing the data we need during Composer installation.

Composer stores locations of every package including Drupal core into vendor/composer/installed.php file. Given that is a PHP file no performance hit should be expected (thanks to Opcache).

🇷🇺Russia Chi

If that's still the case, then we can't rely on Composer being present.

We don't need Composer itself. InstalledVersions class is included to the tarball.

this needs a thorough investigation of the performance cost.

I did it in #26. Would be nice if someone else tested it to confirm.

🇷🇺Russia Chi

I guess it happens because Claro is using content property for drawing the separators. The possible fix would be to use background-image instead like Olivero does.

🇷🇺Russia Chi

@nicxvan we probably need to understand why "Implements hook_*" comment was initially added to Drupal coding standars. I guess it is needed to distinguish ordinary PHP functions from functions that implement Drupal hooks. Obviously with the Hook attribute is no longer needed. Also api.drupal.org might use this notation when listing hook implementatations.

For me it seems that in most cases docblock in hooks is not needed at all.

This issue is very similar to 📌 Allow omitting doxygen when type and variable name is enough Active . Maybe we should take same approach once it is resolved.

🇷🇺Russia Chi

Re: #292 drush gen phpstorm-meta will be able to generate these completions in the next release.

🇷🇺Russia Chi

Cross posted from 📌 OOP hooks using event dispatcher Needs review . The "implements" seems redundant now.

/**
 * Implements hook_help().
 */
#[Hook('help')]
Do you think that "implements" note is redundant for this kind of hooks?

It gets worse in single hook classes.

/**
 * Implements hook_help().
 */
#[Hook('help')]
final class Help {

  /**
   * Implements hook_help().
   */
  public function __invoke(): void {

  }

}
🇷🇺Russia Chi

Certain hook groups should be in a class together.

I would force using single class hooks wherever it is possible. There very few use cases when hooks are highly related to each other.

🇷🇺Russia Chi
/**
 * Implements hook_help().
 */
#[Hook('help')]

Do you think that "implements" notes are redundant for this kind of hooks?

🇷🇺Russia Chi

The fix seems trivial.

Note that @inheritdoc in \Drupal\entity\Access\EntityRevisionRouteAccessChecker::access is not actually referencing anything.

🇷🇺Russia Chi

Drupal currently does not support image styles for files stored in extension directories.

🇷🇺Russia Chi

That is the time format that all datetime fields expect.

Because it's storage format. It is rarely used in UI.
You may make the method more flexible by adding optional format parameter like follows.

function getNow(string $format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT)
Is that a necessity?

It's a general reason for having services injected. Core uses @datetime service when needs to obtain current time.

Hopefully, someday it'll switch from the custom baked TimeInterface to PSR-20.

🇷🇺Russia Chi

I am thinking of making all TT services final to avoid such issues in feature.

🇷🇺Russia Chi

Changing constructor signature could break existing sites that extends these services. Though the should not be considered as public API.
Anyway, I propose we change this the next major release. I've just created 4.x branch.

🇷🇺Russia Chi

Why are the cases coded in camel case? They are like constants. Shouldn't we use uppercase for them?

🇷🇺Russia Chi

I've just released a module that implements the date/time fields in a different way.
It also supports HTML5 elements in views exposed forms
https://www.drupal.org/project/date_point

🇷🇺Russia Chi

There are a few concerns with the proposed approach.

1. The implementation is hardcoded to one specific date format (Y-m-d\TH:i:s).
2. It overlaps with PSR 20 where now() is supposed to return DateTimeImmutable object.
3. It does not use core time service. So no way to mock the date in tests.

🇷🇺Russia Chi

Meanwhile, Date Point's build is green again. Has something been already changed?
https://git.drupalcode.org/project/date_point/-/pipelines/359856

🇷🇺Russia Chi

I like the idea of "Golden Contrib" which was proposed years ago
https://www.drupal.org/project/drupal/issues/1255674#comment-4917546

It's basically a curated list of Drupal modules and themes.
For each project in this list DA must ensure that
- It has active maintainer
- It has a stable release compatible with the current Drupal core
- It has proper documentation
- It complies with the strategy of Drupal CMS

🇷🇺Russia Chi

DomDocument is still pretty verbose.

DomDocument was referenced mainly as an example. I don't think it's the right tool for this. See note #6.

I was looking for something Yii HTML but with support of attachments and custom render callbacks.

🇷🇺Russia Chi

I think such a big change deserves a change record and 11.1 release highlights.

🇷🇺Russia Chi

What was the reason that 'label_count' is moved away from other 'label_*' parameters?

🇷🇺Russia Chi

All we need is a mechanism for the reset, that does not pollute the public interface.

If we were using the Symfony core, we would already have such a mechanism.

Anyway, I suppose it's not a big deal to enable this service pass in Drupal kernel.
\Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass

🇷🇺Russia Chi

unless they use some kind of magic plugin that reads the services.yml files

For PhpStorm you can generate meta information about services.

drush gen phpstorm-meta

Psalm also reads it. Not sure about PhpStan. I suppose phpstan-drupal can help on this.

🇷🇺Russia Chi

#2602368: Allow objects that implement RenderableInterface to used interchangeably with render arrays. indeed is very close to this one. Though the proposed approach is a bit different.

Here we aim to completely remove render arrays.
In #2602368 the render arrays will remain as intermediate layer between elements (objects) and renderer service. That is much easier to implement. The submitted patch is actually a tree-lines change.

As of BC, we don't have to implement it imminently. Custom projects can benefit from this change right now. Contributed projects may start using element objects in major releases where BC breaks are allowed.

🇷🇺Russia Chi

I think this issue has wider scope than 🌱 [policy] Standardize how we implement in-memory caches Needs work . Application state is not only about static caches. There are some other resources that may need to be reset between requests. DB connections, temporary files, open streams, etc. In Spiral framework that process is called finalizing. Finalizers are responsible for cleaning up resources. For instance, logger finalizer will call reset method on Monolog loggers.

Besides resource management there is another challenge. Request aware services. In core.services.yml I counted 47 services that has direct dependency on request_stack and there are many services that has indirect dependency through services like @current_route_match, current_user, datetime.time, etc. In Spiral that implemented with "scoped containers". For each request it creates a scoped container derived from root container with some request specific services.

One more issue to address is stateful Drupal kernel. It has a few of boolean flags (booted, prepared, etc) that needs to be reset after each request.

🇷🇺Russia Chi

It takes 0.015 ms on my localhost. That file is likely loaded from opcache and Composer caches the array in static variable. So it's Ok to call this method multiple times.

🇷🇺Russia Chi

@oily The are dozens different render elements in Drupal core. The MR currently covers just a few ones.

🇷🇺Russia Chi

A bit surprised how much this constant is used in Drupal.

🇷🇺Russia Chi

Submitted a MR for plain text formatter.

I don't know how is JsonMarkup supposed to work here.

🇷🇺Russia Chi

Turns out that default "Plain text" formatter has same bug.

🇷🇺Russia Chi

Given that expressions are not allowed in class constants we will have to deprecate that constant in favor of static method.

public static function version():string {
  return InstalledVersions::getPrettyVersion('drupal/core');
}
🇷🇺Russia Chi

We may use getPrettyVersion() instead.

echo Composer\InstalledVersions::getVersion('drupal/core'), \PHP_EOL;
echo Composer\InstalledVersions::getPrettyVersion('drupal/core'), \PHP_EOL;

Output on 10.3.10

10.3.10.0
10.3.10

Output on 11.x

11.9999999.9999999.9999999-dev
11.x-dev
🇷🇺Russia Chi

@oily that one was about setting Drupal version to 11.2-dev for 11.x branch. That's exactly what MR in this issue does. I am fine to close 🐛 Update Drupal::VERSION in dev branch Active as duplicate.

The relevant Slack conversation:
https://drupal.slack.com/archives/C1BMUQ9U6/p1729010405763549

Note that we will have to update that version to 11.3-dev once 11.3.x branch is open for development.

🇷🇺Russia Chi

Re #10

By "documentation," I mean a list of available properties with their types and a brief description. This documentation may already exist somewhere, but you would need to look it up yourself. For objects with typed properties and methods, IDE can provide that information for you. See Use the builder pattern to make it easier to create render arrays Needs work for details.

How do we handle BC, especially with alter hooks that expect to find arrays?

I've no idea at this moment. Another hook? Anyway, this needs some brainstorming.

🇷🇺Russia Chi

Re #8 That make sense.

Technically, the Drupal already has sort of DOM based on render arrays (should we call it DAM?). The issue merely about replacing associative arrays with objects.

it's better to create a lightweight element tree with a few helper methods to simplify manipulation and traversal

nicmart/tree seems like the right tool for this, at first glance.

🇷🇺Russia Chi

Re #5
That requires benchmarks. My guess is that manipulating an object tree costs almost nothing compared to other operations performed by Drupal's theme layer, such as preprocessing variables and rendering Twig templates.

🇷🇺Russia Chi

Actually, I think, having a full-fledged DOM implementation is not needed. We only need DOM as backing store for content tree. From this point, it's better to create a lightweight element tree with a few helper methods to simplify manipulation and traversal.

PHP’s built-in DOM extension feels overly complex for such tasks and has some pitfalls when dealing with multiple DOMDocument objects. On the other hand, it offers some cool features that could be nice to have, such as traversing in the upward direction, XPath, and CSS selectors (introduced in PHP 8.4) for finding elements. However, none of these features are essential for Drupal's rendering system.

🇷🇺Russia Chi

Overall, this will only mitigate the problem. Dropping render arrays is the only way to fully resolve the issue. I’ve filed a ticket in the ideas queue.

🇷🇺Russia Chi

Meanwhile, we can use a render element to gradually migrate from render arrays to DOM.

/**
 * Provides a render element to build markup using document object model.
 *
 * Properties:
 * - #dom: Document Object Model
 *
 * Usage Example:
 * @code
 * $build['dom'] = [
 *   '#type' => 'dom',
 *   '#dom' => $dom,
 * ];
 * @endcode
 *
 * @RenderElement("dom")
 *
 * @see https://www.php.net/manual/en/book.dom.php
 */
final class Dom extends RenderElementBase {

  /**
   * {@inheritdoc}
   */
  public function getInfo(): array {
    return [
      '#pre_render' => $this->preRenderEntityElement(...),
      '#dom' => NULL,
    ];
  }

  /**
   * Pre-render callback.
   */
  public static function preRenderEntityElement(array $element): array {
    $dom = $element['#dom'] ?? NULL;
    if (!$dom instanceof \DOMDocument) {
      throw new \InvalidArgumentException('#dom property must contain instance of DOMDocument');
    }

    // Instead of using saveHtml, it should traverse the tree recursively,  
    // rendering child nodes while respecting theme hooks and bubbling attached  
    // metadata. 
    return ['#markup' => $dom->saveHTML()];
  }

}
🇷🇺Russia Chi

PHP has evolved a lot since this issue was created. Type hints, property promotion, named arguments, etc. So instead of builders we can create value objects. It'll give same DX in modern IDEs.

Builder

$variables['table'] = TableElement::create()
  ->setHeader($headers)
  ->setRows($rows)
  ->setAttributes(['id' => $table_id])
  ->setTableDrag([
    [
      'action' => 'order',
      'relationship' => 'sibling',
      'group' => $weight_class,
    ],
  ],
)->toRenderArray();

Constructor

$variables['table'] = new TableElement(
  header: $headers,
  rows: $rows,
  attributes: ['id' => $table_id],
  tableDrag: [
    [
      'action' => 'order',
      'relationship' => 'sibling',
      'group' => $weight_class,
    ],
  ],
)->toRenderArray();
🇷🇺Russia Chi

We can't require write permissions to a PHP file in production.

For Twig files it was resolved in #2544932: Twig should not rely on loading php from shared file system . Can it be done same way for containers?

Anyway DB based container cache may still exist and used as fallback for sites that need container rebuild in non CLI SAPI. The point is to use more efficient solution by default.

🇷🇺Russia Chi

implies opening DB connection

Opening DB connection is rather expensive operation, especially in PostgreSQL. Even if the cache is managed through in memory backend (Redis/Memcache) Drupal will open DB connection as bootstrap container depends on Database service.

Production build 0.71.5 2024