title: Alter Services JSON Response

text:
# Question
Title: Alter Services JSON Response
I have created a view to render all taxonomy terms and displayed it through a service. I have also created an endpoint in the service module to hit the url through firefox add-on RESTer to test the JSON response. Now I want to alter the JSON response to add more key and value programatically. I am sharing all my resources which I have used but nothing changed

This is my JSON response so far:

```
[
        {
            "Name": "<a href=\"/forum/1\">General discussion</a>",
            "tid": "1",
            "description": ""
        },
        {
            "Name": "<a href=\"/forum/2\">Miscellaneous - Hangout forums</a>",
            "tid": "2",
            "description": ""
        },
        {
            "Name": "<a href=\"/forum/3\">Debt Management and Debt Consolidation</a>",
            "tid": "3",
            "description": ""
        },
        {
            "Name": "<a href=\"/forum/6\">Archive</a>",
            "tid": "6",
            "description": ""
        }

```

But I want my JSON like this:

```
[
        {
            "Name": "<a href=\"/forum/1\">General discussion</a>",
            "tid": "1",
            "description": "",
            "MY_CUSTOM_KEY": "MY CUSTOM VALUE"
        },
        {
            "Name": "<a href=\"/forum/2\">Miscellaneous - Hangout forums</a>",
            "tid": "2",
            "description": "",
            "MY_CUSTOM_KEY": "MY CUSTOM VALUE"
        },
        {
            "Name": "<a href=\"/forum/3\">Debt Management and Debt Consolidation</a>",
            "tid": "3",
            "description": "",
            "MY_CUSTOM_KEY": "MY CUSTOM VALUE"
        },
        {
            "Name": "<a href=\"/forum/6\">Archive</a>",
            "tid": "6",
            "description": "",
            "MY_CUSTOM_KEY": "MY CUSTOM VALUE"
        }
]

```

I had used hook\_views\_pre\_render to alter the JSON but couldn't get it:

```
function MY_MODULE_views_pre_render(&$view) {
    if($view->name == 'MY_VIEW_NAME') {
        $results = &$view->result;
        foreach($results as $key=>$value) {
            $value->MY_CUSTOM_KEY= "MY CUSTOM VALUE";
        }
    }
}

```

# Answer
Try

```
foreach($results as $key => &$value) {
    $value->MY_CUSTOM_KEY= "MY CUSTOM VALUE";
}

```
> 0 votes

# Answer
This hook solved my question: hook\_views\_post\_render

```
function MY_MODULE_views_post_render(&$view, &$output, &$cache) {
    if($view->name == 'MY_VIEW_NAME') {
        $results = &$output;
        foreach($results as $result) {
            $result->MY_CUSTOM_KEY= "MY CUSTOM VALUE";
        }
    }
}

```
> 0 votes

---
Tags: 7, views, services
---


# Question
Title: How to round the total price, display without decimal?
I need to count on decimal places (tax, promotion, fee ...), but the total price must be mathematically rounded without decimals.

Example:
2 x product1 CZK 424.00
1 x Product2 CZK 408.00

Subtotal CZK 832.00
Shipping CZK 99.00
Discount CZK -41.60
10% VAT CZK 71.86
21% VAT CZK 17.18
-Total CZK 889.40- *remove*
Rounded CZK - 0.60 *it is not necessary to display*
Total CZK 889.00

# Answer
this solved my problem: https://www.drupal.org/project/commerce/issues/3076196

## my module:

roundingmodule.info

```
name: Commerce rounding module.
type: module
description: Rounding.
core: 8.x
package: Custom

```

roundingmodule.services.yml

```
services:
  roundingmodule.rounding_order_processor:
    class: Drupal\roundingmodule\RoundingOrderProcessor
    tags:
      - { name: commerce_order.order_processor, priority: -10 }

```

roundingmodule.commerce\_adjustment\_types.yml

```
rounding:
  label: 'Rounding'
  singular_label: 'rounding adjustment'
  plural_label: 'rounding adjustments'
  has_ui: true
  weight: 20

```

src/RoundingOrderProcessor.php

```
    <?php

namespace Drupal\roundingmodule;

use Drupal\commerce_order\Adjustment;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_order\OrderProcessorInterface;

/**
 * Processes the order's shipments.
 */
class RoundingOrderProcessor implements OrderProcessorInterface {

  /**
   * {@inheritdoc}
   */
  public function process(OrderInterface $order) {

      $rounder = \Drupal::service('commerce_price.rounder');
      $order_total = $order->getTotalPrice();
      $rounded_total = $rounder->round($order_total->divide(100))->multiply(100);
      $difference = $rounded_total->subtract($order_total);

      $order->addAdjustment(new Adjustment([
        'type' => 'rounding',
        'label' => 'Rounding',
        'amount' => $difference,
      ]));
  }

}

```
> 1 votes

---
Tags: 8, commerce
---


# Question
Title: Have a child node inherit taxonomy from a parent during /node/add?
In Drupal 7, I have two content types:

1. **Parent Events** with tags (like "outdoors" or "popular" or "suitable for kids"). "Tags" are taxonomy terms in a vocabulary, connected via an Entity Reference field `field_parent_tags` (using the Checkboxes widget).
2. **Child Events** with the same tags & reference in `field_child_tags`. Each Child also has a mandatory Entity Reference to a Parent Event, `field_parent_event` (using the Autocomplete widget).

I'm trying to have new Child Events automatically inherit their parent's tags when they're first created. For example:

* There is a Parent Event called "Weddings", which has the tags "suitable for kids" and "popular".
* When I make a new Child Event called "Joe & Sarah's Beach Wedding", I'd like it to automatically inherit the tags "suitable for kids" and "popular". Then I'd add the "outdoors" tag to this specific child event, which would apply only to this child and not the parent.
* (Another child event might be someone else's wedding, and not suitable for kids, so I'd uncheck that in the child event).

How would I go about doing that? So far, I think I need to implement some variation of `hook_form_alter()`, possibly overriding its `#ajax` call so that as soon as the child event's `form_parent_event` is filled out, its `field_child_tags` will copy the values from `field_parent_tags`.

Am I going down the right path? I can't figure out where to put that code, if so. I tried overriding `/node/add/childevent` using a `page--node--add-child-event.tpl.php` file, but it seems to have no effect. A little lost :(

Any help would be very much appreciated. Thank you!

# Answer
I ended up using the Rules module for this. It couldn't do it in AJAX when the parent field was specified, but it could make this happen as soon as the child was first saved, and only if its taxonomies were left blank.

The main rule fires a Ruleset component when a child event is saved, and if the parent event is specified. This Ruleset has two parameters: 1) the parent node and 2) the child node.

Next, the Ruleset component just fires two child rules one after another, one for each set of taxonomy terms:

Finally, each individual child rule checks to see if the child event left its taxonomy blank, and if so, sets it to the parent's. I needed one child rule per taxonomy, so that the empty conditions could be checked individually.

That's it! New child events, upon saving, would get the parent tags if it had none of its own.

The code for the rule:

```
{ "rules_inherit_parent_event_taxonomies" : {
    "LABEL" : "Inherit Parent Event Taxonomies",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "ON" : { "node_insert--event" : { "bundle" : "event" } },
    "IF" : [
      { "node_is_of_type" : { "node" : [ "node" ], "type" : { "value" : { "event" : "event" } } } },
      { "NOT data_is_empty" : { "data" : [ "node:field-program" ] } }
    ],
    "DO" : [
      { "component_rules_set_child_taxonomies" : { "parent_node" : [ "node:field-program" ], "child_node" : [ "node" ] } }
    ]
  }
}

```

And the ruleset component:

```
{ "rules_set_child_taxonomies" : {
    "LABEL" : "Set Child Taxonomies",
    "PLUGIN" : "rule set",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "USES VARIABLES" : {
      "parent_node" : { "label" : "Parent Node", "type" : "node" },
      "child_node" : { "label" : "Child Node", "type" : "node" }
    },
    "RULES" : [
      { "RULE" : {
          "IF" : [
            { "node_is_of_type" : {
                "node" : [ "parent-node" ],
                "type" : { "value" : { "program" : "program" } }
              }
            },
            { "node_is_of_type" : {
                "node" : [ "child-node" ],
                "type" : { "value" : { "event" : "event" } }
              }
            },
            { "data_is_empty" : { "data" : [ "child-node:field-topic" ] } }
          ],
          "DO" : [
            { "data_set" : {
                "data" : [ "child-node:field-topic" ],
                "value" : [ "parent-node:field-topic" ]
              }
            }
          ],
          "LABEL" : "Inherit parent\u0027s topics if child has none"
        }
      },
      { "RULE" : {
          "IF" : [
            { "node_is_of_type" : {
                "node" : [ "parent-node" ],
                "type" : { "value" : { "program" : "program" } }
              }
            },
            { "node_is_of_type" : {
                "node" : [ "child-node" ],
                "type" : { "value" : { "event" : "event" } }
              }
            },
            { "data_is_empty" : { "data" : [ "child-node:field-audience" ] } }
          ],
          "DO" : [
            { "data_set" : {
                "data" : [ "child-node:field-audience" ],
                "value" : [ "parent-node:field-audience" ]
              }
            }
          ],
          "LABEL" : "Inherit parent\u0027s audiences if child has none"
        }
      }
    ]
  }
}

```
> 0 votes

---
Tags: 7, theming, entities, taxonomy-terms, ajax
---


title: Drupal 8 views watchdog issues

text:
# Question
Title: Drupal 8 views watchdog issues
I found a couple of issues with the Drupal 8 integration of watchdog support for views and don't know where to report them. The views watchdog project page only shows issues for the 7.x version.

1. With an exposed filter for the message field, you can't get results for words within an em tag (like a module name). In some cases, even plain text can't be searched for. Example: message is "Starting execution of backup\_migrate\_cron()." I can search for messages with "execution" but no for "backup\_migrate\_cron()" or "backup".
2. VBO is not supported for this view type.

# Answer
Views issues are tracked in the Core issue queue. The VBO issue might make more sense in the VBO module issue queue, since it might need to be accommodated by the module itself.
> 0 votes

---
Tags: views
---


# Question
Title: How can I automatically flag new comments?
I have a Drupal 8 site with Flag and Rules modules. How to flag a new comment ?

I want that when a user creates a comment, the comment should be automatically flagged.

I created a type of Flag on the comments and I created a rule with the event "When a new comment is posted".

What should I put in action ?

# Answer
Flag ID should be the ID of the flag being set. If you go to /admin/structure/flags, and Edit the flag, the machine name/ID of the flag will be at the end of the URL -- so /admin/structure/flags/manage/{flag\_id}.

I've not used Rules on D8, but for Entity ID, if you click "switch to data selection" and then click the field, I think it should give you some autocomplete options to help select the data you want. You'll likely end up with something like "comment:id".
> 0 votes

---
Tags: 8, rules, comments, flags
---


# Question
Title: How can I limit query results in hook_views_pre_execute?
I am developing a Drupal 8 website where I have a block view displayed for certain content types that shows related information from other content types. I need to dynamically limit query results based on the moderation state of the node being visited (as opposed to the content in the view). My plan was to grab the node's moderation state from the page context and use that to limit the results of the view. However, the setLimit function seems to have no effect on query results:

```
function myModule_views_pre_execute(ViewExecutable $view) {
  // Only for my_view view.
  if ($view->id() == 'my_view') {
    $list_node = Drupal::request()->attributes->get('node');
    if($list_node->moderation_state->value == "approved"){

    }else{
      dpm("node is not approved, setting limit to 0");
      $view->query->setLimit(0);
    }
  }

```

**UPDATE**

I played around with trying different things in different hooks, inspecting the actual query generated via the view editing interface, as this exposes the "LIMIT #" expression. I learned 2 main things from that process:

1. Things can and will edit the query in other hooks. I found that putting the `setLimit` in `hook_views_query_alter` got overridden by some other module, and by the time `hook_views_pre_execute` came around, it would be changed from what I set it to earlier. However setting it in `pre_execute` is working fine.
2. Amazingly, calling `setLimit(0)` **removes the LIMIT expression from the query entirely!** However, any other value seems to work fine.

Is this expected behavior? Does Drupal prohibit setting the limit for a query to 0? Or should I be logging an issue somewhere?

# Answer
> 0 votes
No idea why setLimit(0) doesn't work as expected, but an alternative is to *act as though* you had limited the results to 0. When you add a contextual filter to a view, one of the options for *When the filter value is NOT available* is to *Display contents of "No results found"*. This seems to be handled by ArgumentPluginBase::defaultEmpty(), which looks like

```
public function defaultEmpty() {
  // We return with no query; this will force the empty text.
  $this->view->built = TRUE;
  $this->view->executed = TRUE;
  $this->view->result = [];
  return FALSE;
}

```

If you drop this snippet into `hook_views_query_alter()` it appears to work exactly the same! I'd wager that you could drop it into any of the views hooks, actually, and it would have the same effect.

EDIT: Whoops, forgot to say you'd want to replace `$this->view` with `$view` if you're inside of the hooks.

---
Tags: 8, views, hooks
---


title: Change data export download link label

text:
# Question
Title: Change data export download link label
I want to change the label shown to export csv file download link that generated with data export of a view. I didn't get any setting to change the label of download link - download full list.

# Answer
The download button is actually rendered from a twig template found at `/views_data_export/templates/export-icon.html.twig`. This means that you can override it in your theme by copying that file to `/themes/YOUR_THEME/templates/export-icon.html.twig` and modifying it to what you need.

You can of course put that twig file into any subdir of `/templates/` that makes sense to you - e.g. `/templates/views_data_export/export-icon.html.twig` will work as well.
> 3 votes

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


# Question
Title: How to force a JS library to be loaded via HTTPS?
How can I force a js library to always load only via SSL?

Specifically, I want to get Drupal to always load stripe.js with SSL, because stripe.js refuses to load over http (you get a 403 FORBIDDEN error).

I'm loading stripe.js through the Commerce Stripe module.

`commerce_stripe.libraries.yml` looks like this:

```
stripe:
  remote: https://github.com/stripe/stripe-php
  version: "4.3.0"
  license:
    name: MIT
    url: https://github.com/stripe/stripe-php/blob/master/LICENSE
    gpl-compatible: true
  js:
    "https://js.stripe.com/v3/": { minified: true }

```

So I thought this would be sufficient to always load via SSL.

On my production site, for which all the assets are SSL, everything works.

On Lando, my local development environment, everything is fine when I access my site from a browser installed on my machine, even when the connection to the locally hosted website is http (connection to my dev site is http, connection to stripe.js is https).

However, when using the Standalone Chrome Debug docker image to test my site with Behat, stripe.js doesn't load. I get a 403 FORBIDDEN error because the Chrome browser in the Standalone Chrome Debug container tries to load stripe.js via http.

From the Chrome browser with the problem, this is what the `<script>` tag looks like for stripe.js:

```
<script src="//js.stripe.com/v3/"></script>

```

I'm not sure exactly why I am having this problem only with the Standalone Chrome Debug docker image, but I suspect it is because I cannot access my site via https from the image at all. However, in the browser, I can open other SSL sites such as https://www.google.com and perform a search without any problems.

So,

* If I am accessing a local installation of Drupal via docker from inside a docker container
* And I do not have access to the Drupal installation via HTTPS
* **Is it impossible to load a third-party js library (stripe.js) via HTTPS?**

The reason I'm confused is that I can load stripe.js locally when accessing my site via a browser in Windows (my dev machine) through http, but in the Docker container (standalone-chrome-debug), accessing my local dev site through http gets a 403 forbidden for stripe.js. (When I manually type the stripe.js library link into the browser, I can download the library, so the problem only occurs with the link/connection generated by Drupal.)

# Answer
That's a protocol relative include, meaning it will take the current protocol and use that. If you access via http, that's what you would get. Is the site being tested under https? Is something removing the protocols (advagg?)?

Modules like advanced aggregation have settings to remove protocol and make all links protocol relative. Disable settings like that and run the tests again.
> 2 votes

---
Tags: 8, javascript, http-request
---


# Question
Title: Composer killed when installing a module
* I am actually running Drupal on a LAMP (XUbuntu 20-04 with 4 GB RAM in VirtualBox)
* At the beginning of the installation I had no problem with installing dependencies using composer
* But since yesterday every composer command gets killed like in the following code (entity print installation):

```
igpde@igpde-VirtualBox:/var/www/html/d8igpde2$ composer require dompdf/dompdf
Using version ^0.8.6 for dompdf/dompdf
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Killed

```
* I thought it could be a memory problem but in the php 7.4 client installation:
    + I read -1 should mean *no limit*

```
; Maximum amount of memory a script may consume (128MB)
; http://php.net/memory-limit
memory_limit = -1

```
* Any Id how I could solve this problem?

Thanks in advance for you suggestions

* Running with the vvv flag:

```
igpde@igpde-VirtualBox:/var/www/html/d8igpde2$ composer -vvv require dompdf/dompdf | tee composer.log
Reading ./composer.json
Loading config file ./composer.json
Checked CA file /etc/ssl/certs/ca-certificates.crt: valid
Executing command (/var/www/html/d8igpde2): git branch --no-color --no-abbrev -v
Executing command (/var/www/html/d8igpde2): git describe --exact-match --tags
Executing command (CWD): git --version
Executing command (/var/www/html/d8igpde2): git log --pretty="%H" -n1 HEAD --no-show-signature
Executing command (/var/www/html/d8igpde2): hg branch
Executing command (/var/www/html/d8igpde2): fossil branch list
Executing command (/var/www/html/d8igpde2): fossil tag list
Executing command (/var/www/html/d8igpde2): svn info --xml
Failed to initialize global composer: Composer could not find the config file: /home/igpde/.config/composer/composer.json
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
Reading /var/www/html/d8igpde2/vendor/composer/installed.json
Loading plugin Drupal\Composer\Plugin\ProjectMessage\MessagePlugin
Loading plugin Drupal\Composer\Plugin\Scaffold\Plugin
Loading plugin Drupal\Console\Composer\Plugin\Extender
Loading plugin Composer\Installers\Plugin
Running 1.10.9 (2020-07-16 12:57:00) with PHP 7.4.3 on Linux / 5.4.0-42-generic
Downloading https://packages.drupal.org/8/packages.json
Writing /home/igpde/.cache/composer/repo/https---packages.drupal.org-8/packages.json into cache
Downloading https://repo.packagist.org/packages.json
Writing /home/igpde/.cache/composer/repo/https---repo.packagist.org/packages.json into cache
Reading /home/igpde/.cache/composer/repo/https---packages.drupal.org-8/drupal-provider-2020-3.json from cache
Reading /home/igpde/.cache/composer/repo/https---packages.drupal.org-8/drupal-provider-2020-2.json from cache
Reading /home/igpde/.cache/composer/repo/https---packages.drupal.org-8/drupal-provider-2020-1.json from cache
...............................................
Reading /home/igpde/.cache/composer/repo/https---repo.packagist.org/provider-sabberworm$php-css-parser.json from cache
Killed

```
* the preceding output is very long
* It waits a lot of time before declaring **Killed**. looks like a time out!
* except for the last reading every **Reading** ... happens fast

# Answer
> 2 votes
You ran out of memory. This happens all the time with Composer.

Composer is a huge memory hog, especially when used with Drupal because of all the external interdependencies. And Drupal's requirements continue to grow with every new release, so the memory needed to use Composer with Drupal continues to grow. 4Gb of *available* memory should be enough, currently, but 2Gb is not enough in my experience. I find this problem can be avoided if you configure your system with sufficient swap space (2x physical memory is usually sufficient). This is for a development system of course - you won't be using Composer to install modules like that on a production system, you should be using a .lock file instead, so Composer's memory requirement will be much smaller.

---
Tags: installation, composer, 9
---


# Question
Title: EventSubscriber returning correct content but status code is 404
As the title says, content is being returned correctly but the status code is `404`.

I have checked the .htaccess file and the Apache config file as well. All seems to be fine.

I have the following in my module routing file:

```
my_module.news_list:
  path: /api/{state}/news
  defaults:
    _controller: Drupal\my_module\Controller\NewsController::index
  methods: [GET]
  requirements:
    _access: 'TRUE'

```

This is the function that does the redirect in my EventSubscriber

```
public function redirectRequestToModule(GetResponseEvent $event) {
            $request = $event->getRequest();
            $validPathBegins = ['/men', '/nat'];
            // This is necessary because this also gets called on
            // node sub-tabs such as "edit", "revisions", etc.  This
            // prevents those pages from being redirected.
            $requestUri = $request->getRequestUri();
            if (!in_array(substr($requestUri, 0, 4), $validPathBegins)) {
                return;
            }

            $node = $request->attributes->get('node');

            // get the configured request query parameters for this content type

            $redirect_url = '/api' . $requestUri;
            $kernel = $event->getKernel();
            $response = $kernel->handle(Request::create($redirect_url));
            $event->setResponse($response);
        }

```

This is what I type in the browser: `mysite.com/nat/news/`

The content returned is correct but the status code is `404`.

P.S There isn't a reachable path on my Drupal website like `/nat/news`. The path mentioned is supposed to return a list of news articles.

# Answer
> 2 votes
Creating an alias in `/admin/config/search/path/add` worked. I created an alias `/api/nat/news/` to `/nat/news`

Thanks 4k4 for a much easier solution drupal.stackexchange.com/a/187497/47547

---
Tags: 8, routes, redirection, event-subscribers
---


# Question
Title: run-tests.sh error: Test class not found
Hi and thanks in advance for your patience - I really appreciate the patience this community has shown me despite my silly questions. I'm using Drupal 9 and have just read this tutorial on unit testing in Drupal 7, but it doesn't seem to be working for me. It's unclear to me whether I'm doing something wrong or the instructions simply aren't valid anymore:

```
www-data@fa5bab330dc3:/opt/drupal/web$ php core/scripts/run-tests.sh --verbose --url http://example.com/ --class "Drupal\Tests\rsvplist\Unit\RSVPListServiceTest"
  ERROR: Test class not found: Drupal\Tests\rsvplist\Unit\RSVPListServiceTest

```

I have tried pointing `run-tests.php` to a specific directory but that doesn't seem to work either:

```
www-data@fa5bab330dc3:/opt/drupal/web$ php core/scripts/run-tests.sh --verbose --url http://example.com/ --directory modules/custom/
  ERROR: No valid tests were specified.

```

I tried the above with variations on the directory, including `modules/custom/rsvplist` and `/opt/drupal/web/modules/custom/rsvplist/tests/src/unit/` (the location of the test file itself), but always got the same error.

When running unit tests via `phpunit` directly I seem to be able to get it to work:

```
www-data@fa5bab330dc3:/opt/drupal/web/core$ phpunit ../modules/custom/rsvplist
PHPUnit 8.0.0 by Sebastian Bergmann and contributors.

Testing ../modules/custom/rsvplist
R                                                                   1 / 1 (100%)

Time: 123 ms, Memory: 6.00 MB

There was 1 risky test:

1) Drupal\Tests\rsvplist\Unit\RSVPListServiceTest::testSomething
This test did not perform any assertions

/opt/drupal/web/modules/custom/rsvplist/tests/src/unit/EnablerServiceTest.php:14

/opt/drupal/vendor/phpunit/phpunit/src/Framework/TestResult.php:860
/opt/drupal/vendor/phpunit/phpunit/src/Framework/TestSuite.php:761
/opt/drupal/vendor/phpunit/phpunit/src/Framework/TestSuite.php:761
/opt/drupal/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:632
/opt/drupal/vendor/phpunit/phpunit/src/TextUI/Command.php:208
/opt/drupal/vendor/phpunit/phpunit/src/TextUI/Command.php:164

OK, but incomplete, skipped, or risky tests!
Tests: 1, Assertions: 0, Risky: 1.

```

I'd like to run my tests via `run-tests.sh` as I'd like to use the `Drupal\KernelTests\KernelTestBase` class so that I can mock out database connections, and as I understand it this should be done via `run-tests.sh` and not `phpunit`. Obviously I'd like to resolve the errors above but I'm also happy to be shown a different / better way of achieving what I'm trying to do.

Here is my test class, located in modules/custom/rsvplist/tests/src/unit/EnablerServiceTest.php:

```
<?php

namespace Drupal\Tests\rsvplist\Unit;

use Drupal\Tests\UnitTestCase;

class RSVPListServiceTest extends UnitTestCase {
  public function testSomething() {
  }
}

```

# Answer
The solution ended up being:

1. Make sure the test file is named as the test class, in this case `RSVPListServiceTest.php`.
2. Make sure my unit tests are placed in the correct directory structure, in my case my `RSVPListServiceTest.php` file had to be in `modules/custom/rsvplist/tests/src/Unit/EnablerServiceTest.php` (as opposed to `unit` with a lowercase `u`)

The *ERROR: No valid tests were specified.* message ended up being a bit of a red herring, and I've submitted a patch to drupal to make this message clearer: https://www.drupal.org/project/drupal/issues/3170651
> 1 votes

---
Tags: testing, 9
---


# Question
Title: Cogwheel / Gear button does not work on manage display pages on Drupal 8
I am new to Drupal and having some issues with the cogwheel button on all of content types when I want to manage their display. When I click the gear / cogwheel icon "please wait" message shows up for a second then then nothing happens, no options to change. I saw this log (not Drupal log, it does not shows up any logs related to this issue) below. (Using Drupal 8.9.5 with PHP 7.4.9 and 5.5.5-10.3.23-MariaDB)

```
16212958669271217639 xx.x8.xx.6x 8x 1xx.0.x.1 8x
--23480000-B--
POST /admin/structure/types/manage/urun/display?ajax_form=1&_wrapper_format=drupal_ajax HTTP/1.1
Connection: keep-alive
Content-Length: 2520
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: application/json, text/javascript, */*; q=0.01
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,tr;q=0.8,ru;q=0.7
Cookie: SESS5c14c0f7969f78d79c3fd3c7b705bf82=ENk2-oEjAYvOOg32skVHKKWcA6DPRgwPwOSP7w-bVXo
Host: xxxxxxx.com.tr
Referer: http://xxxxxxx.com.tr/admin/structure/types/manage/urun/display
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/xx.x8.xx.6x Safari/537.36 OPR/70.x.xxx8.1xx
X-Requested-With: XMLHttpRequest
Origin: http://xxxxxxx.com.tr

--23480000-F--
HTTP/1.1 500 Internal Server Error

--23480000-H--
Message: Access denied with code 403 (phase 1). Match of "rx ^%{tx.allowed_request_content_type_charset}$" against "TX:1" required. [file "C:\/Program Files (x86)/Plesk/ModSecurity/rules/modsecurity_crs-plesk/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "944"] [id "920480"] [msg "Request content type charset is not allowed by policy"] [data "utf-8"] [severity "CRITICAL"] [ver "OWASP_CRS/3.2.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/CONTENT_TYPE_CHARSET"] [tag "WASCTC/WASC-20"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/EE2"] [tag "PCI/12.1"]
Action: Intercepted (phase 1)
Apache-Handler: IIS
Stopwatch: 1599818735740733 0 (- - -)
Stopwatch2: 1599818735740733 0; combined=0, p1=0, p2=0, p3=0, p4=0, p5=0, sr=0, sw=0, l=0, gc=0
Producer: ModSecurity for IIS (STABLE)/2.9.2 (http://www.modsecurity.org/); OWASP_CRS/3.2.0.
Server: ModSecurity Standalone
Engine-Mode: "ENABLED"

--23480000-Z--

--23480000-A--
<< Less

```

UPDATE:

Error on JS console

```
jquery.min.js:2 POST https://xxxxxxx.com.tr/admin/structure/types/manage/urun/display?ajax_form=1&_wrapper_format=drupal_ajax 403
send    @   jquery.min.js:2
ajax    @   jquery.min.js:2
e.fn.ajaxSubmit @   jquery.form.min.js:22
Drupal.Ajax.eventResponse   @   ajax.js:332
(anonymous) @   ajax.js:271
dispatch    @   jquery.min.js:2
v.handle    @   jquery.min.js:2

```

Another Error Message

```
ajax.js:506 Uncaught Drupal.AjaxError {message: "↵An AJAX HTTP error occurred.↵HTTP Result Code: 40…r page using the credentials that you supplied.
↵", name: "AjaxError"}message: "↵An AJAX HTTP error occurred.↵HTTP Result Code: 403↵Debugging information follows.↵Path: /admin/structure/types/manage/urun/display?ajax_form=1↵StatusText: error↵ResponseText:
↵403 - Forbidden: Access is denied.
↵Server Error
↵403 - Forbidden: Access is denied.
↵You do not have permission to view this directory or page using the credentials that you supplied.
↵"name: "AjaxError"__proto__: Error
    at https://xxxxxxx.com.tr/core/misc/ajax.js?v=8.9.5:100:32
    at https://xxxxxxx.com.tr/core/misc/ajax.js?v=8.9.5:643:3
Drupal.Ajax.error @ ajax.js:506
complete @ ajax.js:241
t.complete @ jquery.form.min.js:22
c @ jquery.min.js:2
fireWith @ jquery.min.js:2
l @ jquery.min.js:2
(anonymous) @ jquery.min.js:2
load (async)
send @ jquery.min.js:2
ajax @ jquery.min.js:2
e.fn.ajaxSubmit @ jquery.form.min.js:22
Drupal.Ajax.eventResponse @ ajax.js:332
(anonymous) @ ajax.js:271
dispatch @ jquery.min.js:2
v.handle @ jquery.min.js:2

```

Full Error Text

```
"
An AJAX HTTP error occurred.
HTTP Result Code: 403
Debugging information follows.
Path: /admin/structure/types/manage/urun/display?ajax_form=1
StatusText: error
ResponseText:
403 - Forbidden: Access is denied.
Server Error
403 - Forbidden: Access is denied.
You do not have permission to view this directory or page using the credentials that you supplied.
"

```

# Answer
After a full day's work, I found a solution described below.

It looks like an issue caused by firewall policies on the server. Fortunately, I have an App on my server called 'Web Application Firewall' where you change the settings to somehow bypass this security check.

Read through the app's manual and find the security rule ID and add it to the appropriate text area below and hit apply. This will switch off the security rule causing the issue according to the ID you found.

App's Manual

> ModSecurity audit log The ModSecurity audit log file is the most useful piece of information in the system. When ModSecurity detects that any event occurs, it generates an entry in the audit log file.
>
> A website can stop functioning as expected after you change the web application firewall mode to On from Off or Detection only. In this case, analyze the ModSecurity audit log to find out what is happening. You can switch off too restrictive security rules or adjust the website.
>
> To find out why an HTTP request cannot be completed for a website:
>
> Click the ModSecurity Log File link below and open the audit log in a new browser window. Use Search (Ctrl+F in most web browsers) to find events for the website (the domain name) that experiences problems. For example, your\_domain.tld. The browser will highlight entries like HOST: your\_domain.tld. In three lines above the highlighted entry, find a string like --eece5138-B--. The eight symbols between hyphens (in our example, eece5138) are the ID of the event triggered by the HTTP request. Search further for other entries with the same event ID. Look for an entry with the letter H after the event ID (in our example, eece5138-H--). This entry contains the ID and description of the security rule triggered while checking the HTTP request. The security rule ID is an integer number starting with 3, in quotation marks, and put with the prefix id in square brackets. For example, \[id "340003"\]. Find a security rule ID in the event using a substring \[id "3. Switch off the security rule with this ID in the Security rules section below: enter the security rule ID (digits only) into the Security rule IDs field and click OK.
> 1 votes

---
Tags: ajax
---


title: Save customer information at checkout

text:
# Question
Title: Save customer information at checkout
My customers are required to provide an address at checkout (*Shipping information* pane). They can also create an account after checkout is complete (*Guest registration after checkout* pane).

But the *Customer information / Address* form is empty:

Is this normal behavior? Is it not supposed to pre-fill the form with the shipping info the customer provided during checkout? I couldn't find any option in Commerce settings.

Any idea on how I could make this happen? Do I need to implement it by myself?

* Drupal core: 8.9.3
* Commerce: 8.x-2.20

# Answer
Not sure this would be the recommended way but I got it working using `hook_form_alter`. Customers start by filling their shipping address at step 1 (required) and on `complete` step, I grab this shipping address and copy it to the `customer_information` address field on guest registration, so the customers don't need to fill the same address again. In case the customer address would be different, it can be modified at this step.

```
/**
 * Implements hook_form_alter().
 */
function MYMODULE_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // Commerce checkout form
  if ($form_id === 'commerce_checkout_flow_multistep_default') {

    // Multistep "complete" step
    if ($form['#step_id'] === 'complete') {

      // Get shipping address and copy it to customer profile address
      $profiles = $form_state->getFormObject()->getOrder()->collectProfiles();
      $shipping_address = $profiles['shipping']->address->getValue();
      $form['completion_register']['customer_profiles']['widget'][0]['entity']['address']['widget'][0]['address']['#default_value'] = reset($shipping_address);
    }
  }
}

```
> 1 votes

---
Tags: 8, forms, commerce
---


title: Token for user being viewed

text:
# Question
Title: Token for user being viewed
I am formatting the user profile page in Drupal 8.9.2.

Are tokens available for the user being viewed (in user profile page), to display the user information?

I am using the *Token* and the *Token Filter* modules for this. (edited: 8:44 AM 10 Sep 20)

# Answer
I have solved the problem this way.
(1) I created a **View** to show desired user information.
(2) Then, I added a '**Contextual filter**' to point to the user being viewed. (with the options "*User ID \> Provide default value \> Type: User ID from route context*")
(3) Then, I selected '**REWRITE RESULTS**' and "**Override the output of this field with custom text**". As a result *replacement tokens* become available for user fields. I used that for formatting the Information according to the requirement.
Then, I placed this View block at the desired place.
> 0 votes

---
Tags: users, tokens
---


# Question
Title: How can I get translation for a field of custom date
I am using the paragraphs module. I have a field which contains a date and time e.g. for events, which is added by an author. For the output I use a paragraph-twig-file and I have this:

```
<div class="timeline-date">
    {{ content.field_date }}
</div>

```

In the backend of Drupal I created a custom time "D, d.m.Y - H:i". The output is right e.g. "Fri, 24.08.2018 - 17:14", but my site is in german and not english. **So how, can I translate the day of week in german?** In my case this solution is not working

# Answer
In Twig, you can use built-in translation contexts. I had to output my dates in dutch format. The default formatting was:

```
{% set date = node.created.value|date("j") ~ ' ' ~ node.created.value|date("F") ~ ' ' ~ node.created.value|date("Y") %}
// now {{ date }} outputs: 8 August 2020

```

When I use translation contexts, it worked as expected:

```
{% set date = node.created.value|date("j") ~ ' ' ~ node.created.value|date("F")|t({}, {'context' : 'Long month name'}) ~ ' ' ~ node.created.value|date("Y") %}
// now {{ date }} outputs: 8 augustus 2020

```

More about translation contexts in Twig: https://stefvanlooveren.me/blog/translate-dates-twig-drupal-8
> 0 votes

# Answer
You need to do something like below screenshot in my case i have translated months of date field in french language.

you have to search for day string for different language like fri ,replace the text for each language in text box then save to path admin/config/regional/translate
> -1 votes

---
Tags: 8, i18n-l10n, datetime
---


# Question
Title: How to get the parameter value from an ajax call in the page controller?
I have the following js code according to es6.

```
(($, Drupal) => {
  Drupal.behaviors.mymodule = {
    attach: () => {
      document.querySelectorAll("a").forEach(element => {
        element.addEventListener("click", e => {
            fetch("/mypath", {
              method: "POST",
              body: JSON.stringify({
                path: $(this).attr("href")
              }),
            });
        });
      });
    }
  };
})(jQuery, Drupal);

```

and in the page controller:

```
public function content(\Symfony\Component\HttpFoundation\Request $request) {
  $path = $request->request->get('path');
}

```

But I am not getting the path. Can someone tell me how to get the path in my page controller?

# Answer
Why do you want to use `fetch()` when your code is based on jQuery? There a plenty of examples using `$.ajax()` for POST requests:

*/core/modules/quickedit/js/quickedit.es6.js*

```
  $.ajax({
    url: Drupal.url('quickedit/metadata'),
    type: 'POST',
    data: {
      'fields[]': fieldIDs,
      'entities[]': entityIDs,
    },
    dataType: 'json',
    success(results) {
      // Store the metadata.
      _.each(results, (fieldMetadata, fieldID) => {
        Drupal.quickedit.metadata.add(fieldID, fieldMetadata);
      });

      callback(fieldElementsWithoutMetadata);
    },
  });

```

*/core/modules/quickedit/src/QuickEditController.php*

```
  public function metadata(Request $request) {
    $fields = $request->request->get('fields');
    ...

```

To make PHP accept POST parameters you need to specify the correct request headers. Default in `$.ajax()` is the contentType `application/x-www-form-urlencoded`

So when using `fetch()` start with this:

```
fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },

```

To get on par with $.ajax() you might need to tweak fetch() a little more or wait until core decides to change the Ajax libraries from jQuery to pure Javascript.
> 2 votes

---
Tags: 8, javascript
---


# Question
Title: How do I change text on the submission button in the node form?
I'm trying to change the submit button text "Save and keep published", but with no luck. I'm using the standard `hook_form_FORM_ID_alter()`.

```
function mymodule_form_node_news_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  // This is the problem, what should I put here
  $form['actions']['publish']['#value'] == '';
}

```

This is what `dpm()` returns.

```
'publish' => array(7)
  '#value' => object Drupal\Core\StringTranslation\TranslatableMarkup(5)
    protected string -> string(18) "Save and keep published"
    protected translatedMarkup -> NULL
    protected options -> array(0)
    protected stringTranslation -> NULL
    protected arguments -> array(0)

```

How do I change text on the submission button in the node form?

# Answer
> 13 votes
In `#value` is a translatable string. You can override it with a simple text value:

```
if ( isset($form['actions']['publish']) ) {
   $form['actions']['publish']['#value'] = 'New Text';
}

```

Or you can put there a new translatable string with the t() function, if you want to translate the new string in different languages:

```
if ( isset($form['actions']['publish']) ) {
   $form['actions']['publish']['#value'] = t('New Text');
}

```

**Edit:** Answer the question in comments

What you see in dpm() is the result of t(), which is used in the original form in NodeForm.php:

```
$element['publish']['#value'] = t('Save and publish');

```

In D8 this is an object, which will result in the translated text when used in a string context. For the enduser you simply use it like a string value, but magically it will always be translated. You don't have to look into this object to find a way to change it. To set a new value you simply generate a new translatable object and put this into the place of the old one.

# Answer
> 0 votes
On Drupal 8.9.x you can go with

```
  $form['actions']['submit']['#value'] = t('Sign up');

```

which is working in `YOUR_MODULE.module` also

See https://www.drupal.org/forum/support/theme-development/2016-01-05/how-to-change-submit-button-text-in-registration-form#comment-13530797

---
Tags: 8, forms
---


# Question
Title: Prevent Multiple Form Submissions (Server side)
I'm running into a problem where a user can submit any form built by the Form API multiple times (fast clicking resulting in multiple requests).

I've put in the basic client side (javascript) solution of disabling the button, but I'm curious what the best approach to preventing this situation is on the server side.

Is there a recommended way to use Drupal's form token system to handle this? Especially a global form solution (ie, adding a custom validator to every form using hook\_form\_alter()).

My approach so far has been something like this:

```
function mymodule_form_alter(&$form, &$form_state, $form_id) {
  $form['#validate'][] = 'mymodule_form_validate';
}

function mymodule_form_validate(&$form, &$form_state){
  //initialize form array
  if (!isset($_SESSION['submitted_forms'])){
    $_SESSION['submitted_forms'] = array();
  }

  $form_token = $form_state['values']['form_token'];
  if ( isset($_SESSION['submitted_forms'][$form_token]) && $_SESSION['submitted_forms'][$form_token] = TRUE ){
    form_set_error('name]', 'This form has already been submitted');
  }
  else{
    $_SESSION['submitted_forms'][$form_token] = TRUE;
  }
}

```

I'm running into trouble where the form\_token isn't unique to the form - it seems to stay the same no matter what happens. I'm probably misunderstanding what the token is in the grand scheme of the form api.

Any insight is appreciated!

# Answer
> 8 votes
I had the exact same problem and managed to fix it using the Locking mechanisms from Drupal

In the validate function I used:

```
function mymodule_custom_form_validate($form, &$form_state){
  if (lock_acquire('your_custom_lock_name')) {
    // long operations here
  } else {
    form_set_error("", t("You submitted this form already."));
  }
}

```

And in the submit function I released the lock:

```
function mymodule_custom_form_submit($form, &$form_state){
  // submit code
  lock_release('your_custom_lock_name');
}

```

# Answer
> 1 votes
Here you should consider the module weight:

1. One module (let first\_module) which should have the module weight negative maximum\_value (may be -2000) here it should implement hook\_form\_alter() with the following code.Now you should verify whether the form is already submitted or not by your code.

> ```
>    function first_module_form_alter(&$form, &$form_state, $form_id)
>     {
>       $form['#validate'][] = 'mymodule_form_validate';
>     }
>
> ```

```
function mymodule_form_validate(&$form, &$form_state){
  //a($form_state);
  //initialize form array
  if (!isset($_SESSION['submitted_forms'])){
    $_SESSION['submitted_forms'] = array();
  }

  $form_token = $form_state['values']['form_id'];
  if ( isset($_SESSION['submitted_forms'][$form_token]) && $_SESSION['submitted_forms'][$form_token] = TRUE ){
    form_set_error('name]', 'This form has already been submitted');
  }
  else{
    $_SESSION['submitted_forms'][$form_token] = TRUE;
  }
}

```
1. The second\_module which the have weight of possitive higher value.Here you should unset the session by adding the submit callback to a module

> function second\_module\_form\_alter(&$form, &$form\_state, $form\_id) { $form\['#submit'\]\[\] = 'mymodule\_form\_submit'; }
>
> ```
> function mymodule_form_submit(&$form, &$form_state){
>
>   $form_token = $form_state['values']['form_id'];
>   unset($_SESSION['submitted_forms'][$form_token]);
>
> }
>
> ```

# Answer
> 1 votes
If you want this functionality on all the forms and more control without coding take a look at Hide Submit Button module.

> Features:
>
> 1. Hide or disable the submit button after it has been clicked
> 2. Display a message and/or image while waiting

# Answer
> 0 votes
```
$form['submit'] = array(
  '#type' => 'submit',
  '#value' => t('Save'),
  '#attributes' => array(
    'onclick' => 'javascript:var s=this;setTimeout(function(){s.value="Saving...";s.disabled=true;},1);',
  ),
);

```

hope this will help..

or you can refer Preventing multiple clicks of submit button & drupal has one module Hide submit button

> Some users accidentally click the submit button more than once while waiting for their post to be saved. In some cases this may result duplicate postings or duplicate e-commerce orders.

# Answer
> 0 votes
Here is server-side multiple submit validation implementation available in the module for the Drupal 8 and Drupal 9 https://www.drupal.org/project/pmfs

# Answer
> -1 votes
This was my problem also before. My solution to this is to disable the button via JS.

.module:

```
/**
 * Implementation of hook_init().
 */
function myModule_init(){
if (arg(0) == 'node' && (arg(2) == 'edit' || arg(1) == 'add')) {
    //hide btn when clicked on article nodes
    drupal_add_js(drupal_get_path('module', myModule') . '/js/disable-submit.js');
}

```

JS:

```
Drupal.behaviors.module_disable_submit = function (context) {

/*
 * Disable keypress on form fields.
 * Prevent browser to reload when pressing enter in input fields
 */

$('.buttons input:submit').click(function() {
  $('.buttons input:submit').hide();
  $('#node-form .buttons').prepend('<input type="submit" style="margin:1px 0; box-shadow:0 1px 1px #DDDDDD; border-radius:3px 3px 3px 3px; background:url(/sites/all/themes/rubik/images/bleeds.png) repeat-x scroll 0 -41px #F4F4F4; border-color:#DDDDDD #DDDDDD #CCCCCC; border-style:solid; border-width:1px; color:#B8A98F; cursor:default; font-weight:normal; padding:2px 10px; text-align:center;" value="Saving..." name="op" onclick="return false;" />');
  if ('.buttons input:submit') {
    $('.buttons input:submit').keypress(function() {
      $('.buttons input:submit').parents("form").submit();
      $('.buttons input:submit').hide();
    });
  }
});
}

```

---
Tags: forms
---


# Question
Title: It doesn't work without public_html symlink
I have just updated to Ubuntu 20.04 so have a fresh install of everything.
I have a working Drupal 7 site I'll call mysite.
I have Drush-launcher installed globally at /usr/local/bin/drush
The file structure of the site is the following.

* /var/www/mysite/composer.json (to install Drush 8.4.1)
* /var/www/mysite/vendor/drush/drush/drush (local Drush 8.4.1 binary)
* /var/www/mysite/web
* /var/www/mysite/public\_html (symlink to web)
* /var/www/mysite/web/sites

Drush works with this configuration. `drush status` returns a full and accurate site description of about 15 lines.

If I remove the public\_html link, the Drupal site runs fine but most Drush commands no longer work. `drush status` returns only the bare minimum of 7 lines as it does when it can't find the site. `drush --version` does return the correct version number either way and if I move the Drush 8 directory, all Drush commands return an error as expected. (This shows I'm still using the correct binary).

I have several Drupal 8 sites that are configured this exact same way (no public\_html directory or link) and they work as expected.

I have searched in the ~/.drush directory for any reference to public\_html and there are none related to this site. I have cleared the Drush cache. There are no references to public\_html in my Apache config for the site. Searching isn't turning up anything useful.

I could just leave the public\_html link in the filesystem but git wants me to add it or ignore which seems kinda silly.

What might I be doing wrong?

# Answer
Solved it!

Thanks to @sonfd for making me think more about the composer installation. Look what I found in there:

```
"extra": {
  "installer-paths": {
    "public_html": [
      "type:drupal-core"
    ]
  }
},

```

I changed that from public\_html to web and it works. Damn.
> 0 votes

---
Tags: drush
---


title: AJAX SettingsCommand Usage

text:
# Question
Title: AJAX SettingsCommand Usage
**Class Documentation:** SettingsCommand

I'm trying to figure out how to use this Ajax Command correctly. I must be confused from the documentation, so I'm hoping someone can shed some light where I'm mistaken.

*\__construct(array $settings, $merge = FALSE)*

> **array $settings**: An array of key/value pairs of JavaScript settings.
> **bool $merge**: Whether the settings should be merged into the global drupalSettings.

Given the array already in drupalSettings: \['drupalSettings'\]\['myData'\] = \[1,2,3,4,5\];
And the following ajaxCallback I would like to replace the 'myData' array with \[2, 4\]:

```

    namespace Drupal\settings_controller_test\Form;

    use Drupal\Core\Form\FormBase;
    use Drupal\Core\Form\FormStateInterface;
    use Drupal\Core\Ajax\AjaxResponse;
    use Drupal\Core\Ajax\SettingsCommand;

    class SettingsControllerTestForm extends FormBase
    {
        public function getFormId() { return 'settings_controller_test_form'; }

        public function buildForm(array $form, FormStateInterface $form_state)
        {
            $form['invoker'] = [
                '#type' => 'submit',
                '#value' => t('Invoke Callback'),
                '#ajax' => [
                    'callback' => [$this, 'ajaxCallback']
                    ]
                ];

            $form['#attached']['drupalSettings']['myData'] = [1,2,3,4,5];
            $form['#attached']['library'][] = 'settings_controller_test/test';
            return $form;
        }

        public function ajaxCallback(array &$form, FormStateInterface $form_state)
        {
            $response = new AjaxResponse();

            #clear old myData settings
            $response->addCommand(new SettingsCommand(['myData' => []], TRUE));

            #add new data for myData settings
            $response->addCommand(new SettingsCommand(['myData' => [2,4]], TRUE));

            return $response;
        }

        public function validateForm(array &$form, FormStateInterface $form_state){}
        public function submitForm(array &$form, FormStateInterface $form_state){}
    }

```

I'm testing the state of 'myData' in JavaScript using the following:

```

(function ($, Drupal, drupalSettings) {
    Drupal.behaviors.myBehaviour = {
      attach: function (context) {
        //output: [1, 2, 3, 4, 5]
        console.log(drupalSettings.myData);

        $(document).once().ajaxComplete(function(event, xhr, settings) {
          //output: [2, 4, 3, 4, 5]
          console.log(drupalSettings.myData);
        });

      }
    };
  })(jQuery, Drupal, drupalSettings);

```

**UPDATE:** The attempt to clear the myData array fails. Then when I attempt to set myData = \[2,4\] with merge set as TRUE the leading two elements change to 2,4 and the remaining elements in the array are still there.
**NOTE:** If I change: `$response->addCommand(new SettingsCommand(['myData' => [2,4]], TRUE));` to `$response->addCommand(new SettingsCommand(['myData' => [2,4]], FALSE));` the myData array remains completely unchanged \[1,2,3,4,5\]

# Answer
> 1 votes
Yes you need one more command to set the data back to nothing before you can overide it from trial and error the "merge" FALSE does nothing. so ...

```
// $response = new AjaxResponse();
// If want to replace you need to empty the array first.
$response->addCommand(new SettingsCommand([
  'MyData' => [],
], TRUE));
// then add new ones.
$response->addCommand(new SettingsCommand([
  'MyData' => [
    'New' => 'New values'
  ],
], TRUE));

```

See my New full example: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Ajax%21SettingsCommand.php/class/SettingsCommand/8.6.x#comment-64379

# Answer
> 0 votes
I faced the same issue and tried the answer from @taggartJ but not work. I use an alternative method to solve this issue as below:

```
public function ajaxCallback(array &$form, FormStateInterface $form_state)
    {
        $response = new AjaxResponse();

        // Send new value by DataCommand
        // We need to set $selector and $key
        // https://www.drupal.org/docs/drupal-apis/ajax-api/core-ajax-callback-commands
        $response->addCommand(new DataCommand($selector, $key, [2,4]));

        return $response;
    }

```

In JavaScript we just need to determine $('selector').data('key') is undefined or not, then we could update drupalSettings value.

```
    if ($('selector').data('key') != null) {
      drupalSettings.myData = $('selector').data('key');
    } else {
      drupalSettings.myData = [];
    }

```

Hope it helps.

---
Tags: 8, javascript, ajax
---


# Question
Title: How do I properly use hook_preprocess_views_view_unformatted()?
I have the following hook in mymodule.module.

```
function mymodule_preprocess_views_view_unformatted(&$variables) {
  $view = $variables['view'];
  $rows = $variables['rows'];

  if (in_array($view->id(),
      [
        'my_view',
      ]
    )
  )
    {
        foreach ($rows as $id => $row) {
          $custom_row_class = 'card-background-' . get_card_background();
          var_dump($custom_row_class);
          $variables['rows'][$id]['attributes']->addClass([$custom_row_class]);
        }

      var_dump($variables['rows'][0]['attributes']);
    }
}

```

The output is:

```
/Users/me/Sites/mysite/web/modules/custom/mymodule/mymodule.module:55:string 'card-background-11' (length=18)

/Users/me/Sites/mysite/web/modules/custom/mymodule/mymodule.module:58:
object(Drupal\Core\Template\Attribute)[7400]
  protected 'storage' =>
    array (size=1)
      'class' =>
        object(Drupal\Core\Template\AttributeArray)[7223]
          protected 'value' =>
            array (size=1)
              ...
          protected 'name' => string 'class' (length=5)

```

Right after supposedly adding the class to the rows attributes, it isn't there, and not surprisingly isn't in the attributes value passed to views-view-unformatted.html.twig.

# Answer
I tested your code locally and the way you are adding the class did work for me. E.g.

```
function mymodule_preprocess_views_view_unformatted(&$variables) {
  $rows = $variables['rows'];

  foreach ($rows as $id => $row) {
    $variables['rows'][$id]['attributes']->addClass(['test-123', 'test-abc']);
  }
}

```

... worked fine for me. I'd say your `var_dump()` is not giving you the full picture.

Try this instead:

```
var_dump($variables['rows'][0]['attributes']->__toString());

```

When I var dump with toString() - I see the class indicated in the output - hopefully you will too

```
/var/www/mysite/docroot/modules/custom/my_module/my_module.module:149:string ' class="card test-123 test-abc"' (length=31)

```
> 1 votes

---
Tags: 8, views
---


# Question
Title: Recurring Framework crashes with Datarans
I'm using Commerce Recurring Framework latest version (8.x-1.0-beta5) with Commerce Datatrans (also latest version, 8.x-1.0-beta1). When first payment happens (customer gets redirected to Datatrans, does the payment and gets redirected back to site) everything works fine.

But since it's recurring payment when user account should be charged again (after some time, from cron job) I get following error:

> The website encountered an unexpected error. Please try again later. Error: Call to undefined method Drupal\commerce\_datatrans\Plugin\Commerce\PaymentGateway\Datatrans::createPayment() in Drupal\commerce\_recurring\RecurringOrderManager-\>closeOrder() (line 157 of modules/contrib/commerce\_recurring/src/RecurringOrderManager.php).

Stack trace shows:

```
#0 /var/www/html/drupal/web/modules/contrib/commerce_recurring/src/Plugin/AdvancedQueue/JobType/RecurringOrderClose.php(32): Drupal\commerce_recurring\RecurringOrderManager->closeOrder(Object(Drupal\commerce_order\Entity\Order))
#1 /var/www/html/drupal/web/modules/contrib/advancedqueue/src/Processor.php(95): Drupal\commerce_recurring\Plugin\AdvancedQueue\JobType\RecurringOrderClose->process(Object(Drupal\advancedqueue\Job))
#2 /var/www/html/drupal/web/modules/contrib/advancedqueue/src/Processor.php(75): Drupal\advancedqueue\Processor->processJob(Object(Drupal\advancedqueue\Job), Object(Drupal\advancedqueue\Entity\Queue))
#3 /var/www/html/drupal/web/modules/contrib/advancedqueue/advancedqueue.module(19): Drupal\advancedqueue\Processor->processQueue(Object(Drupal\advancedqueue\Entity\Queue))
#4 [internal function]: advancedqueue_cron()
#5 /var/www/html/drupal/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(392): call_user_func_array('advancedqueue_c...', Array)
#6 /var/www/html/drupal/web/core/lib/Drupal/Core/Cron.php(236): Drupal\Core\Extension\ModuleHandler->invoke('advancedqueue', 'cron')
#7 /var/www/html/drupal/web/core/lib/Drupal/Core/Cron.php(134): Drupal\Core\Cron->invokeCronHandlers()
#8 /var/www/html/drupal/web/core/lib/Drupal/Core/ProxyClass/Cron.php(75): Drupal\Core\Cron->run()
#9 /var/www/html/drupal/web/core/modules/automated_cron/src/EventSubscriber/AutomatedCron.php(65): Drupal\Core\ProxyClass\Cron->run()
#10 /var/www/html/drupal/web/modules/contrib/devel/webprofiler/src/EventDispatcher/TraceableEventDispatcher.php(76): Drupal\automated_cron\EventSubscriber\AutomatedCron->onTerminate(Object(Symfony\Component\HttpKernel\Event\PostResponseEvent), 'kernel.terminat...', Object(Drupal\webprofiler\EventDispatcher\TraceableEventDispatcher))
#11 /var/www/html/drupal/vendor/symfony/http-kernel/HttpKernel.php(88): Drupal\webprofiler\EventDispatcher\TraceableEventDispatcher->dispatch('kernel.terminat...', Object(Symfony\Component\HttpKernel\Event\PostResponseEvent))
#12 /var/www/html/drupal/vendor/stack/builder/src/Stack/StackedHttpKernel.php(32): Symfony\Component\HttpKernel\HttpKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Symfony\Component\HttpFoundation\Response))
#13 /var/www/html/drupal/web/core/lib/Drupal/Core/DrupalKernel.php(686): Stack\StackedHttpKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Symfony\Component\HttpFoundation\Response))
#14 /var/www/html/drupal/web/index.php(22): Drupal\Core\DrupalKernel->terminate(Object(Symfony\Component\HttpFoundation\Request), Object(Symfony\Component\HttpFoundation\Response))
#15 {main}

```

Simply put `createPayment()` method doesn't not exist at Datatrans class?!? I assume that because Datatrans is not maintained regularry it get outdated, even I have the latest varsion. But again, I used compser for installing - it should take care of compatibilities, right?

I also downloaded other Datatrans payment module - "Payment Datatrans" and searched it's code for same createPayment() method, but didn't find it?!?

Then I downloaded the oldest version of Commerce Recurring module and it also has the same call, which btw looks like:

```
// The createPayment() call might throw a decline exception, which is
// supposed to be handled by the caller, to allow for dunning.
$payment_gateway_plugin->createPayment($payment);

```

So I'm really stuck here - what module is "guilty" for this error? Recurring Payment for calling unexsiting method or Commerce Datatrans for not having it? How to solve this problem?

# Answer
> 1 votes
Module is simply not supporting recurring payment (yet). It is kinda prepared for it (stores alias returned from payment service), but main functionality of making API call is missing. I created missing code on my own and it can be found here:

https://www.drupal.org/project/commerce\_datatrans/issues/3168477#comment-13823549

To repeat - it's not official and you can use it on your own risk.

---
Tags: 8, commerce, payment-gateways
---


# Question
Title: Is it possible to combine two filter criteria exposed filter into one dropdown
Is it possible to combine two filter criteria exposed filter into one dropdown. In drupal 8 I am creating a view to search certain content type. One of the content type has three select list field, I do not want to create three seperate exposed filter dropdown on the search page, Is there is a way to combine all into one exposed filter dropdown ?

Any suggestions and guidance deeply appreciated.

# Answer
Even with Better Exposed Filters you will not achieve what you need. As I understood you want one selectbox for the end user which merges three different fields of your content type?

This is not possible out of the box. When filtering the name of the selectboxes and the chosen values will be added to the URL like "?selectbox1=123&selectbox2=abc&selectbox3=xyz" (not exactly, but this is not important). Views does it for you to translate these URL parameters into the field names and the database query.

For your idea you need a way to tell Drupal that "?my\_merged\_selectbox\[\]=123&my\_merged\_selectbox\[\]=abc&my\_merged\_selectbox\[\]=xyz" needs to be somehow translated into the seperated filters / field names and values like above.

The only way would be to write your own views filter plugin. Helpful link: https://zanzarra.com/blog/custom-views-filter-plugin-drupal-8-bounding-box-geofield

I do not know if you have programming skills but what you want to achieve will need custom programming and is not trivial.
> 1 votes

---
Tags: 8, views
---


title: What is hook_field_default_fields()?

text:
# Question
Title: What is hook_field_default_fields()?
I'm looking through a Drupal 7 module code in an attempt to understand what it does. It implements `hook_field_default_fields()`, but I can't find any documentation on this.

What does this hook do?

I did find that the Field Types API seems to expose similar hooks such as `hook_field_extra_fields()`, but they aren't exactly the same.

# Answer
> 1 votes
It's a hook used from the Features module. Truly, the feature.api.php file, which should contain a description of all the hooks used by a module, contains a description for `hook_field_default_fields_alter()`.

> Deprecated as of 7.x-2.0.
>
> Alter the default fields right before they are cached into the database.
>
> `@param array[] &$fields`
> By reference. The fields that have been declared by another feature.
>
> @deprecated

Usually an alter hook is paired with a "normal" hook, but that is not always the case.
If you see that the hook is always invoked with `drupal_alter('field_default_fields', /* the other arguments */)`, the module uses only the alter hook. Checking if the module itself implements `hook_field_default_fields()` or `hook_field_default_fields_alter()` would also help to understand which hook is used from the module. Unfortunately, in this case, the module doesn't implement neither one or the other hook. This is easily explained from the fact the hook has been deprecated. (A module should be the first one not to implement its own deprecated hooks.)

---
Tags: 7, hooks
---


title: Allow authorization via cookies

text:
# Question
Title: Allow authorization via cookies
We are migrating from Drupal 7 to Drupal 8 and are currently at the last hurdle - relying on Drupal's session to authenticate for custom scripts.

Previously we used to rely on `drupal_bootstrap` but now I have implemented a similar Drupal 8 aware version for bootstrapping and checking the user is authenticated (and which roles they have etc) - this is broadly based on `core/authorize.php`.

However - this only works in the drupal root directory or the `core/` directory - in every other directory this fails to authenticate the user.

I believe this is down to the routing, and authentication only working for pre-defined routes.

Specifically I want to be able to authenticate users in any script in a folder (recursively). EG

* external\_scripts/script1.php
* external\_scripts/script1.php
* external\_scripts/other\_scripts/script3.php

How do I add a route to allow this? Or can I just bypass this route checking when using the cookie? Can I spoof the route?

```
<?php

/**
 * @file
 * Locates the Drupal root directory and bootstraps the kernel.
 */

use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\Routing\Route;

function _find_autoloader($dir) {
  $autoloadFile = $dir . '/vendor/autoload.php';
  if (file_exists($autoloadFile)) {
    return include_once($autoloadFile);
  }
  elseif (empty($dir) || $dir === DIRECTORY_SEPARATOR) {
    return FALSE;
  }
  return _find_autoloader(dirname($dir));
}

// Immediately return if classes are discoverable (already booted).
if (class_exists('\Drupal\Core\DrupalKernel') && class_exists('\Drupal')) {
  return \Drupal::service('kernel');
}

$autoloader = _find_autoloader(empty($_SERVER['PWD']) ? getcwd() : $_SERVER['PWD']); // defined in start.inc
if (!$autoloader || !class_exists('\Drupal\Core\DrupalKernel')) {
  print "This script must be invoked inside a Drupal 8 environment. Unable to continue.\n";
  exit();
}

const MAINTENANCE_MODE = 'update';

try {
  $request = Request::createFromGlobals();
  $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
  $kernel->boot();
  $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('<none>'));
  $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<none>');
  $kernel->preHandle($request);
  if (PHP_SAPI !== 'cli') {
    $request->setSession($kernel->getContainer()->get('session'));
  }
}
catch (HttpExceptionInterface $e) {
  $response = new Response('', $e->getStatusCode());
  $response->prepare($request)->send();
  exit;
}

\Drupal::moduleHandler()->addModule('system', 'core/modules/system');
\Drupal::moduleHandler()->addModule('user', 'core/modules/user');
\Drupal::moduleHandler()->load('system');
\Drupal::moduleHandler()->load('user');

$content = [];
$show_messages = TRUE;

$account = \Drupal::service('authentication')->authenticate($request);

if ($account) {
  \Drupal::currentUser()->setAccount($account);
}

var_dump(\Drupal::currentUser());

```

# Answer
I tried many different ways of loading the user, using the session as the starting point. In every singe scenario it fell down.

So in the end I used as much of the Drupal scaffold as I could, and copied the relevant bits from the relevant classes and functions in order to control the loading of a user record in an ajax handler that exists outside of Drupal's page space.

It uses the cookie to load the session, retrieve the user id, details and roles and create an account object before setting the bootstrapped Drupal kernel current user to the account object.

We deal with access control at a higher level (relying on `\Drupal::currentUser()` and leveraging `$user->isAuthenticated()` for example) so this script gets up to a consistent point in both contexts (inside Drupal, and non-drupal pages inside the domain) for user management etc.

```
<?php

/**
 * @file
 * Bootstraps the Drupal kernel and loads the user for the incoming request via cookie
 */

use Drupal\Core\DrupalKernel;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\UserSession;
use Symfony\Component\HttpFoundation\Request;

function _find_autoloader($dir) {
  $autoloadFile = $dir . '/vendor/autoload.php';
  if (file_exists($autoloadFile)) {
    return include_once($autoloadFile);
  }
  elseif (empty($dir) || $dir === DIRECTORY_SEPARATOR) {
    return FALSE;
  }
  return _find_autoloader(dirname($dir));
}

// Immediately return if classes are discoverable (already booted).
if (class_exists('\Drupal\Core\DrupalKernel') && class_exists('\Drupal')) {
  return \Drupal::service('kernel');
}

// Load autoload
$autoloader = _find_autoloader(empty($_SERVER['PWD']) ? getcwd() : $_SERVER['PWD']); // defined in start.inc
if (!$autoloader || !class_exists('\Drupal\Core\DrupalKernel')) {
  print "This script must be invoked inside a Drupal 8 environment. Unable to continue.\n";
  exit();
}

const MAINTENANCE_MODE = 'update'; // Don't bother theming

if (PHP_SAPI == 'cli') { // CLI won't have a cookie, stop now
  return;
}

$request = Request::createFromGlobals();
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$kernel->boot();
$connection = $kernel->getContainer()->get('database');

// Get session id from session cookie
$sid = reset($_COOKIE);

// Get uid from sessions, get user from uid
$query = $connection->queryRange('SELECT uid FROM {sessions} WHERE sid = :sid', 0, 1, [':sid' => Crypt::hashBase64($sid)]);
$uid = (string)$query->fetchField();
$values = $connection->query('SELECT * FROM {users_field_data} u WHERE u.uid = :uid AND u.default_langcode = 1', [':uid' => $uid])->fetchAssoc();

// Get roles from uid, and set account
if (!empty($values) && $values['status'] == 1) {
  $rids = $connection->query('SELECT roles_target_id FROM {user__roles} WHERE entity_id = :uid', [':uid' => $values['uid']])->fetchCol();
  $values['roles'] = array_merge([AccountInterface::AUTHENTICATED_ROLE], $rids);
  $account = new UserSession($values);
  \Drupal::currentUser()->setAccount($account);
}

```
> 0 votes

---
Tags: 8, bootstrapping, external-scripts
---


# Question
Title: Cannot flag nodes and comments automatically
I created a code to automatically flag nodes and comments. When I put only the code to flag the nodes, it works. But when I add the code to flag the comments it doesn't work anymore.

Which code should I use ?

```
<?php

function admin_task_notify_entity_update(Drupal\Core\Entity\EntityInterface $entity) {

  // Flag node.
  if (in_array($entity->bundle(), ['annonce', 'article', 'demande', 'discussion', 'evenement', 'itineraire', 'recette'])) {
    $flag_id = 'report_node';

    $flag_service = \Drupal::service('flag');
    $flag = $flag_service->getFlagById($flag_id);

    $flag_service->flag($flag, $entity);
  }

  // Flag comment.
  if (in_array($entity->bundle(), ['annonce', 'article', 'demande', 'discussion', 'evenement', 'itineraire', 'recette', 'produit', 'service'])) {
    $flag_id = 'report_comment';

    $flag_service = \Drupal::service('flag');
    $flag = $flag_service->getFlagById($flag_id);

    $flag_service->flag($flag, $entity);
  }

}

```

# Answer
Change the code in the following way so that it works as you expect:

```
  // Flag comment.
  if ($entity->getEntityTypeId() == 'comment') {
    $flag_id = 'report_comment';

    $flag_service = \Drupal::service('flag');
    $flag = $flag_service->getFlagById($flag_id);

    $flag_service->flag($flag, $entity);
  }

```
> 1 votes

---
Tags: 8, entities, flags
---


# Question
Title: How to use DefaultSelection::getReferenceableEntities in custom controller?
***My Goal:***

I want to create a customized `entity_autocomplete` form field to better fit my needs compared to the default one - making some modifications to the HTML and JS that's being used, as well as how submissions are handled.

Specifically, I want to do something like this but I need more control over the backend, and everything...

***What Drupal can do:***

Drupal's default entity autocomplete already lets the user type 2 letters, and it finds all entities that contain these 2 letters.

***My Problem:***

Unfortunately I have trouble figuring out how to use the existing "search feature" if you will call it that.

***Some Considerations:***

I looked into using search API, but this was similarly overwhelming. Considering that this functionality I'm looking for is already built into Drupal, I figure I can just re-implement it, without any additional modules, right? Really, I'm just re-designing the UI. And even if I need to beef it up in the future with a faster, resource saving search engine, I can just replace that aspect of my module/controller. (If someone can point out how to use Search API to do what I need, I'd be happy to listen)

***What I've done so far:***

I have already created my own custom route that points to a JSON controller which will accept the search parameters.

Based on all my research I figured I need to add `use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;` to the top.

I see that `DefaultSelection::getReferenceableEntities` seems to do exactly what I need it to do.

However, the constructor for this class has 9 different parameters, many of them classes which I know nothing about.

But there is a `create` method, which apparently allows you to inject configuration data, but also it requires a `ContainerInterface`.

So here's where I'm lost...

**How exactly do I make use of `DefaultSelection::getReferenceableEntities` in my custom controller?**

# Answer
> 2 votes
Okay, it took me over 2 weeks to get to the bottom of this, but turns out, that `DefaultSelection::getReferenceableEntities` is just a wrapper for `Drupal::entityQuery`. This becomes especially clear when realizing that `DefaultSelection::getReferenceableEntities` makes a call to `DefaultSelection::buildEntityQuery`. And this method is only a complicated way to make a customized query.

So for my purposes, all I had to do was learn about entity queries. Here's how I ended up performing a search:

**For taxonomy terms**

```
            $query = \Drupal::entityQuery('taxonomy_term');
            $query->condition('vid', 'my_taxonomy_terms'); //select the collection
            $query->condition('name', $search_term, 'CONTAINS'); //searching the title for a search term
            $term_ids= $query->execute();
            $terms = \Drupal\taxonomy\Entity\Term::loadMultiple($term_ids);  //process the nodes however is desired

            $result = [];

            foreach($terms as $term){
              $result[$term->id()] = $term->getName();
            }

            return $result;

```

**For other entities and nodes**

```
            $query = \Drupal::entityQuery('node');
            $query->condition('field_somefield', 'somevalue'); //optional condition to filter results by
            $query->condition('title', $search_term, 'CONTAINS'); //searching the title for a search term
            $node_ids = $query->execute();
            $nodes = \Drupal::entityTypeManager()->getStorage('node')->loadMultiple($node_ids); //process the nodes however is desired

            $result = [];

            foreach($nodes as $node){
              $result[$node->id()] = $node->getTitle();
            }

            return $result;

```

Reference: https://api.drupal.org/api/drupal/core!lib!Drupal.php/function/Drupal%3A%3AentityQuery/8.2.x

---
Tags: 8, entities
---


# Question
Title: Why there is not loadData() method in FileSystem?
To use the `private://` scheme of Drupal 8 I had to :

* Create a folder outside the docroot folder
* Implement a `$settings['file_private_path'] = '../private-files';` to designate this folder
* Make sure authorization matches the website user to write into it

Then I load the filesystem helper (I could use injection dependency but that is not the point here) :

```
$this->filesystem = \Drupal::service('file_system');

```

Prepare the directory in case it does not exists :

```
$this->filesystem->prepareDirectory('private://any_folder', FileSystemInterface::CREATE_DIRECTORY);

```

And then I could save a (unmanaged) file:

```
$this->filesystem->saveData(json_encode(['My Beautiful File Body']), 'private://any_folder/any_file.json', FileSystemInterface::EXISTS_REPLACE);

```

And this works fine.

But to load the file, I would have expected to have an "opposite" (say, `loadData()` ) method in `$this->filesystem`.

And as the file is unmanaged (which is fine) I cannout use `File Entity::load()` to load it.

So I end up with :

```
$loadedFile = json_decode(file_get_contents('private://any_folder/any_file.json'), JSON_OBJECT_AS_ARRAY);

```

Which works fine, but raises questions :

* Is this a legitimate way to do it (meaning, using a Drupal helper to save a file, then loading it from a straight PHP function) ?
* Why there is no `loadData()` method in the `FileSystem` service as I would have expected ?
* How does the Drupal scheme 'public:// or private://) is resolved from this PHP function ?

# Answer
> 2 votes
To answer your questions in respective order:

* Sure. If there's no built-in API function to make it easier, there's nothing wrong with using `file_get_contents` since the function can use Drupal's file stream protocols. The core test, `FileSaveDataTest::testFileSaveData()`, is doing this to confirm that `saveData()` works.
* One can only guess about the requirements as the class was composed. `saveData()` is a wrapper around a `file_put_contents()` op so that logging can take place when Drupal writes to a temp file. Perhaps there was no need to wrap `file_get_contents` in the same way?
* Drupal has a `StreamWrapperManager` service class that registered different custom `myscheme://` streams with PHP. This manager makes use of core PHP function `stream_wrapper_register()` to register any injected class that has the tags: `{ name: stream_wrapper, scheme: myscheme }`. For example, look at `CoreServiceProvider::register()` which registers the `private://` scheme when it detects `file_private_path` settings has been set.

---
Tags: 8, files
---


title: How to properly program AJAX links?

text:
# Question
Title: How to properly program AJAX links?
I have a custom module that uses AJAX. Everything works fine the way it is. I'm just wondering if it's the proper way to do it in Drupal. I'm new to Drupal 8 and 9 programming

This is a line from my code

```
$link ='<a href="/nojs/my-link/1" class="use-ajax btn btn-default">Test AJAX</a>';

```

Is this ok to do or should I be building my link? If so, why and how?

**EDIT**

I currently build non-ajax links like

```
  $url = Url::fromRoute('entity.node.canonical', array('node' => $record->nid));
  $title_link = Link::fromTextAndUrl($record->title, $url);
  $title_link =$title_link->toRenderable();
  $title_link=render($title_link);

```

# Answer
> 2 votes
If you just need to add the classes I believe it can be done like so

```
$url = Url::fromRoute(
  'entity.node.canonical',
  ['node' => $record->nid],
  ['#attributes' => ['class' => ['btn', 'btn-default', 'use-ajax']]]
);

 $title_link = Link::fromTextAndUrl($record->title, $url);

```

At that point $title\_link should be able to be rendered in the template as is!

```
// php
$variables['title_link'] = $title_link;

// twig
{{ title_link }}

```

---
Tags: nodes, 9
---


# Question
Title: EntityQuery with a condition on an array
I try to list all fields where a paragraph type is referenced (to find all contents which have paragraphs of a specific type).

My problem: I do a EntityQuery on field\_config entity type to find the fields. But, the condition on which paragraph\_type are targeted doesn't work correctly and return all fields which can content a paragraph disregarding the type.

Here my code:

```
// Recover my paragraph_type selected in my form.
$paragraph_type = $form_state->getValue('paragraph_type');

// List all field_config which referred this paragraph_type.
$query = \Drupal::entityQuery('field_config')
  ->condition('field_type', 'entity_reference_revisions')
  ->condition('settings.handler', 'default:paragraph')
  ->condition('settings.handler_settings.target_bundles', $paragraph_type, 'IN');

$field_config = $query->execute();

```

For exemple, I have a paragraph type "press\_release\_about" which can be add only in press release in a specific field. But for this paragraph (and all others), it's all fields which can contains a paragraph in the system which are returned.

When I inspect a field\_config which referred paragraph, I can see that **settings.handler\_settings.target\_bundles** is an array of the paragraph types which can be add with this field. The format is:

```
[settings:protected] => Array
    (
        [handler] => 'default:paragraph'
        [handler_settings] => Array
            (
                [target_bundles] => Array
                    (
                        [1col_text] => 1col_text
                        [1col_image] => 1col_image
                        [1col_quote] => 1col_quote
                        [1_col_graphique] => 1_col_graphique
                        [2_cols_texte_media] => 2_cols_texte_media
                        [2_cols_texte_graphique] => 2_cols_texte_graphique
                        [2_cols_text] => 2_cols_text
                    )
              )
         )

```

If I remove the condition `->condition('settings.handler_settings.target_bundles', $paragraph_type, 'IN')`, this change nothing. And if I change the `IN`by `NOT IN`, I have no result.

I don't know if I don't write my condition correctly or if my error is elsewhere.

# Answer
try to use an array instead of the value of $paragraph\_type.

that would be like this :

```
->condition('settings.handler_settings.target_bundles', [$paragraph_type], 'IN')

```
> 5 votes

# Answer
Unfortunately, this cannot be achieved directly with `IN` or other default operators atm.

This will throw an error like this:

```
PHP Warning:  mb_strtolower() expects parameter 1 to be string, array given in /var/www/bayer/docroot/core/lib/Drupal/Core/Config/Entity/Query/Condition.php on line 171

```

There is an open issue queue exactly for this: https://www.drupal.org/project/drupal/issues/2248567

Meanwhile, if you want to achieve this somehow, then we can do something like this:

Example: Consider if the `settings.handler_settings.target_bundles` key in some `field_config` config has values like these:

```
[
  'article'=> 'article',
  'faq' => 'faq',
  // etc...
]

```

Then we can use entityQuery something like this to add a condition based on these.

```
// Recover my paragraph_type selected in my form.
$paragraph_type = $form_state->getValue('paragraph_type');

// List all field_config which referred this paragraph_type.
$query = \Drupal::entityQuery('field_config')
  ->condition('field_type', 'entity_reference_revisions')
  ->condition('settings.handler', 'default:paragraph')
  // We can write some logic to make 'article' dynamically via a variable.
  ->condition('settings.handler_settings.target_bundles.article', 'article');

$field_config = $query->execute();

```
> 1 votes

---
Tags: 8, database
---


# Question
Title: How to use my custom widget in a custom form
I have developed a custom widget for the paragraph fields. It is working very well.

Now, I would like to add this widget in a render array of a custom form.

What is the best approach?

# Answer
I think I found a good way... feel free to comment:

1-Create an Element which will display the custom widget

2-Move a maximum of the logic from the widget to the element

3-Use the element in the widget
> 0 votes

---
Tags: forms
---


# Question
Title: Constraint on paragraph field not working
Here is a very simple code:

1-My constraint plugin (MyConstraint.php)

```
/**
 * @Constraint(
 *   id = "MyConstraint",
 *   label = @Translation("Never Validated", context = "Validation"),
 *   type = "string"
 * )
 */
class MyConstraint extends Constraint {
  public $message = "error %value";
}

```

2-My constraint validator (MyConstraintValidator.php) \[=\>addViolation in all cases\]

```
class MyConstraintValidator extends ConstraintValidator {

  public function validate($items, Constraint $constraint) {
    dpm("I am displayed");
    $this->context->addViolation($constraint->message, [
              '%value' => 10
            ]);
    return;
}

```

3-My constraint added to my bundle

```
function mymodule_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle)
{
    if($bundle=='my_bundle'){
      $fields['my_paragraph_field']->addConstraint('MyConstraint', []);
    }
}

```

**Result:**

1-The dpm message 'I am displayed' is displayed

2-The entity is saved without any validation error

**Notes**:

-I have other constraints which are working well, If I test one of them (on my\_bundle), the violation of this working constraint will be displayed but not the one with the code detailled here.

-The problematic constraint is added to a paragraph field... I suspect the problem is coming from there

-Nothing in the error logs.

I am looking for a hint to where to look.

# Answer
> 0 votes
On your addConstraint() your second parameter is an empty array - if you do not want to add any options leave that empty or use NULL

# Answer
> 0 votes
Ok, I found the solution...

It was a widget problem!! As I used a custom widget for this paragraph field, I didn't realize that the widget was also handling part of the violation process inside the `function flagErrors` which was badly overroded.

Sorry for this

# Answer
> -1 votes
You need to add

```
namespace Drupal\my_module\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * Validates the MyConstraint .
 */
class MyConstraintValidator extends ConstraintValidator {

  /**
   * {@inheritdoc}
   */
  public function validate($items, Constraint $constraint) {

    if (!$item = $items->first()) {
      return;
    }

    $field_name = $items->getFieldDefinition()->getName();

    /** @var \Drupal\Core\Entity\EntityInterface $entity */
    $entity = $items->getEntity();

    if ($entity->hasField('my_paragraph_field')) {

      $value = $entity->my_paragraph_field->value;

      // Check if the value matches or not.
      if ($value != 10) {

        $this->context->addViolation($constraint->message, [
          '%value' => 10
        ]);
      }

    }

  }

}

```

For reference : Adding Constraint to entity referenced Paragraph field

---
Tags: 8, forms, plugins
---


# Question
Title: Favicon settings missing on subtheme config
Using Drupal 8 W3CSS Theme 8.x-1.17, I created a subtheme. The subtheme works fine, but on the settings page, the entire `#edit-favicon` div is hidden; `style="display: none"` has been added. I can't figure out why this is happening. However, on the parent theme, the favicon is being displayed. In `subtheme.info.yml`, features and favicon are set to true.

```
settings:
  features:
    favicon: true

```

# Answer
> 0 votes
Try setting:

```
settings:
    features:
        favicon: true
    favicon:
        use_default: false

```

---
Tags: theming, configuration
---


# Question
Title: Count multivalue image field values in views-view-fields.html.twig
Making a presentation template for the gallery. The photo gallery has an image field with multiple values. I need to output the number of gallery photos (in the field\_gallery\_photo). How do I do this? I tried adding a field with a photo to the view, and all the values are shown in one line. The result is not accurate:

```
{{ fields.field_gallery_photo.content | length }}

```

---

In version 7 I did the following:

1. added the nid field
2. redefined the template for it
3. specified the following in the template:

```
$node = node_load($output);
print sizeof($node->field_gallery_photo['und']);

```

# Answer
> 2 votes
Your D7 PHP would translate into D8 Twig like this:

```
{% set node = row._entity %}
{{ node.field_gallery_photo.getvalue | length }}

```

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


# Question
Title: How to retrieve view row attributes when in twig template
I am using addClass() in hook\_preprocess\_views\_view\_unformatted (see my question regarding this at here), and the class is added to each row, but the next stop for the view results is views\_view.html.twig, where dumping the rows data with

```
{{ dd(rows) }}

```

shows no sign of the attributes part of the row data, which contains the class.

# Answer
The *views-view.html.twig* template is at a higher level. To manipulate data at that level, you'll need to use template\_preprocess\_views\_view().

You used template\_preprocess\_views\_view\_unformatted() which allows you to manipulate the data in *views-view-unformatted.html.twig*. This seems like the correct approach given your case.

Here are the contents of *views-view-unformatted.html.twig* from the views module in core.

```
{#
/**
 * @file
 * Default theme implementation to display a view of unformatted rows.
 *
 * Available variables:
 * - title: The title of this group of rows. May be empty.
 * - rows: A list of the view's row items.
 *   - attributes: The row's HTML attributes.
 *   - content: The row's content.
 * - view: The view object.
 * - default_row_class: A flag indicating whether default classes should be
 *   used on rows.
 *
 * @see template_preprocess_views_view_unformatted()
 *
 * @ingroup themeable
 */
#}
{% if title %}
  <h3>{{ title }}</h3>
{% endif %}
{% for row in rows %}
  {%
    set row_classes = [
      default_row_class ? 'views-row',
    ]
  %}
  <div{{ row.attributes.addClass(row_classes) }}>
    {{- row.content -}}
  </div>
{% endfor %}

```

You can see that if you loop through the rows variable, each row has an attributes property - the classes you added in *template\_preprocess\_views\_view\_unformatted()* will be part of it.
> 1 votes

---
Tags: views, theming
---


title: views intergration with redirect module

text:
# Question
Title: views intergration with redirect module
I've googled and nothing found about redirect module integration into views to add **new filter criteria for a content type or taxonomy**.

I need all redirects (`FROM` and `To` fields that showing in the image) path against specific **nid** (contextual filter) or **content type** (blog, event, article).

For more clarifications, see attached image

# Answer
> 0 votes
Redirect module has default views in `admin/structure/views` that fetchs all redirect URLs without any entity type filter neither you can add any relationship and nor filter criteria for any specific entity type.

So, we have to go programmatically way to achieve such scenario. See simple code below for content types only. If you want to go with any other entity type (like taxonomy), make changes in `foreach loop`

# CODE

```
$query = db_select('redirect', 'r');
$query->condition('r.type', 'redirect')
      ->fields('r', array('rid', 'redirect', 'redirect_options', 'source'));
$query->orderBy('rid', 'DESC');
$exe_query = $query->execute()->fetchAll();
foreach($exe_query as $result => $key){
    $str_node = substr($key->redirect,0,4);
    $nid = substr($key->redirect,5);
    if($str_node == 'node' && is_numeric($nid)){
      $node =  node_load($nid);
      if($node->type == 'article' && $node->status == 1){
        //Do Something
      }
    }
}

```

Now, you can add this code in custom module.

*Very important, the `redirect_options` column in `redirect` table has all the URL's (where your source URL is going to redirect) parameters in serialize form. So, you have to unserialize it first and concat with `redirect` columns' output.*

# Answer
> 3 votes
**For your first question:**

Redirect module integrated with views module, just navigate to admin/structure/views and you will see View called **Redirects**, enable it if it's not enabled, then pick the field you want, source field label is 'Source redirect' and from is redirect URL.

You can also create a new your view just be sure you using the base table or redirect

---

**For the second question:**

you need first to understand how redirect module structured.

Each redirect record you see is an entity, and it has the following fields:

1. rid: Primary Key: Unique redirect ID.
2. hash: A unique hash based on source, source\_options, and language.
3. type: The redirect type; if the value is 'redirect' it is a normal redirect handled by the module.
4. **uid**: The {users}.uid of the user who created the redirect.
5. source: The source path to redirect from.
6. source\_options: A serialized array of source options.
7. redirect: The destination path to redirect to.
8. redirect\_options: A serialized array of redirect options.
9. language: The language this redirect is for; if blank, the alias will be used for unknown languages.
10. status\_code: The HTTP status code to use for the redirect.
11. count: The number of times the redirect has been used.
12. access: The timestamp of when the redirect was last accessed.
13. status: Boolean indicating whether the redirect is enabled (visible to non-administrators).

As you see from the structure, there is no reference to the entity you added the redirect for; you have only a reference for the user who creates the redirect.

You can create a relation between the redirect and the user who creates the redirect, then get the nodes which authored by that user; Then you can adjust the views in the way you want.

Please notice this would **work with nodes** and with **any entity store uid**, but for example, in **Taxonomy case it won't work** because taxonomy entity doesn't store the uid.

another tip might help a bit is to add the redirect URL as a filter then make some string comparison.

# Answer
> 0 votes
There is a sandbox module called Views Redirect Relationship that provides the thing you might need. It is now (2020) quite old (2014) and I wish it had been promoted to a full project by now because this is super useful for large sites.

I need this on Drupal 8 so I created an issue to get this officially released and a Drupal 8/9 update going:

https://www.drupal.org/project/2285335/issues/3171396

---
Tags: 7, views, redirection
---