beerendlauwers → created an issue.
The patch also needs to include a change to the webp_flush_webp_derivatives
function in webp.module
, which was introduced by
https://www.drupal.org/project/webp/issues/3153137
🐛
Using Image Widget Crop in responsive images does not refresh webp image
Fixed
.
Currently, the derivative webp uri is generated like this: $derivative_webp_uri = preg_replace('/\.(png|jpg|jpeg)$/i', '.webp', $derivative_uri);
This corresponds to the code $destination = $this->getWebpDestination($uri, '@directory@filename.webp');
Because this patch changes the above to $destination = $this->getWebpDestination($uri, '@directory@filename.@extension.webp');
, it also needs to change there.
Changing it to this makes it consistent again:
$derivative_webp_uri = \Drupal::service('webp.webp')->getWebpDestination($derivative_uri, '@directory@filename.@extension.webp');
Yup, works!
Works!
beerendlauwers → created an issue.
beerendlauwers → created an issue.
I wrote my own kernel request event subscriber for this that piggy backs off of the configuration form of the module:
namespace Drupal\my_module\EventSubscriber;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\language\LanguageNegotiatorInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Redirects to the relevant front page if no language code has been set.
*/
class IpCountryDetectionSubscriber implements EventSubscriberInterface {
/**
* Drupal\Core\Entity\EntityTypeManagerInterface definition.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* The language negotiator.
*
* @var \Drupal\language\LanguageNegotiatorInterface
*/
protected $negotiator;
/**
* Drupal\Core\Path\PathMatcherInterface definition.
*
* @var \Drupal\Core\Path\PathMatcherInterface
*/
protected PathMatcherInterface $pathMatcher;
/**
* Constructs a IpCountryDetectionSubscriber.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\language\LanguageNegotiatorInterface $negotiator
* The language negotiator manager service.
* @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
* The path matcher service.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager,
LanguageNegotiatorInterface $negotiator,
PathMatcherInterface $path_matcher) {
$this->entityTypeManager = $entity_type_manager;
$this->negotiator = $negotiator;
$this->pathMatcher = $path_matcher;
}
/**
* Redirects to the relevant front page if no language code has been set.
*
* The relevant front page is determined by ip2country and the
* language negotiation subscriber from ip_language_negotiation.
*
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
* The Event to process.
*/
public function onKernelRequest(RequestEvent $event): void {
$request = $event->getRequest();
$path = $request->getPathInfo();
// Only redirect if we have no language information in the URL.
if ($path !== '/') {
return;
}
try {
$method_id = 'ip-language-negotiation-ip';
$languageEntity = NULL;
if ($this->negotiator->isNegotiationMethodEnabled($method_id)) {
$ipLanguageNegotiation = $this->negotiator->getNegotiationMethodInstance($method_id);
$langcode = $ipLanguageNegotiation->getLangcode($request);
// Fallback is English (Europe) if IP detection fails.
if ($langcode === NULL) {
$langcode = 'en';
}
$languageEntity = $this->entityTypeManager->getStorage('configurable_language')
->load($langcode);
}
if ($languageEntity instanceof ConfigurableLanguage) {
$request_query = $request->query->all();
$route_name = $this->pathMatcher->isFrontPage() ? '<front>' : '<current>';
$url = Url::fromRoute($route_name, [], ['language' => $languageEntity]);
$url->setOption('query', (array) $url->getOption('query') + $request_query);
$response = new TrustedRedirectResponse($url->setAbsolute()
->toString());
$event->setResponse($response);
}
}
catch (\Throwable $exception) {
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events = [];
$events[KernelEvents::REQUEST][] = ['onKernelRequest', 400];
return $events;
}
}
Service definition:
my_module.kernel_request_subscriber:
class: Drupal\my_module\EventSubscriber\IpCountryDetectionSubscriber
arguments: [ '@entity_type.manager', '@language_negotiator', '@path.matcher' ]
tags:
- { name: event_subscriber }
For number 5, we could load it from the remote_id
:
$remote_id = $subscriber->get('remote_id');
$remote_config_id = $subscriber->get('remote_config_id');
$remote = $this->entityTypeManager->getStorage('remote')->load($remote_id);
if (!($remote instanceof RemoteInterface)) {
throw new \LogicException("Could not load remote with ID $remote_id");
}
$http_client = $remote->getHttpClient(true);
This could also be done in the constructor if you feel that's cleaner.
I wrote some code a long while ago for the channel filtering. This goes before $channels_to_notify[] = $channel->id();
:
$filters = $channel->get('channel_filters');
$passedFilters = true;
foreach ($filters as $filter) {
$directField = $filter['path'];
if ($entity->hasField($directField)) {
// Only checks first value right now.
$firstValueFromFilter = trim((string)$filter['value'][0]);
if ($filter['operator'] === '=') {
$fieldValue = trim($entity->get($directField)->getString());
if ($fieldValue !== $firstValueFromFilter) {
$passedFilters = false;
}
} elseif ($filter['operator'] === 'CONTAINS') {
if (!Arrays::any($entity->get($directField)->getValue(), function (
$element
) use ($firstValueFromFilter) {
if (isset($element['value'])) {
$fieldValue = $element['value'];
}
return $fieldValue === $firstValueFromFilter;
})) {
$passedFilters = false;
}
}
}
}
if (!$passedFilters) {
continue;
}
I made the field_types array that way to support the different providers. Otherwise, you would still have a lot of code duplication for the same field. I mean, we could silently ignore any field types that do not exist, then you wouldn't need the provider keys anymore. Did you use these provider keys for anything else?
Another thing to add to the annotation: a type property to determine what kind of method will be generated (getter/setter/adder/remover).
I was wondering about that, what purpose does that have? For code generation, it doesn't really matter. It would be useful for categorization, so you could group the generators on an overview form or the like. What's your vision on it?
@D34dMan I'm looking for a code-based solution that allows me to manage all translations for my custom strings in a single spot. PO files split things up by language, and the Texts module uses a custom content entity, so I can't deploy it or put it in versioning. This module seems like a great fit if it were to support translations.
beerendlauwers → created an issue.
@himanshu_jhaloya Indeed, this is an issue to change the documentation to reflect this knowledge.
beerendlauwers → created an issue.
beerendlauwers → created an issue.
beerendlauwers → created an issue.
What do you think of this initial annotation setup?
namespace Drupal\entity_bundle_scaffold\Plugin\EntityBundleClassMethodGenerator;
/**
* A getter method generator for float fields.
*
* @EntityBundleClassMethodGenerator(
* id = "float_getter",
* method_prefix = "get",
* field_types = {
* "float": { "provider": "core" },
* "decimal": { "provider": "core" },
* "computed_decimal": { "provider": "computed_field" },
* "computed_float": { "provider": "computed_field" },
* }
* )
*/
class FloatGetter extends BaseScalarType {
/**
* {@inheritdoc}
*/
public static function getType(): string {
return 'float';
}
}
This would add a get(fieldLabel)
method to each applicable field type.
A collection of thoughts as I was perusing the code:
We could also pull out the method prefix from the annotation and have it be determined in a static parent method, e.g. FieldGetter.php
. That might be cleaner, but would make one-off custom methods a bit more cumbersome because you would first have to define a parent class for your one-off method generator.
We'll have to make some minor changes to EntityBundleClassGenerator::buildFieldGetterName
(and rename it) to use that prefix.
There might be some other things we might want to put into the plugin annotation / parent class logic, e.g. the method visibility and "generators.bundle_class.field_getter_name_source".
The "generators.bundle_class.fields_to_ignore" setting might have to be a matrix of fields and applicable generators (think of the role / permission checkboxes matrix). This matrix might also solve https://www.drupal.org/project/entity_bundle_scaffold/issues/3402376 ✨ Make automatic bundle class/getter method generation configurable Active .
is there a branch open for this? I'd like to customize and add to the method generators and this seems like a good fit.
For determining whether a certain generator can be used for a certain field: we can take the logic from WidgetPluginManager
that checks if it's in the 'field_types' array and also provides a static isApplicable
method for making a decision on the field definition.
I don't think it's handy to have it be a non-static method, because that would mean you would have to instantiate each plugin to check if it applies or not.
I'm working on something similar: given a field storage, I'd like to mark one field instance's display configuration as "canonical", and then ask the system to give me an overview of diffs for all other instances of the field.
I'd then like to be able to mark particular parts of the non-canonical configuration to be overwritten. For example, I might not care about a different description in some cases, but I do care about the type of form widget that is used. In other cases, I might want to enforce the descriptions to be the same. I'm thinking of some checkboxes next to each key in the settings array.
beerendlauwers → created an issue.
beerendlauwers → created an issue.
Issue is still present. @AkshayAdhav you probably did not test with a patch for 2269823, e.g. https://www.drupal.org/files/issues/2023-08-29/core-checkbox-groups-10.1... → .
To properly test it, you'll have to create your own FieldWidget that extends OptionsButtonsWidget, for example:
namespace Drupal\my_example_module\Plugin\Field\FieldWidget;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsButtonsWidget;
/**
* Plugin implementation of the 'options_buttons' widget.
*
* @FieldWidget(
* id = "example_options_buttons",
* label = @Translation("Check boxes/radio buttons - With Groups"),
* field_types = {
* "boolean",
* "entity_reference",
* "list_integer",
* "list_float",
* "list_string",
* },
* multiple_values = TRUE
* )
*/
class ExampleOptionsButtonsWidget extends OptionsButtonsWidget
{
protected function getOptions(FieldableEntityInterface $entity)
{
return [
'Top level label 1' => [
1 => 'Option one',
2 => 'Option two',
],
'Top level label 2' => [
3 => 'Option three',
4 => 'Option four',
],
];
}
}
Select the "Check boxes/radio buttons - With Groups" widget in the form display configuration. Trying it without a patch for 2269823 results in an error. With a patch, you'll see the behaviour displayed in the original issue description.
+1 on this. I needed a way to provide a checkbox exposed filter that indicated if an entity reference field was empty or not, and was surprised to find that this does not exist out of the box.
beerendlauwers → created an issue.
I've added two new items to the context for the alter hook:
+ $context['plugin_settings'] = $this->getSettings();
+ $context['field_definition'] = $this->fieldDefinition;
I added these because I need to return different fields based on the type of field.
Patch is otherwise identical to #8.
@mark_fullmer For multi-value fields, the original field description is already shown:
Perhaps showing it below each single widget could be a configurable option in the form display widget settings?
beerendlauwers → created an issue.
beerendlauwers → created an issue.
After applying #122, I appear to be getting a JS error after each AJAX call in Drupal.behaviors.fieldGroup
:
Uncaught TypeError: Cannot read properties of undefined (reading 'Effects')
For future googlers: see https://www.drupal.org/project/symfony_mailer/issues/3403887 ✨ Microsoft Graph API Support Needs work
beerendlauwers → created an issue.
I also encountered this issue. Ideally, there should be another toggle under "Rewrite Results" to skip the Xss::filterAdmin
filter.
For now, I'm using the "Rewrite Results" toggle itself for this purpose. See the attached patch. It was written for Drupal 10.1.4, but it'll probably work on other versions.
beerendlauwers → created an issue.
beerendlauwers → created an issue. See original summary → .
Changing the "Alert Type" dropdown to become the bundle type seems like a great way to migrate existing alerts and align the structure of this module to Drupal's entity type architecture.
beerendlauwers → created an issue.
I was able to reproduce this with Gin 8.x-3.0-rc1
. What you need:
- Small viewport (1920x1080 of smaller)
- Button to open the entity browser is at the bottom of the viewport (see image)
This consistently opens the entity browser largely outside the viewport up top. Resizing the viewport triggers the fluidModal
JS behavior and fixes it.