title: Add CSS/JS to particular view?

text:
# Question
Title: Add CSS/JS to particular view?
I'm having trouble understanding how to attach a library to views. I want my assets to be included in /foo but not in /bar. I've read through the documentation on this more than once and from my understanding this is achieved by using preprocess, such as:

```
function my_theme_preprocess_page(&$variables) {
  if($variables['is_front']){
    $variables['#attached']['library'][] = 'my_theme/my_library';
  }
}

```

I'm new to Drupal so forgive my inherit ignorance, but what does $variables contain? 'is\_front' is easy enough, but how do I apply this to views or content types?

Thank you all in advance.

# Answer
> but what does $variables contain?

A couple of render arrays and some values that be used by twig template. Your best option is check de documentation for each preprocess function to see what are included in $variables. Docs link template\_preprocess(&$var) better explanation about preprocess functions and default list of template preprocess functions

> but how do I apply this to views or content types?

For me the best option is your twig template file by including this line.

```
{{ attach_library('my_theme/my-library') }}

```

No matter how many times this will be 'attached' only one will be downloaded (or aggregate). And only will added if this particular template will be rendered.

More info about Twig debug is here
> 8 votes

# Answer
One way to do it via your theme:

Set up your js as a library in your `mytheme.libraries.yml` file:

```
library-name:
  js:
    js-file-location/js-file-name.js: {}

```

Call your library in a preprocess hook in your `mytheme.theme` file:

```
/**
 * Implements hook_preprocess_views_view().
 */
function mytheme_preprocess_views_view(&$vars) {
  $vars['#cache']['contexts'][] = 'route';
  if ($vars['view_array']['#name'] == 'view_name') {
    $vars['#attached']['library'][] = 'mytheme/library-name';
  }
}

```

You'll need to replace these parts with your own actual code:

* `js-file-location` \- is it in a folder?
* `js-file-name` \- include the extension, I've used .js in this example
* `library-name` \- call it whatever you like
* `mytheme` \- the machine name of your theme

Note the cache context in this example is set to cache per route. It's important to know about it but outside the scope of this question.

Source: Adding stylesheets (CSS) and JavaScript (JS) to a Drupal 8 theme
> 9 votes

# Answer
I made a module for that for Drupal 8: Views Attach Library.

> The Views Attach Library module is designed to attach multiple libraries (JS and CSS) to views by providing just a library name.
>
> ## How to use?
>
> Installation is as simple as copying the module into your `modules/contrib` directory, then enabling the module.
>
> To add a library to a view follow below steps:
>
> 1. Create or edit view
> 2. Find Attach Library section
> 3. Click on add library or edit library
> 4. Add or edit library name in textfield.
> 1 votes

# Answer
Using hook\_views\_pre\_render() a library can be attached to a view with JS/CSS.

```
<?php
/**
 * Implements hook_views_pre_render().
 */
function hook_views_pre_render(ViewExecutable $view) {
  if (isset($view) && ($view->storage->id() == 'test_view')) {
    $view->element['#attached']['library'][] = 'custom/view.lib';
  }
}

```

Here 'custom/view.lib', custom is the module/theme name and view.lib is the library name.
> 1 votes

# Answer
As per the documentation of template\_preprocess\_page():

> See the page.html.twig template for the list of variables.

To know if a page is a view, please refer to: hook\_preprocess\_page(): how to tell a views page?

The content type is available as a property of the $node variable: `$variables['node']->type`.
> 0 votes

---
Tags: 8, theming
---


title: Custom 404 handling for images

text:
# Question
Title: Custom 404 handling for images
I'm looking for a way to handle 404's on images in Drupal. I have created several subscribers, but none seem to get triggered. My first try was to create subscriber that extends `RouteSubscriberBase`. The alterRoutes method looked like:

```
protected function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('system.404')) {
      $route->setDefault('_controller', '\Drupal\my_module\Controller\ImageRouteController::load');
    } else {
     (..)
    }
  }

```

This works perfectly for all 404's except for images (ending in .jpg or .png). This will still generate a default 404 page. It's actually a light-weight version, not the same as a 404 on a non-image non-existing page. When I debug through the Drupal code (starting in index.php) I see it goes through many steps before generating that light 404. So it does reach the Drupal code.

I found one particular interesting bit of code (which is reached when visiting a non-existing image):

```
$this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event);

```

This can be found in the `handle` method of `Symfony\Component\HttpKernel\HttpKernel`. With that knowledge I managed to find this page: https://www.drupal.org/node/2331613 . Again, it doesn't seem to work. What I have now:

my\_module.services.yml:

```
my_module.exception_image_subscriber:
    class: Drupal\my_module\EventSubscriber\ExceptionImageSubscriber
    tags:
      - { name: event_subscriber }

```

src\EventSubscriber\ExceptionImageSubscriber.php (removed comments):

```
<?php
namespace Drupal\my_module\EventSubscriber;

use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

class ExceptionImageSubscriber extends HttpExceptionSubscriberBase {

  /**
   * {@inheritDoc}
   */
  protected function getHandledFormats() {
    return ['svg','jpg','gif','png','webp'];
  }

  /**
   * {@inheritdoc}
   */
  protected static function getPriority() {
    return 0;
  }

  /**
   * Handles a 404 error for images
   */
  public function on404(GetResponseForExceptionEvent $event) {
     dd('test'); // <- not firing?!
  }
}

```

This doesn't seem to do anything, not for non-images or for images.

I start to believe the problem is that modules are not loaded when images are requested. Is there any way around this issue?

# Answer
> 5 votes
The light-weight version are fast 404 pages. They are configurable in `system.performance.yml`. The configuration can be overridden in `settings.php`. The default is:

```
$config['system.performance']['fast_404']['paths'] = '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i';

```

If you want to override this 404 handling in code your exception subscriber needs a priority \>200:

```
  protected static function getPriority() {
    return 300;
  }

```

and the format has to be `html`, not the file extensions:

```
  protected function getHandledFormats() {
    return ['html'];
  }

```

For reference https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21EventSubscriber%21Fast404ExceptionHtmlSubscriber.php/class/Fast404ExceptionHtmlSubscriber

---
Tags: 9, event-subscribers
---


# Question
Title: hook_theme_suggestions_image_alter() not returning ['data-responsive-image-style']
Perhaps I have similar issue to this Drupal 9.2 template\_preprocess\_image hook not working.

When I put this code in myTheme.theme

```
function HOOK_theme_suggestions_image_alter(array &$suggestions, array $variables)
{
 $responsive_style = $variables['attributes']['data-responsive-image-style'];
 $suggestions[] = 'image__'.$responsive_style;
}

```

The hook works good on inline images with this module Inline responsive images and it returns `['data-responsive-image-style']`.

But it doesn't work with regular article images, it returns `null`.

When I debug `$variables['attributes']` it has just this value

```
$variables[...] array (1)
  property => array (1)
    => string (12) "schema:image"

```

# Answer
I have found solution. I invoked from parent twig responsive\_image\_style\_id

```
function hook_preprocess(&$variables, $hook) {
  if ($hook == 'responsive_image') {
    $GLOBALS['responsive_image_style_id'] = $variables['responsive_image_style_id'];
  }
}

function hook_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if ($hook == 'image') {
    return $suggestions[] = 'image__'.$GLOBALS['responsive_image_style_id'];
  }
}

```
> 0 votes

---
Tags: theming, hooks
---


# Question
Title: How to describe dynamic config.settings values in schema.yml
I have a module config settings.yml file with a dynamic list of the fields attached to a user entity, eg

```
archive:
  directory: user-history/archive/
  filename: user-history-archive
  max_cardinality: 5
base_fields:
  uid: true
  name: true
  pass: true
  mail: true
  timezone: true
  status: true
  roles: true
  created: true
  changed: true
  access: true
  login: true
  init: true
  langcode: true
  preferred_langcode: true
  preferred_admin_langcode: true
attached_fields:
  field_alpha_text: 1
  field_beta_term: 1
  field_paragraph: 1
  field_user_story: 1
  user_picture: 0
  field_delta_value: 1
no_change:
  ignore: true
  delete: ''

```

I am unable to find out how this structure should be described in the module schema.yml file so that config\_inspector does not flag the schema as invalid.

I have tried vaiations on

```
user_history.settings:
  type: config_object
  label: 'User history settings'
  mapping:
    no_change:
      type: mapping
      label: 'No change'
      mapping:
        ignore:
          type: boolean
          label: 'Ignore records with no change'
        delete:
          type: string
          label: 'Delete "no change" records older than'
        batch:
          type: integer
          label: 'Batch size for "no change" record delete'
    base_fields:
      type: mapping
      label: 'Base fields to be tracked'
      mapping:
        uid:
          type: boolean
          label: 'Uid'
        name:
          type: boolean
          label: 'Name'
        pass:
          type: boolean
          label: 'Password'
        mail:
          type: boolean
          label: 'Mail'
        timezone:
          type: boolean
          label: 'Timezone'
        status:
          type: boolean
          label: 'Status'
        roles:
          type: boolean
          label: 'Roles'
        created:
          type: boolean
          label: 'Created'
        changed:
          type: boolean
          label: 'Changed'
        access:
          type: boolean
          label: 'Last access'
        login:
          type: boolean
          label: 'Login'
        init:
          type: boolean
          label: 'Initial mail'
        langcode:
          type: boolean
          label: 'Langcode'
        preferred_langcode:
          type: boolean
          label: 'Preferred langcode'
        preferred_admin_langcode:
          type: boolean
          label: 'Preferred admin langcode'
    attached_fields:
      type: mapping
      label: 'Attached fields to be tracked'
      mapping:
        attached_fields.%key:
          type: integer
          label: [label]
    archive:
      type: mapping
      label: 'Archive settings'
      mapping:
        directory:
          type: string
          label: 'Directory for archive files'
        filename:
          type: string
          label: 'Name for archive files'
        max_cardinality:
          type: integer
          label: 'Maximum field cardinality for separate column values'

```

but without success.

Any suggestions please?

# Answer
> 0 votes
I think this might be covered under the **#Defining a new schema** subheading here https://www.drupal.org/docs/drupal-apis/configuration-api/configuration-schemametadata#sequence-definitions

I tried to do this using a mapping type and couldn't get it to work, but switching to a sequence does, because a sequence is for identically typed subkeys, whereas a mapping means you might have different subtypes. When to use mapping or sequence to define an array in a schema file?

For a dynamic mapping, use instead the sequence type:

```
my_module.settings:
  type: config_object
  label: 'My module settings'
  mapping:
    node_type:
      type: sequence
      label: "List of node types"
      sequence:
        type: string
        label: "Node type key"

```

This allows arbitrary key -\> (string)values beneath the node\_type key in your schema.yml

---
Tags: 8
---


# Question
Title: How do I switch from a recommended release to a development snapshot?
Is there a non-Drush, Ludwig way to switch from the recommended release of a module to a development snapshot in Drupal 9, for example copying the development snapshot files and run update.php?

The Drush answer for Drupal 7 given in How can I update from the recommended release of a module to it development snapshot? suggests to do that.
In my case, I want to switch to the development snapshot of the Address module to resolve the *doctrine/collections missing when using Ludwig on Drupal 9* issue.

# Answer
> 3 votes
You can install the dev version of Drupal modules by setting the version constraint as `1.x-dev`. For example: `composer require drupal/token:1.x-dev`.

Read more: https://www.drupal.org/docs/develop/using-composer/using-composer-to-install-drupal-and-manage-dependencies#specify-version

---
Tags: 9, updating
---


# Question
Title: Paragraph of text in webform generated email is split into multiple lines rather than presurving single line of text
I am using a webform to send an email. The webform contains a textarea field.

I have noticed that if I enter a paragraph of text in the textarea field, then that same text is split into multiple lines in the email I receive.

So rather than being a single line of text which is wrapped within the email, it looks like the paragraph is split into separate lines (as shown in following image):

This is puzzling since if I check the body of the email using `hook_mail_alter()` the paragraph appears as a single line of text:

I can't work out why this is occurring. I am not sure if this is something that webform is doing or if it is something being done by the mail server itself (could it be something to do with plain text email protocal perhaps?). Was hoping someone would be able to enlighten me on the likely cause of this issue and how to solve it?

# Answer
> 0 votes
The issue seems to be with the plain text format of the mail.If you want to send mail content with designed structure then you must use Mime mail module.Once you enable the module you can use a HTML formatter for the textarea that is used to structure the mail. Let me know if you face any issues.

# Answer
> 0 votes
RFC 2822 says that each line of body text should be no longer than 78 characters and be terminated by \r\n, for a total of 80 characters on the line.

Drupal core follows this standard and wraps your text to make sure your email complies with this specification. There is no way to send a specification-compliant plain text email without wrapping the lines.

Instead, you can send HTML email, where your text will look like this is all on one line. (In actuality, the body of the email is still limited to 78 characters but, because it is interpreted as HTML, line breaks are ignored when displaying the formatted text.) Drupal core does not support HTML directly, instead you will need to install a contributed module such as Mime Mail to allow you to send HTML email.

---
Tags: 7, webforms, emails
---


# Question
Title: Creating a store in the Commerce module fails
Using Drupal 9, latest release of Commerce 8.x-2.28. I followed the Lugwig install instructions for the Commerce module. Everything seemed to install OK.

When I fill out the Create Store form, I get an error. The log shows: Location http://d9.susansmithjones.com/store/add/online Referrer http://d9.susansmithjones.com/store/add/online

Message Error: Class 'Doctrine\Common\Collections\ArrayCollection' not found in CommerceGuys\Addressing\Subdivision\Subdivision-\>\__construct() (line 117 of /home/dsusansm/public\_html/modules/address/lib/commerceguys-addressing/v1.0.9/src/Subdivision/Subdivision.php)

To review, the Commerce menu is showing and allows me to access the form to create a store. But when I try saving, I get the above message. It seems somehow related to addresses? What have I forgotten to do before creating the store? --\>

# Answer
> 0 votes
That issue is resolved with the latest dev version of Address, see https://www.drupal.org/project/address/issues/3126733

---
Tags: commerce, installation
---


# Question
Title: Checking for the content type in html.html.twig
I need the html.html.twig template to output different classes for the `<body>` tag, depending on the type of content. I know how to do this in the node template, but it doesn't work in the html.html.twig template. We need something like the following.

```
{% if node.bundle == 'page'  %}
  <body class="pageClass">
{% else %}
  <body class="newsClass">
{% endif %}

```

# Answer
> 4 votes
There is no need to write code to get the content type of the viewed node, inside the html.html.twig file: That value is already passed to the template file.

> * logged\_in: A flag indicating if user is logged in.
> * root\_path: The root path of the current page (e.g., node, admin, user).
> * node\_type: The content type for the current node, if the page is a node.

The Seven theme is using that value, in its html.html.twig template.

```
{%
  set body_classes = [
    logged_in ? 'user-logged-in',
    not root_path ? 'path-frontpage' : 'path-' ~ root_path|clean_class,
    node_type ? 'page-node-type-' ~ node_type|clean_class,
    db_offline ? 'db-offline',
  ]
%}

```

Since the template file is used for any page, the template file is first checking `node_type` is initialized, and then it uses its value.

Similar code is used in the Bartik's html.html.twig template.

If you are using a theme developed from other users, I would first check the theme is already adding a class basing on the content type; if the theme is already doing that, and adding the CSS class to `<body>`, there isn't anything extra to do, except using the CSS classes added from the theme as selectors for CSS styles.
If you are developing a custom theme, I would add the same code I shown. Once that `body_classes` is initialized inside the template file, adding the CSS classes to the `<body>` tag is as simple as using the following code (a single line).

```
<body{{ attributes.addClass(body_classes) }}>

```

The code you wrote needs to be changed as follows, to work.

```
{% if node_type is not empty and node_type == 'page'  %}
    <body class="pageClass">
{% elseif node_type is not empty %}
    <body class="newsClass">
{% endif %}

```

# Answer
> 3 votes
You simply can do that without any templating by implementing `template_preprocess_html`.

```
/**
 * Implements template_preprocess_html().
 */
function MYTHEME_preprocess_html(&$variables) {

  $node = \Drupal::routeMatch()->getParameter('node');
  if ($node instanceof \Drupal\node\NodeInterface) {

    // Add node type body class.
    $variables['attributes']['class'][] = 'node-type-' . str_replace('_', '-', $node->bundle());

    // Add conditional body class.
    switch ($node->bundle()) {
      case 'page':
        $variables['attributes']['class'][] = 'foo';
        break;
      case 'news':
        $variables['attributes']['class'][] = 'bar';
        break;
    }
  }
}

```

# Answer
> 2 votes
For Drupal 9:

On Drupal 9 node\_type is not available, please use:

```
{% set  node_type = node.bundle|clean_class %}

```

---
Tags: 8, theming
---


title: Translating Menu Item Programmatically?

text:
# Question
Title: Translating Menu Item Programmatically?
I have been trying to translate menu items programmatically but upon saving it just adds the english field value to all my translations. Below is the code I am trying to execute:

```
 if ($entity->hasTranslation($language->getId())) {
      //For update
      $entity->removeTranslation($language->getId());
    }
    try {
      $entity->addTranslation($language->getId(), ['title' => 'abcd'])->save();
    } catch (EntityStorageException $e) {
      \Drupal::logger('Menu-Translation')->error($e->getMessage());
      \Drupal::messenger()->addError(t('Failed to add translation for ' . $language->getName()));
    }

```

I am debugging and I think the issue lies in the line :

```
$entity->addTranslation($language->getId(), ['title' => 'abcd'])->save();

```

Any help would be appreciated. Thankyou.

# Answer
You didn't take into account the default language. Your code will break if you're running this code on a callback in the default language, because you remove the default translation, and you're not allowed to do that:

```
$defaultLanguage = \Drupal::languageManager->getDefaultLanguage()->getId();
if ($entity->hasTranslation($language->getId()) && $language->getId() !== $defaultLanguage) {
  // For update
  $entity->removeTranslation($language->getId());
}
try {
  if ($language->getId() === $defaultLanguage) {
    // Just set the field value, not the translation:
    $entity->set('title', 'abcd');
  }
  else {
    $entity->addTranslation($language->getId(), ['title' => 'abcd'])->save();
  }
} catch (EntityStorageException $e) {
  \Drupal::logger('Menu-Translation')->error($e->getMessage());
  \Drupal::messenger()->addError(t('Failed to add translation for ' . $language->getName()));
}

```
> 1 votes

---
Tags: i18n-l10n, navigation
---


# Question
Title: How to exclude taxes from total prices but still show the tax during checkout
So I create a tax type Custom and set the rate 18%. The checkbox `Display taxes of this type inclusive in product prices.` comes in checked by default. If I leave it like that, cart shows product price as tax added and still displays tax line. If I uncheck it, cart shows product price as is but it hides the tax line. What I want is the combination of the two; I don't want to include the tax in the total price but I still want to display the tax in the cart. How can I achieve this?

# Answer
> 1 votes
This patch works beautifully for me, with both `Display taxes of this type inclusive in product prices.` under tax types and `Prices are entered with taxes included.` under store unchecked.

---
Tags: 8, commerce
---


# Question
Title: Set the quantity per product equal to value in input
I'm using the Commerce Ajax Add to Cart module to add a product to my cart using AJAX. I guess I'll have to do that by creating a patch.

It's working fine, but I'd like to change how a product is added to the cart. For example, users add 4 times the same product in the cart. I've already made some changes so the by default, the quantity in my item cart is four. For now, if users click on \*Add to cart, then the quantity will be added to the cart.

Instead of adding the quantity to the cart, I'd like to update the quantity. If users click on *Add to cart* and the quantity is five, instead of adding five to the quantity, the quantity for the product is five instead of nine.

After digging, I've found on commerce/modules/cart/src/Form/AddToCartForm.php `submitForm()`, which uses the following code.

```
$this->entity = $this->cartManager->addOrderItem($cart, $order_item, $form_state->get(['settings', 'combine']));

```

I tried to remove the order item before adding the item (to "simulate" a quantity of 0) with this code.

```
$this->cartManager->removeOrderItem($cart, $order_item);

```

I also tried by updating the order item cart.

```
$this->entity = $this->cartManager->updateOrderItem($cart, $order_item, $form_state->get(['settings', 'combine']));

```

Neither of them gave the expected result.

Do you have any idea?

# Answer
As I thought, I've ended up to create a patch for this feature.

Reminder, **this not a hotfix**, it's specific for my website.

```
diff --git a/modules/cart/src/CartManager.php b/modules/cart/src/CartManager.php
index 3b27ae77..b81db592 100644
--- a/modules/cart/src/CartManager.php
+++ b/modules/cart/src/CartManager.php
@@ -108,7 +108,8 @@ class CartManager implements CartManagerInterface {
       $matching_order_item = $this->orderItemMatcher->match($order_item, $cart->getItems());
     }
     if ($matching_order_item) {
-      $new_quantity = Calculator::add($matching_order_item->getQuantity(), $quantity);
+      //$new_quantity = Calculator::add($matching_order_item->getQuantity(), $quantity);
+      $new_quantity = $quantity; //TODO: voir si impact sur la partie menu ?
       $matching_order_item->setQuantity($new_quantity);
       $matching_order_item->save();
       $saved_order_item = $matching_order_item;

```
> -1 votes

---
Tags: commerce, ajax, 9
---


# Question
Title: Which attributes are used for product variations on the PDP (product display page)?
Let's assume we have one product with 2 product variations. Both the variations have 10 product attributes each; they are all filled with their option values, for example `color = Blue`, `size = 10L`, or `height = 5`.

How does the Commerce module decide which attributes are used for product variations on the product display page?

# Answer
A product attribute in Drupal Commerce only ever refers to a field on the product type (Commerce 1.x) or product variation type (Commerce 2.x+) that differentiates one variation from another on a display. These fields are always explicitly declared - in Commerce 1.x using the checkbox on the field configuration and in Commerce 2.x using the attribute checkboxes on the product variation type configuration page. Only those explicitly declared fields will be used by the Add to Cart form for product variation selection.

You can add any additional fields to it that you want. They will only ever be used for display.
> 0 votes

---
Tags: commerce
---


title: How do I share Google photos?

text:
# Question
Title: How do I share Google photos?
I would like to have all shared albums of a certain google account automatically into a Drupal website. I was able to establish a connection with 'Google\_photos\_api' and show all shared albums on site with code below.

```
<?php
$GooglePhotosService = \Drupal::service('google_photos_api.client');
try {
  $optParams=array("pageSize" => 50);
  $SharedAlbumlijst = $GooglePhotosService->googleServicePhotosLibrary->sharedAlbums->listSharedAlbums($optParams);
  ksm($SharedAlbumlijst);
  echo '<div id="GooglePhotos" class="grid views-view-grid">';
  echo '<div class="row">';
  foreach ($SharedAlbumlijst as $album) {
    echo '<div class="col-6 col-sm-6 col-md-4 col-lg-4 col-xl-3" style="margin-bottom: 10px;">';
    // Get some properties of an album
    $albumId = $album->getId();
    $title = $album->getTitle();
    $productUrl = $album->getProductUrl();
    $coverPhotoBaseUrl = $album->getCoverPhotoBaseUrl() . '=w200-h200-c';
    echo '<h5>' . $title . '</h5>';
    echo '<a href="' . $coverPhotoBaseUrl . '" id="' . $albumId . '">';
    echo '<img src="' . $coverPhotoBaseUrl . '" alt="' . $title . '">';
    echo '</a>';
    echo '</div>';
  }
  echo '</div>';
}
catch (Exception $e) {
  ksm($e);
}

```

The problem I cannot figure out is to list all media-items of a given album. Code below is not functioning. I don't know how to pass the albumID into this??

```
<?php
$GooglePhotosService = \Drupal::service('google_photos_api.client');

try {
  $albumId = 'ANfpKL0unQw8nWACRpVCPj0JxmZ5JHkX_xCecI-VPFxKrFScPPfpE8HakFWvKG3KFVXNnNyigXB0';
  $optParams = ['albumId' => $albumId];
  $mediaItems = $GooglePhotosService->googleServicePhotosLibrary->mediaItems->search($optParams);

  ksm($MediaItems);
}

catch (Exception $e) {
  ksm($e);
}

```

Any help would be great!! Thanks in advance!!

```
Error code:
The website encountered an unexpected error. Please try again later.
TypeError: Argument 1 passed to Google_Service_PhotosLibrary_Resource_MediaItems::search() must be an instance of Google_Service_PhotosLibrary_SearchMediaItemsRequest, array given, called in C:\Xampp2\htdocs\Demertr\modules\contrib\php\php.module(81) : eval()'d code on line 7 in Google_Service_PhotosLibrary_Resource_MediaItems->search() (line 79 of vendor\google\apiclient-services\src\Google\Service\PhotosLibrary\Resource\MediaItems.php).

```

`MediaItems.php`

```
class Google_Service_PhotosLibrary_Resource_MediaItems extends Google_Service_Resource {

public function search(Google_Service_PhotosLibrary_SearchMediaItemsRequest $postBody, $optParams = []) {
    $params = ['postBody' => $postBody];
    $params = array_merge($params, $optParams);
    return $this->call('search', [$params], 'Google_Service_PhotosLibrary_SearchMediaItemsResponse');
  }
}

```

```
SearchMediaItemsRequest.php

class Google_Service_PhotosLibrary_SearchMediaItemsRequest extends Google_Model {
  public $albumId;
  protected $filtersType = 'Google_Service_PhotosLibrary_Filters';
  protected $filtersDataType = '';
  public $pageSize;
  public $pageToken;
...

```

# Answer
> 0 votes
No idea really, but looking at the error message and the docs at https://google.github.io/php-photoslibrary/v1.1.0/classes/Google.Photos.Library.V1.SearchMediaItemsRequest.html (if that is the right version), I would say that you need to create an instance of `SearchMediaItemsRequest`, set the album id on that object and then pass that into the `search` method. So maybe something like this based on your code:

```
$media_request = new SearchMediaItemsRequest();
$media_request->setAlbumId($albumId);
$mediaItems = $GooglePhotosService->googleServicePhotosLibrary->mediaItems->search($media_request);

```

---
Tags: media, 9
---


# Question
Title: How can I programmatically change the view mode?
In Drupal 7 I did something like:

```
  function mymodule_views_pre_render(&$view) {
    //dpm($view);
    if ($view->name == 'services') {
      $view->style_plugin->row_plugin->options['view_mode'] = variable_get('services_teaser');
    }
    else if ($view->name == 'portfolio') {
      $view->style_plugin->row_plugin->options['view_mode'] = variable_get('portfolio_teaser');
    }
  }

```

I don't know how to set the view mode on the fly, in Drupal 8. The idea is to be able to select the view mode for the view from a configuration form, instead of doing it from the view form.

How do I achieve this?

# Answer
You can select VIew Mode as:

```
function YOUR_MODULE_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity, $context) {
  if ($entity->getEntityTypeId() == 'taxonomy_term' && $entity->bundle() == 'tag' && $view_mode == 'full') {
    $view_mode = 'CUSTOM VIEW MODE';
  }
}

```
> 15 votes

# Answer
Since the example code seems to be for a view, with `hook_views_pre_build()` you can programmatically set the view mode in a Drupal 9 view.

```
/**
 * Put the following lines on the top of the module file,
 * after the PHP opening tag and the documentation comment containing the
 * @file tag.
 */
use Drupal\views\Plugin\views\row\EntityRow;
use Drupal\views\ViewExecutable;

/**
 * Implements hook_views_pre_build().
 */
function YOUR_MODULE_views_pre_build(ViewExecutable $view) {
  if ($view->rowPlugin instanceof EntityRow && $view->rowPlugin->getEntityTypeId() === 'node' && $view->rowPlugin->options['view_mode'] === 'teaser') {
    $view->rowPlugin->options['view_mode'] = 'other_teaser';
  }
}

```

Maybe this is useful for others who need to migrate their Drupal 7 custom code to Drupal 9 or higher.
> 4 votes

# Answer
Extending @tim's answer, I found that I had to change the cache key as well.

```
function HOOK_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
      if ($entity->getType() === 'my_content_type') {
        // Get the value of the "setting" field.
        switch ($entity->field_list_style->value) {
          case 'custom':
            // Set the view mode.
            $count = $build['field_my_entity_reference']['#items']->count();
            for ($i = 0; $i < $count; $i++) {
              $build['field_my_entity_reference'][$i]['#view_mode'] = 'custom_view_mode';

              $cache_key = array_search('default_view_mode', $build['field_my_entity_reference'][$key]['#cache']['keys']);
              $build['field_my_entity_reference'][$key]['#cache']['keys'][$cache_key] = 'custom_view_mode';
            }
            break;
        }
      }
    }

```
> 2 votes

# Answer
In a preprocess function, it can be done depending of a value of one field like this:

```
function hook_preprocess_paragraph(array &$variables) {
  $paragraph = $variables['paragraph'];
  if ($paragraph->field_paragraph_image_clickable->value === "0") {
    $variables['content']['field_paragraph_image_ref']['0']['#view_mode'] = 'image_without_link';
    unset($variables['content']['field_paragraph_image_ref']['0']['#cache']['keys']);
  }

```
> 2 votes

# Answer
If you have an entity reference field attached to a node, and want to offer the editor a choice of view modes through another field, you can change the view mode in the render array.

In this example `my_content_type` has a field `field_my_entity_reference` that is set up to be rendered using `default_view_mode`. The `field_list_style` field offers a list of display options that are used to override the default view mode.

```
function HOOK_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
  if ($entity->getType() === 'my_content_type') {
    // Get the value of the "setting" field.
    switch ($entity->field_list_style->value) {
      case 'custom':
        // Set the view mode.
        $count = $build['field_my_entity_reference']['#items']->count();
        for ($i = 0; $i < $count; $i++) {
          $build['field_my_entity_reference'][$i]['#view_mode'] = 'custom_view_mode';
        }
        break;
    }
  }
}

```
> 0 votes

---
Tags: views, 8
---


# Question
Title: How can I force user logout from a JavaScript library in a custom module?
I've written a custom module for Drupal 8 to monitor user device location frequently. If a user goes out of an allowed zone boundary, I need to force logging the user out of the website. I created following files in the module folder (*gps\_test*):

1. File *gps\_test.info.yml*
2. File *gps.js*: JavaScript program to monitor the user device's GPS location.
3. File *gps\_test.libraries.yml*: Contains the *gps.js* library.
4. File *gps\_test.module*: Implements a hook to attach the JavaScript library on every page load.

```
function gps_test_page_attachments(array &$page) {
  $page['#attached']['library'][] = 'gps_test/gps';
}

```

How can I force the user being logged out (or prevent the user from using the website) from the *gps.js* library?

# Answer
As @Tushar mentioned it, you can use the `user_logout()` function.

Simplest way I see is to log your user out with an AJAX call when your JS detects that the user needs to be logged out. Here is a basic example of how it can be done.

In your JS, you need to add:

```
Drupal.behaviors.logout= {
  attach: function(context, settings) {
    if(yourConditionToLogOutUserisMet) {
      $.ajax({
        url: "/log-me-out", // custom route to log current user out
        success: function(data) {
          // do whatever you want on success of your ajax call
        }
      });
    }
  }
}

```

Then, create your custom route in gps\_test.routing.yml

```
gps_test.my_custom_log_out:
  path: '/log-me-out'
  defaults:
    _controller: '\Drupal\gps_test\Controller\MyLogOutController::logUserOut'
  requirements:
    _permission: 'access content'

```

And finally, create the route controller:

```
namespace Drupal\gps_test\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;

class MyLogOutController extends ControllerBase {
  function logUserOut() {
    if ($this->currentUser()->isAuthenticated()) {
      user_logout();

      return new JsonResponse([
        'message' => "Current user session has ended.",
      ], 200);
    }
  }
}

```
> 4 votes

---
Tags: 8, users, javascript
---


# Question
Title: Exception\UnknownExtensionException: The module does not exist or is not installed
I get this error on my site

> Drupal\Core\Extension\Exception\UnknownExtensionException: The module does not exist or is not installed. in Drupal\Core\Extension\ExtensionList-\>getExtensionInfo() (line 346 of ...core/lib/Drupal/Core/Extension/ExtensionList.php).

This error is happening in shared hosting server.

```
  public function getExtensionInfo($extension_name) {
$all_info = $this->getAllInstalledInfo();
if (isset($all_info[$extension_name])) {
  return $all_info[$extension_name];
}
throw new UnknownExtensionException("The {$this->type} $extension_name does not exist or is not installed."); // line 346

```

}

I have been searching online and found lot of discussions but I could not fix it. How can I fix the error?

Php: 7.0 Drupal: 8

# Answer
> 2 votes
I have agree with @4k4 you can fix this with database

If your module have been deleted from the system use this query

```
delete from `key_value` where collection = 'system.schema' and name = '$extension_name';

```

for example:

```
delete from `key_value` where collection = 'system.schema' and name = 'config_tools';
delete from `key_value` where collection = 'system.schema' and name = 'git_config';

```

# Answer
> 5 votes
I had the error still appearing no matter what.

> Drupal\Core\Extension\Exception\UnknownExtensionException: The module twig\_food does not exist.

Finaly i found this command working:

```
drush cdel core.extension module.twig_food

```

---
Tags: theming
---


title: Tarball 9.3.0 to Composer 9.3.0

text:
# Question
Title: Tarball 9.3.0 to Composer 9.3.0
We have a large production website running 8.9.20 with a Tarball directory format. We would like to make the jump to 9.3.0 and convert the site from Tarball to Composer directory format. I performed the following:

* Cloned the production website to "staging" (copy production directory and database)
* drush up drupal-9.3.0

This "staging" Tarball 9.3.0 website has a clean "status" report and could be promoted to production with some additional testing. This is a great step in the right direction.

I also created a composer based website to directory "d9" as follows:

* composer create-project drupal/recommended-project d9
* composer require contrib modules and bootstrap theme
* updated composer.json repository to find our GitHub code
* composer require non-drupal library to vendor, custom module and custom bootstrap subtheme

This Composer 9.3.0 site "status" report is clean. The site does not contain our configuration data (content types, etc) or our content. Another step in the right direction.

How do we move from Tarball to Composer directory format? Perhaps this is as easy as copying the database from the Tarball 9.3.0 site to the Composer 9.3.0 site. This is similar to our Cloning process above without copying the directory. I have never seen this documented anywhere and would like to make sure this is the correct move for our (eventually) production website. Thanks!

# Answer
> 1 votes
> The site does not contain our configuration data (content types, etc) or our content. How do we move from Tarball to Composer directory format? Perhaps this is as easy as copying the database from the Tarball 9.3.0 site to the Composer 9.3.0 site.

Yes, when you have managed to rebuilt the entire codebase with composer you can move the database containing your content and the active configuration. Copy at the same time the files directory, in a default install `sites/default/files/`, so that both are in sync.

The files folder contains some files generated during a cache rebuild or when needed. Like aggregated css/js files, compiled templates or image styles. It doesn't really matter whether you simply copy all files or exclude those to let them be rebuilt if necessary.

Concerning the config sync folder. If you switch to the composer drupal/recommended-project it is also recommended to move the sync folder outside of the webroot. See https://www.drupal.org/docs/configuration-management/changing-the-storage-location-of-the-sync-directory

---
Tags: 9, composer
---


# Question
Title: Unique constraint on several entity fields fails when >1 jsonapi POST requests happen right after another
In a fully decoupled drupal 9 project I have a custom entity type and added a unique constraint for several fields just as described here. This works well and adding a second entity with the same field values is not possible. However, I'm using JSONAPI POST requests to create the entities. I noticed that when issuing multiple POST requests with the exact same field values right after another, the validator method (using the `entityTypeManager->getStorage(...)->getQuery(...)->condition(...)->execute()` to check the DB) does not return other entities, as no duplicate entity exists yet. I.e. it happens so fast that multiple identical-valued entities are created at the exact same timestamp (The `created` values of the entities are identical)!

Bypassing the constraint is dangerous and must be prevented.

What can I do to solve this problem?

**Update** This is the function that is called inside the `ConstraintValidator`

```
public function validate($entity, Constraint $constraint)
{
  ...
  if (!$this->isUnique($entity))
    $this->context->addViolation($constraint->notUnique);
  ...
}
private function isUnique(CustomType $entity) {
  $date = $entity->get('date')->value;
  $type = $entity->bundle();
  $employee = $entity->get('employee')->target_id;
  $query = $this->entityTypeManager->getStorage('custom_type')->getQuery()
    ->condition('status', 1)
    ->condition('type', $type)
    ->condition('employee', $employee)
    ->condition('date', $date);

  if (!is_null($entity->id()))
    $query->condition('id', $entity->id(), '<>');

  $workIds = $query->execute();
  return empty($workIds);
}

```

I'm happy to find any flaws. So far this code works well in all other cases.

**Update Drupal::lock()**

I've implemented 2 event subscribers to add and release `\Drupal::lock()` as mentioned in the comments. Using xdebug I can confirm that the code is run, however, the lock does not seem to have any effect. The documentation for `lock()` is rather limited. Not sure what's wrong here.

```
<?php

namespace Drupal\custom_entities\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

class JsonApiRequestDBLock implements EventSubscriberInterface {

  /**
   * Adds a lock for JSON:API requests.
   *
   * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
   *   The event to process.
   */
  public function onRequest(RequestEvent $event) {
    $request = $event->getRequest();
    if ($request->getRequestFormat() !== 'api_json') {
      return;
    }

    if ($request->attributes->get('_route') === 'jsonapi.custom_type--work.collection.post' &&
      $request->attributes->get('_controller') === 'jsonapi.entity_resource:createIndividual'
    ) {
      $lock = \Drupal::lock();
      $lock->acquire('custom_create_lock');
    }

  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = ['onRequest'];
    return $events;
  }

}

```

and release the lock after the response

```
<?php

namespace Drupal\custom_entities\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

class JsonApiResponseDBRelease implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::RESPONSE][] = ['onResponse'];
    return $events;
  }

  /**
   * Release JSON:API responses.
   *
   * @param \Symfony\Component\HttpKernel\Event\ResponseEvent $event
   *   The event to process.
   */
  public function onResponse(ResponseEvent $event) {
    $response = $event->getResponse();
    if (strpos($response->headers->get('Content-Type'), 'application/vnd.api+json') === FALSE) {
      return;
    }
    $request = $event->getRequest();
    if ($request->attributes->get('_route') === 'jsonapi.custom_type--work.collection.post' &&
      $request->attributes->get('_controller') === 'jsonapi.entity_resource:createIndividual'
    ) {
      // Release the lock.
      $lock = \Drupal::lock();
      if (!$lock->lockMayBeAvailable('custom_create_lock'))
        $lock->release('custom_create_lock');
    }
  }

}

```

This was added to the `services.yml`

```
  # Event subscribers.
  custom_entities.jsonapi_db_lock.subscriber:
    class: Drupal\custom_entities\EventSubscriber\JsonApiRequestDBLock
    tags:
      - { name: event_subscriber }
  custom_entities.jsonapi_response_db_release.subscriber:
    class: Drupal\custom_entities\EventSubscriber\JsonApiResponseDBRelease
    tags:
      - { name: event_subscriber }

```

# Answer
Without seeing all the code used for the *custom\_type* entity, including the code for its handlers, and answering to why the code doesn't find duplicates, there are two "flaws" I can imagine possible in the shown code.

The first "flaw" is that the query searching for existing entities is more restrictive than it should. This means it checks for entity fields that should be irrelevant for the entities to be duplicates, for example:

* The *status* field, assuming it's the *status* field used by the Drupal core entities
* The *date* field, assuming it contains the creation date/timestamp

The only Drupal core entity that uses an entity validation to avoid duplicate entities are created is the *path\_alias* entity, implemented by the `PathAlias` class. That entity has a *status* field, it supports revisions, but it doesn't have a field to store when it has been created, nor does it have an owner entity (like nodes do).
`UniquePathAliasConstraintValidator` is its entity constraint validator; the code for `UniquePathAliasConstraintValidator::validate()` is the following one.

```
  $path = $entity->getPath();
  $alias = $entity->getAlias();
  $langcode = $entity->language()->getId();
  $storage = $this->entityTypeManager->getStorage('path_alias');
  $query = $storage->getQuery()
    ->accessCheck(FALSE)
    ->condition('alias', $alias, '=')
    ->condition('langcode', $langcode, '=');
  if (!$entity->isNew()) {
    $query->condition('id', $entity->id(), '<>');
  }
  if ($path) {
    $query->condition('path', $path, '<>');
  }
  if ($result = $query->range(0, 1)->execute()) {
    $existing_alias_id = reset($result);
    $existing_alias = $storage->load($existing_alias_id);
    if ($existing_alias->getAlias() !== $alias) {
      $this->context->buildViolation($constraint->differentCapitalizationMessage, ['%alias' => $alias, '%stored_alias' => $existing_alias->getAlias()])
        ->addViolation();
    }
    else {
      $this->context->buildViolation($constraint->message, ['%alias' => $alias])
        ->addViolation();
    }
  }
}

```

Using that code as example, and using only the code that strictly checks for duplicates, in your case I would use the following code. (I am showing only the code for `isUnique()`.)

```
private function isUnique(CustomType $entity) {
  $date = $entity->get('date')->value;
  $type = $entity->bundle();
  $employee = $entity->get('employee')->target_id;
  $query = $this->entityTypeManager->getStorage('custom_type')
    ->getQuery()
    ->accessCheck(FALSE)
    ->condition('type', $type)
    ->condition('employee', $employee)
    ->condition('date', $date);

  if (!$entity->isNew()) {
    $query->condition('id', $entity->id(), '<>');
  }

  $result = $query->range(0, 1)->execute();
  return empty($result);
}

```

I added the call to `accessCheck(FALSE)` because, without seeing the code used by the entity access handler, and without knowing if the entity has an owner entity, I cannot exclude the implementation of `isUnique()` isn't finding duplicates because the currently logged-in user doesn't have access to the duplicates (or any entity of that type). Without calling `accessCheck(FALSE)`, the query will return the entities to which the currently logged-in user has access.
(The missing call to `accessCheck(FALSE)` is the other, possible, "flaw" I can see in the shown code.)
> 2 votes

---
Tags: entities, 9
---


# Question
Title: Drag and drop to sort taxonomy weight in a view
I need to create a custom admin view to replace the default taxonomy term listing page for a given vocabulary. The reason is that we have added custom fields on the vocabulary and the admins need to see those fields on the term listing page. To be clear, I am not talking about the individual term page that shows the content attached to that term, but the actual admin listing page that displays all of the terms for a given vocabulary. Obviously, I can create a view to do this, but I can not figure out how to preserve the drag and drop sorting functionality. I looked at the Draggable Views module, which I have used before, but that creates its own separate weight field and does not sort on the actual taxonomy term weight. Is there a better way to go about this? I just want to be able to sort the taxonomy weight in a view OR even better would be a way to just display the custom fields in the default taxonomy term listing screen, which I could not figure out how to do. I figured that was just a view that I could edit like the main content view, but I guess it is not. I couldn't figure out how to display the custom fields on that default admin taxonomy listing page.

# Answer
We ended up creating a custom module that overrides the taxonomy overview form. I pasted our code here in case this helps someone else out. In our case we needed to add a field called Acronym, a field called Type and we also added the Status. You can adjust as needed. Our custom module was called mc\_taxonomy and this was in the mc\_taxonomy.module file.

```
<?php

use Drupal\field\FieldConfigInterface;

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add status, field_acronym, and field_type to the overview page.
 */

function mc_taxonomy_form_taxonomy_overview_terms_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  // Get the vocab from the form to read its field config data.
  $vocab = $form_state->get(['taxonomy', 'vocabulary']);
  $fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('taxonomy_term', $vocab->id());

  // Insert fields if they exist.
  mc_taxonomy_overview_insert_field($form, 'status', 'Status', 1, function ($value) {
    return $value ? 'Published' : 'Unpublished';
  });

  if (isset($fields['field_type'])) {
    mc_taxonomy_overview_insert_field($form, $fields['field_type']);
  }

  if (isset($fields['field_acronym'])) {
    mc_taxonomy_overview_insert_field($form, $fields['field_acronym']);
  }

}

function mc_taxonomy_overview_insert_field(&$form, $field, $label = null, $index = 1, $valueFunction = null) {
  if ($index <= 0) {
    // TODO Allow index == 0.
    // TODO Check upper bound.
    throw new Exception('index must be >= 1.');
  }
  // Extract data from $field if it's the right type.
  if ($field instanceof FieldConfigInterface) {
    if (!$label) {
      $label = $field->label();
    }
    $fieldName = $field->getName();
  } else {
    $fieldName = $field;
  }
  // Add field to the header.
  $form['terms']['#header'] = array_merge(
    array_slice($form['terms']['#header'], $index - 1, $index, TRUE),
    [$label],
    array_slice($form['terms']['#header'], $index, NULL, TRUE)
  );
  foreach ($form['terms'] as &$term) {
    // Find terms within the render array.
    if (is_array($term) && !empty($term['#term'])) {
      // Add field to the term for the body.
      $fieldValue = $term['#term']->get($fieldName)->value;
      $term = array_merge(
        array_slice($term, $index - 1, $index, TRUE),
        [
          $fieldName => [
            '#markup' => $valueFunction ? $valueFunction($fieldValue) : $fieldValue,
            '#type' => 'item',
          ]
        ],
        array_slice($term, $index, NULL, TRUE)
      );
    }
  }
}

```
> 1 votes

---
Tags: views, taxonomy-terms
---


# Question
Title: how to convert date into timestamp using timezone
I am using strtotime to convert date into time stamp but its does not work correctly. I know its relatively to time zone. My drupal store time zone is denver. I am not sure why its not showing correct date. there is around one day difference. so The last date I used 31 but I get last date of 30th not 31

Here are my query to make date into time and fetch record

```
date_default_timezone_set(drupal_get_user_timezone());
$startdate = strtotime(\Drupal::request()->query->get('startdate')); // 2021-12-01
$endate = strtotime(\Drupal::request()->query->get('enddate')); //2021-12-31
$database = \Drupal::database();
if(!empty($startdate)){
$userrecord = $database->query("SELECT mail, access FROM users_field_data WHERE access BETWEEN $startdate and $endate")->fetchAll();

```

Here is twig where i Called date

```
{{ result.access|format_date('custom', 'F j, Y')|e }}

```

# Answer
> 2 votes
Drupal stores times always in UTC, never in local time. Also Unix timestamps are by definition in UTC.

You can convert a local date string to a timestamp by creating a \DateTime object:

```
$timestamp = (new \DateTime('2021-12-31'))->getTimestamp();

```

Which is using the default PHP timezone or by specifying your own time zone:

```
$timestamp = (new \DateTime('2021-12-31', new \DateTimeZone('America/New_York')))->getTimestamp();

```

---
Tags: 8, theming, datetime
---


title: Cache controller with json response

text:
# Question
Title: Cache controller with json response
I want to return a cached response in a controller that returns JSON data. I tried the following code.

```
$build = array(
  '#cache' => array(
    'contexts' => ['ip'],
  ),
);

return (new CacheableJsonResponse(['test'], 200))->addCacheableDependency(CacheableMetadata::createFromRenderArray($build));

```

I get this exception.

> LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\Core\Cache\CacheableJsonResponse. in Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-\>wrapControllerExecutionInRenderContext() (line 154 of /Applications/MAMP/htdocs/finder-cms/docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php).

# Answer
The controller from your question runs without exception:

```
public function demo() {
  $build = [
    '#cache' => [
      'contexts' => ['ip'],
    ],
  ];
  return (new CacheableJsonResponse(['test'], 200))->addCacheableDependency(CacheableMetadata::createFromRenderArray($build));
}

```

Result:

> \["test"\]

To produce the exception you need a controller like this:

```
public function demo() {

  $build = ['#markup' => 'early rendering'];
  $markup = \Drupal::service('renderer')->render($build);

  $build = [
    '#cache' => [
      'contexts' => ['ip'],
    ],
  ];
  return (new CacheableJsonResponse(['test'], 200))->addCacheableDependency(CacheableMetadata::createFromRenderArray($build));
}

```

Result:

> LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early.

This may not always be that obvious. Another example is when you try to get an url from an url object, see this answer https://drupal.stackexchange.com/a/187094/47547

---

**Add an URL with cacheable metadata to a response**

This is how you avoid the exception, when you render an url for a json response, and at the same time add the correct cache metadata to the response:

```
  $generated_url = $url->toString(TRUE);
  $response = new CacheableJsonResponse(['url' => $generated_url->getGeneratedUrl()], 200);
  $response->addCacheableDependency($generated_url);
  return $response;

```
> 10 votes

# Answer
After using multiple options, below code worked in my case for returning rest response.

```
$url = \Drupal\Core\Url::fromRoute('entity.node.canonical', [
  'node' => $node->id(),
], $options);
$url = $url->toString(true)->getGeneratedUrl();

```

Cheers!
> -2 votes

---
Tags: 8, caching, page-controller
---


# Question
Title: Is it possible to allow anonymous users to view a temporary managed file via hook_file_download()?
I am creating a live image preview system for customizable products that needs to send a user's temporary file to a remote server.

I have a token-based system to protect the file but the problem seems to be that the file is temporary. I've created a hook\_file\_download() to return the headers as required to allow access when approved but the file access is still being denied somewhere.

It does not seem to be a module weight issue as I've made my custom module have the lowest weight and verified via debug code that it fires after core file\_file\_download()

EDIT: Further troubleshooting shows the the headers array is getting a key value set to "-1" somewhere after hook\_file\_download() and core "FileDownloadController" which is where the file is getting denied. Any ideas where this \[0\] = -1 header value is getting set and how to override it?

If I strip it down to the basics for testing as shown below the 'allow' headers are returned but the file is still being blocked when viewed from an anonymous browser:

```
function MYMODULE_file_download($uri) {

  // Check to see if this is a config download.
  $scheme = StreamWrapperManager::getScheme($uri);

  if ($scheme == 'temporary'){
    if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri])){

      $file = reset($files) ?: NULL;

      // Access is granted.
      $headers = file_get_content_headers($file);
      return $headers;
    }
  }
}

```

# Answer
Temporary files are handled by `file_file_download()`, an implementation of `hook_file_download()` done from the File module. The code it uses is the following one.

```
  // Find out if a temporary file is still used in the system.
  if ($file->isTemporary()) {
    $usage = \Drupal::service('file.usage')->listUsage($file);
    if (empty($usage) && $file->getOwnerId() != \Drupal::currentUser()
      ->id()) {
      // Deny access to temporary files without usage that are not owned by the
      // same user. This prevents the security issue that a private file that
      // was protected by field permissions becomes available after its usage
      // was removed and before it is actually deleted from the file system.
      // Modules that depend on this behavior should make the file permanent
      // instead.
      return -1;
    }
  }

```

Reading the comments, that is done on purpose to avoid a private file, protected by field permissions, is visible after the field permissions are changed, but before the file is deleted.

Looking at the code that invokes that hook, in `FileDownloadController::download()` for example, I don't see any way to avoid that, as the code doesn't use `hook_file_download_alter()`.

A workaround could be setting that file as being used, since the code checks the file is not used, before blocking the access.

```
function mymodule_file_download($uri) {
  if (StreamWrapperManager::getScheme($uri) == 'temporary') {
    if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri])){
      if ($file = reset($files)) {
        // Access is granted.
        \Drupal::service('file.usage')->add($file, 'mymodule', 'unexisting_entity', 10);
        $headers = file_get_content_headers($file);
        return $headers;
      }
    }
  }
}

```

I used `'unexisting_entity'` and 10 as entity type and entity ID. If you have real values for them, you should use those.

Note that `FileUsageBase::add()`, the `DatabaseFileUsageBackend::add()` parent method, changes the file to permanent, in the case it is not already.

```
// Make sure that a used file is permanent.
if (!$file->isPermanent()) {
  $file->setPermanent();
  $file->save();
}

```

When a file usage is decremented and becomes 0, the file is changed to temporary from `FileUsageBase::delete()`.

```
// If there are no more remaining usages of this file, mark it as temporary,
// which result in a delete through system_cron().
$usage = \Drupal::service('file.usage')->listUsage($file);
if (empty($usage)) {
  $file->setTemporary();
  $file->save();
}

```

I would rather increase the file usage, instead of making directly a file permanent, as decreasing the file usage doesn't conflict with other modules that could set the same file as permanent.
Alternatively, I would use the following code for `hook_file_download()`.

```
function mymodule_file_download($uri) {
  if (StreamWrapperManager::getScheme($uri) == 'temporary') {
    if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri])){
      if ($file = reset($files)) {
        // Access is granted.
        if (!$file->isPermanent()) {
          $file->setPermanent();
          $file->save();
        }
        $headers = file_get_content_headers($file);
        return $headers;
      }
    }
  }
}

```

In this case, to make the file temporary again, I would use the following code.

```
// Store the file entity reference in $file.
$usage = \Drupal::service('file.usage')->listUsage($file);
if (empty($usage) && !$file->isTemporary()) {
  $file->setTemporary();
  $file->save();
}

```

To achieve what you want, it would be also possible to change the controller for the *system.temporary* route, but that seems excessive.
> 1 votes

---
Tags: files
---


# Question
Title: How to get current region or current block of node in hook_theme_suggestions_node()
I need to get the current region or the current block where a node is rendered, in `hook_theme_suggestions_node()`.

```
function mymodule_theme_suggestions_node(array $variables) {
  $node_region = "I don't know how to get it";
  $node_block = "I don't know how to get it";
  $suggestions[] = 'node__' . $node_region . '__' . $node_block;
}

```

I need only one value between `$node_region` and `$node_block`. How can I obtain them?

# Answer
> 0 votes
If you want a node to display differently on different parts of the page, the way to do that is to use View modes.

---
Tags: hooks, 9
---


# Question
Title: Send email to author when content is published through scheduler
I have used Scheduler module with content moderation integration to publish a content automatically. It is perfectly working using the module. Now I want to add a functionality that once the content is published via cron, an email will be sent to the author of that particular content.

I have used `hook_scheduler_publish_action` to perform this action, but unfortunately I am facing some different scenario.

1. If I remove node publish code and keep only the mail sending code, the mail is fired.
2. If I remove the mail sending code and keep only node publish code, the node is published.
3. If I keep both, only mail is sent, content is not published.

**Ref**: https://git.drupalcode.org/project/scheduler/blob/8.x-1.x/scheduler.api.php

**Below code is only publishing content, not sending email.**

```
function MYMODULE_scheduler_publish_action(NodeInterface $node) {
  // node moderation state will be 'published'
  $node->set('moderation_state', 'published');
  $node->save();

  // email send to author
  $mail_params = array(
    'mail_subject' => 'run cron',
    'mail_body' => '<p>node published using scheduler</p>',
    'mail_to' => 'someone@email.com'
  );

  \Drupal::service('MYMODULE.common_service')->FunctionToSendEmail($mail_params);
}

```

**Below code is only sending email, not publishing content.**

```
function MYMODULE_scheduler_publish_action(NodeInterface $node) {
  // email send to author
  $mail_params = array(
  'mail_subject' => 'run cron',
  'mail_body' => '<p>node published using scheduler</p>',
  'mail_to' => 'someone@email.com'
  );

  \Drupal::service('MYMODULE.common_service')->FunctionToSendEmail($mail_params);

  // node moderation state will be 'published'
  $node->set('moderation_state', 'published');
  $node->save();
}

```

That means this hook only perform the first action and ignores others.

Now my question is how will I perform multiple actions using this hook or is there any other procedure to do this?

Please help me. Thanks in advance.

# Answer
The Scheduler Module itself do provide some events , which one of them is `PUBLISH`. So you can create an event subscriber in your module and listen to publish event like this:

```
class YourSchedulerEventSubscriber implements EventSubscriberInterface {
  public function publishAndSendMail(SchedulerEvent $event) {
  /** @var \Drupal\node\Entity\Node $node */
  $node = $event->getNode();
  $node->set('moderation_state', $node->publish_state->getValue());

  $event->setNode($node);

  $mail_params = array(
  'mail_subject' => 'run cron',
  'mail_body' => '<p>node published using scheduler</p>',
  'mail_to' => 'someone@email.com'
  );
  \Drupal::service('MYMODULE.common_service')->FunctionToSendEmail($mail_params); //Better to be sent as service argumnets
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    // The values in the arrays give the function names above.
    $events[SchedulerEvents::PUBLISH][] = ['publishAndSendMail'];
    return $events;
  }
}

```
> 0 votes

---
Tags: 8
---


title: Templating the user edit page

text:
# Question
Title: Templating the user edit page
i'm using the theme startupgrowth lite and i want to theme my user edit page , only when the user is a 'testeur' and he's editing the 'candidate user profile'.

i know that when i want to modify the form i must do this step:

1- add function to template.php to override the template page:

```
 function startupgrowth_lite_theme($existing, $type, $theme, $path) {
$items['user_profile_form'] = array(
    // Forms always take the form argument.
        'arguments' => array('form' => NULL),
        'render element' => 'form',
        'template' => 'page--user--edit',
        'path' => drupal_get_path('theme', 'startupgrowth_lite') . '/template/form',
);
return $items;
}

```

2- After that i must create a folder /template/form/ and put my file page--user--edit.tpl.php on it and start coding in.

3- flush cache and you will have the render, if not that you must make the administration theme like your theme by default on my case (startupgrowthup theme).

But in normal case, i must write on code `<?php print render($form['XXX']); ?>` to have the field of user\_profil\_form named 'XXX'.

All 2steps works good but i don't know how to have the field of form on my page to modify all informations like i want to expose.

this is a screenshot that how i want to expose my page edit user.

# Answer
Well my solution for this, is to make a function on a custom module and print out my code directly to the page.

```
function custommodule_form_alter(&$form, $form_state, $form_id) {
  global $user;
  if($form['#form_id'] == "user_profile_form" && in_array('administrator', $user->roles)){
    echo $form['form_id']['#value'];
    print render($form['field1']);
    print render($form['field2']);
  }
  dpm($form);
}

```

PS: I use this to modify the user form only for some rules on my project. Here I choose administrator to see only `field1` and `field2` from all the form fields for example.

```
in_array('administrator', $user->roles)

```
> 0 votes

---
Tags: theming, forms
---


# Question
Title: Add a second RulesAction to a custom module
I created a custom module containing one Rules Action that works perfectly. I tried adding a second by creating a second php file in the `MODULE/src/Plugin/RulesAction` folder, with the names and class etc all changed from the original action.

I've tried refreshing the cache, and uninstalling/installing the module but the new action is not showing up. Is there another step I need to take, other than just putting a new file in the `MODULE/src/Plugin/RulesAction` folder?

# Answer
> 0 votes
I'm an idiot, it's right there under a different subheading. I expected them to appear together, but I set a different value on this line:

`* category = @Translation("This is the heading the action appears under."),`

---
Tags: 8, rules, actions
---


# Question
Title: Debugging functional tests with phpunit just hang unless I toggle "stop/start listenting for php debug connections"
Trying to get tests up and running by following https://www.previousnext.com.au/blog/running-and-debugging-phpunit-tests-phpstorm-ddev-and-xdebug. Seems to work, except having an issue with functional tests. If I disable xdebug, the test runs in like 5 secs. If I enable xdebug and try to "debug the test", it just hangs forever.

If I wait like 30s then toggle "stop/start listening for PHP Debug Connections" in phpstorm, a second "standard input code" tab opens in the debug panel and it continues to hang. Clicking "resume program" continues the execution, but a few seconds later I need to do it again. This happens a few times and the test eventually completes, but something about xdebug seems to be causing things to get stuck.

I'm reproducing with breakpoints in NodeAdminTest::testContentAdminSort and UiHelperTrait::drupalLogin.

# Answer
> 0 votes
Increasing the "max simultaneous connections" to 3+ in the phpstorm settings fixes the problem.

---
Tags: testing
---


# Question
Title: How to alter list of available countries provided commerce/guys
I need to alter the list of countries that are displayed in a webform. That uses a widget that is powered by the Address module which is powered by the commerceguys/addressing library.

According to the docs for Drupal/Commerce, that can be done with an event subscriber.

> You can alter the list of available countries for a select list by subscribing to the AddressEvents::AVAILABLE\_COUNTRIES

In fact, in the Address module, there is example code. This shouldn't be so hard, right?

Question is; when does the event fire? I'm on a page that has generated dropdown menu with a list of countries clearly produced by the Address module. But, the event never fires (see output below from the webprofiler)

I've pretty much copied the code in the module used as a test. But no luck getting the event to happen. So;

1. Anyone have any experience and hopefully success customizing the list of available countries
2. Any suggestions on determining when an event should fire

Side note to #2. Looking at the trait, I can see where it "should fire" but what page / endpoint would trigger that?

# Answer
> 0 votes
Here is the answer. Service Decorators

What needs to happen is to augment/modify the behavior of one method in the address.country\_repository service. Specifically `\Drupal::service('address.country_repository')->getList();`

Service Decorators from Symfony does exactly that- allows the base class to persist, but provides the ability to add to or modify the behavior of methods within the class

# Answer
> 0 votes
After reviewing this with module maintainers, the answer to the question is that it can't be resolved in the approach I was taking

> Webform is special, it uses the address element directly so the event (which is field type specific) is not fired. In that case you will need to override the country repository

---
Tags: webforms
---


# Question
Title: How can I print view/edit/comment links?
I have a view that uses the "View content," "edit content," and "view comments" fields. I can't figure out how to print these in a custom twig template.

I've tried:

```
{{ fields.comments_link.content }}
{{ fields.comments_link }}
{{ comments_link }}

```

Similar attempts to print the view and edit links didn't work either. Other fields print fine. Can someone point me in the right direction, or do I just need to call the NID into the view and print that into a link?

# Answer
Add "view content" & "edit content" link in view as follow

Then put views-view-table--articles.html.twig file in your theme's template directory and get fields as follow.

```
<div class="example-template">

{% for row in rows %}
  {% set titletxt = '' %}
  {% set viewnod = '' %}
  {% set editnode = '' %}
    {% for key, column in row.columns %}

      {% for field in column.fields %}

        {% for content in column.content %}

          {% if field == 'title' %}
             {% set titletxt = content.field_output %}
          {% endif %}

          {% if field == 'view-node' %}
             {% set viewnod = content.field_output %}
          {% endif %}

          {% if field == 'edit-node' %}
             {% set editnode = content.field_output %}
          {% endif %}

        {% endfor %}

      {% endfor %}

    {% endfor %}

    <div>
      <h3>
        {{titletxt}}
      </h3>
      <div>
        {{viewnod}}
      </div>
      <div>
        {{editnode}}
      </div>
    </div>

{% endfor %}

```

Please have a look, this might help you. Thanks
> 1 votes

---
Tags: 8, views, theming
---


# Question
Title: How do I pass parameters to the form builder?
I have the following routes in module\_name.routing.yml.

```
module_name.usergroup_delete:
  path: 'module_name/usergroup/delete/{arg1}'
  defaults:
    _form: '\Drupal\module_name\Form\DeleteUserGroup'
    _title: 'Delete User group'
  requirements:
    _permission: 'access admin menus'

```

This is the code in module\_name/src/Form/DeleteUserGroup.php.

```
namespace Drupal\module_name\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;

class DeleteUserGroup extends ConfigFormBase {

  public function getFormId() {
    return 'delete_user_group';
  }
/**
 * General form for switching all nodes from one user to another.
 */
  public function buildForm(array $form, FormStateInterface $form_state,$product_code) {
  $form['_product'] = array(
        '#type' => 'value',
        '#value' => $product_code,);
//get the user group and username to display the confirmation message
$result = db_query('select field_p_group_name_value from {content_type_usergroup} ctu'
        . ' where vid=%d',$product_code);
    while ($row = $result->fetchObject()) {
      $user_group = $row->field_p_group_name_value;
    }

return confirm_form($form,t('Are you sure you want to delete "' .$user_group. '" User Group?'),
        isset($_GET['destination']) ? $_GET['destination'] : "function_name",t('This action cannot be undone.'),t('Delete'),t('Cancel'));

  }
/**
 * #submit callback for node_adoption_transfer_form().
 */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $form_values = $form_state->getValues();
  //if ($form_state['values']['confirm']) {
    $param = $form_state->getValue('_product');
    drupal_set_message(t('Group ' .$param.' will get deleted.'));
    db_query('DELETE FROM {content_type_usergroup} WHERE vid = %d', $param);
    //delete the users of the usergroup too
    db_query('DELETE FROM {usergroup_user_map} WHERE group_id=%d', $param);
    drupal_set_message(t('usergroup has been deleted.'));
    drupal_goto('function_name');
  }

  protected function getEditableConfigNames() {
    return "delete_user_group";
  }

}

```

I am getting the following error:

> DeleteUserGroup::buildForm() must be compatible with Drupal\Core\Form\FormInterface::buildForm(array $form, Drupal\Core\Form\FormStateInterface $form\_state)

Why?

# Answer
> 48 votes
The parameter has to have the same name in routing.yml and build method. And when using parameters in forms you have to set a null value in the parameter list:

```
public function buildForm(array $form, FormStateInterface $form_state, $arg1 = NULL) {

```

# Answer
> 15 votes
First create a routing.yml file

```
admin_notes.form:
  path: '/example_module/form/{arg}'
  defaults:
    _form: '\Drupal\example_module\Form\ExampleForm'
  requirements:
    _permission: 'access content'

```

Then create a `.php` file under folder structure `/src/Form/ExampleForm.php`. Then build a form

```
public function buildForm(array $form, FormStateInterface $form_state, $arg = NULL) {
  $form['example_note'] = [
    '#type' => 'textarea',
    '#title' => $this->t('Block contents'),
    '#description' => $this->t('This text will appear in the example block.'),
    '#default_value' => $arg,
  ];
  $form['actions'] = ['#type' => 'actions'];
  $form['actions']['delete'] = [
    '#type' => 'submit',
    '#value' => $this->t('Delete'),
  ];
  return $form;
}

```

# Answer
> 6 votes
This is not asked in the question. Maybe it could also help, I had to pass a parameter to a form that was not loaded by a route. The form is integrated into a template loaded by a controller.

In `custom_module.routing.yml`:

```
path: '/lorem/{arg}'
defaults:
    _controller: '\Drupal\my_module\Controller\LoremController::testLorem'

```

In the controller, the form is called and the parameter `$arg` is passed to the form builder.

```
public function testLorem($arg) {
     $form = \Drupal::formBuilder()->getForm('Drupal\my_module\Form\testForm', $arg);
     $build = [
         '#theme' => 'custom_theme',
         '#form' => $form,
         '#arg' => $arg,
     ];

     return $build;
}

```

And in the form :

```
public function buildForm(array $form, FormStateInterface   $form_state, $arg = null) {
}

```

---
Tags: forms, 8
---


# Question
Title: How to remove the fieldsets that are pup around "list (text)" fields that have their display set to "Check Boxes / Radio Button"?
We have a Drupal 9 website and are using "list (text)" fields whose displays are set to "Check Boxes/ Radio Button". This causes the output to be wrapped in a field set which we need to remove.

I have tried some trial and error (guessing) at altering the field in hook\_form\_alter() but the fieldset remains.

The field variable is below:

```
Array
(
    [#type] => container
    [#parents] => Array
        (
            [0] => field_order_item_logo_wrapper
        )

    [#attributes] => Array
        (
            [class] => Array
                (
                    [0] => field--type-list-string
                    [1] => field--name-field-order-item-logo
                    [2] => field--widget-options-buttons
                )

        )

    [widget] => Array
        (
            [#title] => Image / Logo
            [#description] =>
            [#field_parents] => Array
                (
                )

            [#required] => 1
            [#delta] => 0
            [#weight] => 0
            [#element_validate] => Array
                (
                    [0] => Array
                        (
                            [0] => Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsButtonsWidget
                            [1] => validateElement
                        )

                )

            [#key_column] => value
            [#type] => radios
            [#default_value] => custom_logo
            [#options] => Array
                (
                    [custom_logo] => stdClass Object
                        (
                            [__CLASS__] => Drupal\Core\Field\FieldFilteredMarkup
                            [string:protected] => Provide Logo
                        )

                    [stock_art_as_shown] => stdClass Object
                        (
                            [__CLASS__] => Drupal\Core\Field\FieldFilteredMarkup
                            [string:protected] => Stock Art As Shown
                        )

                    [stock_logo] => stdClass Object
                        (
                            [__CLASS__] => Drupal\Core\Field\FieldFilteredMarkup
                            [string:protected] => Stock Logo
                        )

                    [no_logo] => stdClass Object
                        (
                            [__CLASS__] => Drupal\Core\Field\FieldFilteredMarkup
                            [string:protected] => No Logo
                        )

                    [logo_on_file] => stdClass Object
                        (
                            [__CLASS__] => Drupal\Core\Field\FieldFilteredMarkup
                            [string:protected] => Logo is on File
                        )

                    [repeat] => stdClass Object
                        (
                            [__CLASS__] => Drupal\Core\Field\FieldFilteredMarkup
                            [string:protected] => Repeat Exact Style as Previous Order
                        )

                )

            [#after_build] => Array
                (
                    [0] => Array
                        (
                            [0] => Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsButtonsWidget
                            [1] => afterBuild
                        )

                )

            [#field_name] => field_order_item_logo
            [#parents] => Array
                (
                    [0] => field_order_item_logo
                )

            [#tree] => 1
        )

)

```

# Answer
> 1 votes
Tried to replicate with same settings as you have mentioned but for me its not adding field set please check it might be your theme settings

---
Tags: entities
---


# Question
Title: How do you remove a user role via a hook update?
I would like to remove a user role via a hook update in Drupal 9.

I believe I would need to do something like the below but unclear what other code might be needed.

```
$user->removeRole('administrator');
$user->save();

```

# Answer
First, load all your users having the role you wish to delete:

```
$usersHavingRole = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties(['roles' => 'my_role']);

```

Then, for each user, remove the role (this is the code you mentioned):

```
foreach($usersHavingRole as $user) {
  $user->removeRole('my_role');
  $user->save();
}

```

And finally, delete the role:

```
$role = \Drupal\user\Entity\Role::load('my_role');
if (!empty($role)) {
  $role->delete();
}

```
> 2 votes

---
Tags: users, hooks
---


# Question
Title: Use Migrate Tools to import into multiple value link field from JSON array
I am trying to import data into a multi-value link field from a JSON source using Migrate Tools. I think I should be able to do this without writing a custom plugin, but so far nothing is working. My JSON looks like this:

```
[
 {
  "first_name": "Joe"
  "last_name": "Smith"
  "departments": [
     {
       "department_name": "Mail room"
       "department_url": "https://myoffice.com/mailroom"
     },
     {
       "department_name": "Receiving"
       "department_url": "https://myoffice.com/receiving"
     }
   ],
 },
 { . . . etc }
]

```

The `department_name` and `department_url` values would be the title value and uri value for a multi-value link field. I have tried using the sub\_process plugin by configuring the migration config this way:

```
- name: department_data
  label: "Department data"
  selector: departments

...

process:
   field_department_link:
      plugin: sub_process
      source: department_data
      process:
        'field_department_link/title': department_name
        'field_department_link/uri': department_url

```

I should note that this migration config is working overall, as I have a number of straight-up text fields that are importing just fine, so I know the issue is specific to how I'm trying to handle this particular field. Also please note that I don't have any control over the JSON itself. It's generated by a third-party application to which I don't have access.

# Answer
Got it figured out. Here's the process section of the config file for the multi-value link field:

```
process:
  field_department_link:
    plugin: sub_process
    source: department_data
    process:
      uri: department_url
      title: department_name

```
> 2 votes

---
Tags: migrations
---


# Question
Title: How do I get the public url of a file from the uri or filename
I'm using php from with a view (Views PHP) I'm trying to extract the real url of a file from a file reference. I am able to get the the uri of the file and or the filename. What drupal function can I use to get thee actual public URL of the file?.

```
$videouri = db_query('SELECT filename FROM `file_managed` WHERE fid = ' . $nidvideo)->fetchColumn();
//drupal_set_message('<pre>'. print_r($videourl, TRUE) .'</pre>');
$realpath = drupal_realpath($videouri);
$videourl = file_create_url($realpath);
return($videourl);

```

# Answer
> 20 votes
What do you mean by "public URL" exactly ?

file\_create\_url() can give the absolute URL to the image out of the box.

```
$videouri = db_query('SELECT uri FROM {file_managed} WHERE fid = :nidvideo', array(':nidvideo' => $nidvideo))->fetchColumn();
//drupal_set_message('<pre>'. print_r($videourl, TRUE) .'</pre>');
$videourl = file_create_url($videouri);

```

`file_create_url()` expects a valid uri. `drupal_realpath()` gives the server path which does not work.

I also changed your database query to avoid any SQL injection vulnerable.

# Answer
> 10 votes
Don't use `drupal_realpath()` as it has been deprecated now.

Either of the following can be used:

**1**. (`file_stream_wrapper_get_instance_by_uri($uri)`):

```
$uri = $field[0]['uri'];  // file path as uri: 'public://';
if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
  $path = $wrapper->realpath();
}

```

**2**. (`file_create_url($uri)`):

```
$uri = $node->field_video['und'][0]['uri'];  // file path as uri: 'public://';
$video_path = file_create_url($uri);

```

# Answer
> 4 votes
Check the following example:

```
$url = file_stream_wrapper_get_instance_by_uri($filepath)->getExternalUrl()

```

See: API for DrupalPublicStreamWrapper.

Related:

# Answer
> 2 votes
In Drupal 8 you can use the `file_url_generator` service

```
Drupal::service('file_url_generator')->generateAbsoluteString($uri)

```

Because the `file_create_url($uri)` function is deprecated since 9.3:

https://www.drupal.org/node/2940031

---
Tags: 7, files, uri
---


# Question
Title: How do I move a node's tags to be near its author information in my Bartik subtheme
I want to style a node's author data and tags slightly differently to the Bartik theme in Drupal 9.3. That is, rather than:

```
Submitted by user1 on Mon, 1/1/70
Tags
  foo
  bar

```

I'd like to have:

```
Submitted by user1 at Mon, 1/1/70 on foo | bar

```

So far, I have created a subtheme `tweak` with the following definition in `tweak.info.yml`:

```
name: Tweak
type: theme
description: This is a sub-theme of Bartik
core_version_requirement: ^8 || ^9
base theme: bartik
version: '9.3.0'

regions:
  header: Header
  primary_menu: 'Primary menu'
  ...

```

I have copied the following templates into my subtheme and modified them:

```
templates/node.html.twig
templates/field--taxonomy-vocabulary-1.html.twig

```

I have enabled my subtheme and I can confirm that the overriding templates are being executed. That is, I get the following:

```
Submitted by user1 at Mon, 1/1/70
on foo | bar

```

Unfortunately, there is a lot of HTML in between the two lines, ie.

```
<span>
  Submitted by
<span class="field field--name-uid field--type-entity-reference field--label-hidden">
<span lang="" about="/user/2" typeof="schema:Person" property="schema:name" datatype="">user1</span>
</span>
at
<span class="field field--name-created field--type-created field--label-hidden">Mon, 1/1/70 - 16:29</span>
</span>

</div>
  </header>
 <div class="node__content clearfix">
   <div class="field field--name-taxonomy-vocabulary-1 field--type-entity-reference field--label-above clearfix">
 on
  <a href="/taxonomy/term/7" hreflang="en">foo</a>
 | <a href="/taxonomy/term/2" hreflang="en">bar</a>
  </div>

```

What I'd like to have is the output from `field--taxonomy-vocabulary-1.html.twig` within the same `<div>` as the `Submitted by ...` content. However, I cannot see how to do that. Can anyone give me some pointers?

# Answer
@khummari's answer didn't work for me. However, I was able to adapt it.

I continued to use `field--taxonomy-vocabulary-1.html.twig` to theme the tags as I desired.

I then modified `node.html.twig` as follows. I used

```
{{ content.taxonomy_vocabulary_1 }}

```

to render the tags in my desired location. To prevent them rendering in their default location, I rendered the node's content as follows:

```
{{ content|without('taxonomy_vocabulary_1') }}

```

This feels like a bit of a hack though. Does anyone have a better suggestion?
> 1 votes

# Answer
In node--article.html.twig override in your theme's template directory as follow

Then override the tags field twig template as follow

following should be the result
> 0 votes

---
Tags: theming, nodes, taxonomy-terms
---


# Question
Title: Execute a behavior only once per page load
Moving from Dupal 7 to 9, I'm having a problem with javascript behaviors being called multiple times. In the browser console, when I load a page, I'm seeing:

```
process test for [object HTMLDocument] pet_guides.js:27:15
process test for [object HTMLUListElement] pet_guides.js:27:15
process test for https://whiskerdocs-local-d9.pglatz.com/portal/config/user-interface/shortcut/manage/default/customize pet_guides.js:27:15
process test for [object HTMLUListElement] 2 pet_guides.js:27:15
process test for [object HTMLElement] 2 pet_guides.js:27:15

```

This is my code:

```
  Drupal.behaviors.guideTest = {
    attach: function (context, settings) {
      console.log('process test for ' + context);
    }
  };

```

I'm looking at the docs on drupal.org and it isn't making sense to me yet. What I reall want to do is where console.log in to run a loop like

```
  $.each($('.section-wrapper'), function(index) {
    $(this).addClass('foo');
  });

```

What is the correct syntax to use a once() to make this execute only one time? If I had a behavior with more than one loop, is there a way to use a single once() wrapper arond them all, or would each look need its own? I thought using a behavior was like using `jQuery(document).ready(function ($)`, so the code would only be executed when the DOM was fully loaded, and don't understand why it is being called for five different contexts.

# Answer
> I thought using a behavior was like using jQuery(document).ready(function ($), so the code would only be executed when the DOM was fully loaded, and don't understand why it is being called for five different contexts.

No. If it would be like this, behaviors would be pointless.

1. Behaviors are tied to a single DOM node, because in Drupal you don't know when this DOM node is rendered/injected in the page (remember BigPipe, Ajax Views, Ajax shopping carts, etc).
2. Behaviors are fired first time after DOM ready, AND potentially very often afterwards when new partials are injected into the DOM. To avoid duplicating event listeners on pre-existing, older nodes use the `once`-function.
3. The `context` just makes it faster to de- and re-attach the behaviors, if you omit the context, any injection of a DOM node has to search the entire document for potential behaviors, and not just inside the context of the newly injected partial.
4. The equivalent of `$(document).ready()` would be calling `$(document, context).once()` inside a behavior, because the document-context is passed only once.

Your loop code would look like this:

```
Drupal.behaviors.myCustomBehavior= {
  attach: function (context, settings) {
    $('.section-wrapper', context).once('myCustomOnceId').each( function(index) {
      $(this).addClass('foo');
    });
  }
};

```

So, e.g. if your `<div class="section-wrapper">` is inside a row of an infinite scroll view, every `<div>` will get exactly one `foo` class, no matter when it is loaded.

Continuing the example above with the infinite scroll view and the "foo" class, after 2 Ajax injections...

...without using a behavior, you would end up with something like
`<div class="section-wrapper foo"></div><div class="section-wrapper"></div><div class="section-wrapper"></div>`

...using a behavior without `once`, you would end up with something like
`<div class="section-wrapper foo foo foo"></div><div class="section-wrapper foo foo"></div><div class="section-wrapper foo"></div>`
> 2 votes

---
Tags: javascript
---


# Question
Title: Programmatically find out field name of an Id-field
Depending on the type of entity, it is either nid/vid/uid and possibly other. It is nice to have an `->id()` method which allows you to work with data in an uniform fashion without relying on those details, but there are quite some use-cases, where I am running into troubles.

Just an example, getting list of revision ids for an generic entity seems not possible without knowing the name of the id-field.

```
$entityTypeId = $entity->getEntityTypeId();
$entityId = $entity->id();

$typeStorage = \Drupal::entityTypeManager()->getStorage($entityTypeId);

$query = $typeStorage->getQuery();
$query->allRevisions();
$query->condition("??????", $entityId);

```

# Answer
EntityType provides a function to get field keys: `EntityType::getKeys`. The result is an array and the `id` key identifies the property name of the primary field.

See https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21EntityType.php/function/EntityType%3A%3AgetKeys
> 3 votes

---
Tags: entities
---


# Question
Title: Custom AJAX Response not firing on Flag action
I'm trying to run custom javascript functions at the same time as people interact with certain flags on my site, I have followed this tutorial on how to respond to both Flag/Unflag actions, and this site for how to setup the custom ajax responses, except it just doesn't appear to be able to combine the two

The code inside my FlagSubscriber.php file (from the first tutorial link) looks like the below

```
class FlagController implements EventSubscriberInterface {

    public function onFlag(FlaggingEvent $event) {
      dpm('Test Text');

      $response = new AjaxResponse();
      $response->addCommand(
        new ExampleCommand()
      );
      return $response;
    }

    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents() {
      return [
        FlagEvents::ENTITY_FLAGGED => [['onFlag']]
      ];
    }
  }

```

It runs the dpm text the next time the page is loaded, but it doesn't seem to be running my custom Ajax response at all, even if I try running a standard Ajax Response from here. Are there some places that you can't run these kind of Ajax Response requests?

**EDIT**

For those wondering how to do the same thing, look into what the accepted response mentions about altering the route, because you basically need to overwrite how flag does its job and add your code as an extension of it.

So, I have a `RouteSubscriber.php` file with the following

```
namespace Drupal\my_module\Routing;

  use Drupal\Core\Routing\RouteSubscriberBase;
  use Symfony\Component\Routing\RouteCollection;

  /**
   * Listens to the dynamic route events.
   */
  class RouteSubscriber extends RouteSubscriberBase {

    /**
     * {@inheritdoc}
     */
    protected function alterRoutes(RouteCollection $collection) {
      // We need to take control of the default methods for the Flag controller so that we can hook into it's actions and add our own
      if ($route = $collection->get('flag.action_link_flag')) {
        $route->setDefault('_controller', 'Drupal\my_module\Controller\FlagController::flag');
      }
      if ($route = $collection->get('flag.action_link_unflag')) {
        $route->setDefault('_controller', 'Drupal\my_module\Controller\FlagController::unflag');
      }
    }
  }

```

Then I have a `FlagController.php` with code such as

```
namespace Drupal\my_module\Controller;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\flag\FlagInterface;
use Drupal\flag\Controller\ActionLinkController;

/**
 * Controller responses to flag and unflag action links.
 *
 * The response is a set of AJAX commands to update the
 * link in the page.
 */
class FlagController extends ActionLinkController {
  /**
   * Performs a flagging when called via a route.
   *
   * @param FlagInterface $flag
   *   The flag entity.
   * @param int $entity_id
   *   The flaggable entity ID.
   *
   * @return AjaxResponse|null
   *   The response object, only if successful.
   **/
  public function flag(FlagInterface $flag, $entity_id) {
    $response = parent::flag($flag, $entity_id);
    // The line above means your code still does what Flag needs to do, so you need to keep this in, or you'll stop flag working

    // Now you can add your own commands based on this link, like below
    https://www.drupal.org/docs/drupal-apis/ajax-api/core-ajax-callback-commands
    $response->addCommand(new EntityAddCommand($foo, $bar, $baz));

    //'EntityAddCommand' is something I wrote in my own javascript function

    return $response;
  }

  /**
   * Performs a unflagging when called via a route.
   *
   * @param FlagInterface $flag
   *   The flag entity.
   * @param int $entity_id
   *   The flaggable entity ID.
   *
   * @return AjaxResponse|null
   *   The response object, only if successful.
   **/
  public function unflag(FlagInterface $flag, $entity_id) {
    $response = parent::unflag($flag, $entity_id);

    //.... etc, do your own commands for unflagging

    return $response;
  }

```

# Answer
> 2 votes
The flagging events don't deal with responses, so you won't be able to return one from there. A different approach is to create a route subscriber, and alter the `flag.action_link_flag` and `flag.action_unlink_flag` routes, replacing the controller with your own custom one, e.g.

```
protected function alterRoutes(RouteCollection $collection) {
  if ($route = $collection->get('flag.action_link_flag')) {
    $route->setDefault('_controller', 'Drupal\custom_module\Controller\CustomController::flag');
  }
  if ($route = $collection->get('flag.action_link_flag')) {
    $route->setDefault('_controller', 'Drupal\custom_module\Controller\CustomController::unflag');
  }
}

```

Your custom controller would extend the original flag controller (`Drupal\flag\Controller\ActionLinkController`), use its methods to generate the original response, and then just tack your JS command(s) onto the end.

```
class CustomController extends ActionLinkController {

  public function flag(FlagInterface $flag, $entity_id) {
    $response = parent::flag($flag, $entity_id);
    $response->addCommand(...);
    return $response;
  }

  // Same for unflag()

}

```

For full coverage, you might also need to do something similar to the `flag.action_link_flag_nojs` and `flag.action_link_unflag_nojs` routes. But if your functionality is purely JS and doesn't need to be present for users without it, probably no need to bother.

---
Tags: 8, ajax, flags
---