title: Multiple file uploads

text:
# Question
Title: Multiple file uploads
I am uploading multiple files using Drupal's form API but I am doing it multiple times:

```
$form['upload-group']['data-sources'] = array(
    '#type'         => 'file',
    '#name'         => 'datasources[]',
    '#title'        => t('Data Source(s)'),
    '#attributes'   => array('multiple' => 'multiple'),
);

$form['upload-group']['ref-attach'] = array(
    '#type'         => 'file',
    '#name'         => 'attaches[]',
    '#title'        => t('Ref Attachment(s)'),
    '#attributes'   => array('multiple' => 'multiple'),
);

```

I am using the standard code I have used many times before for one multiple upload field on my form. However file\_save\_upload's first parameter is the index of the array (without any reference to the array name itself.):

```
$num_files = count($_FILES['datasources']['name']);

for ($i = 0; $i < $num_files; $i++) {

    $file = file_save_upload($i, $validators, 'public://', FILE_EXISTS_REPLACE);

    if ($file) {
        $src = 'public://'.$file->filename;
        $dest = 'public://datasources/'.$file->filename;
        file_unmanaged_move($src, $dest, FILE_EXISTS_REPLACE);
    }
}

```

My thought is that this is causing confusion as to which array it is trying to upload and why I am not getting anything uploaded at all!!

Has anyone come across this issue before or have any ideas on a solution?

# Answer
> 1 votes
`file_save_upload()` only works on the `$_FILES['files']` array. This usually happens automatically because `#name` in the form element is `'files[]'`.

I was on the right lines by using `'#name' => 'datasources[]'` and `'#name' => 'attaches[]'`. However, they were not getting uploaded because they weren't named `'files[]'`.

I have worked around this by adding a function.

```
function mymodule_merge_upload_files(&$files, $sourcename) {
  // Number of files added to $_FILES['files'] already (if any)
  $num_sofar = isset($files['files']['name']) ? count($files['files']['name']) : 0;
  // Number of additional files we are appending
  $num_app = count($files[$sourcename]['name']);

  for ($i = 0; $i < $num_app; $i++) {
    $files['files']['name'][$num_sofar] = $files[$sourcename]['name'][$i];
    $files['files']['type'][$num_sofar] = $files[$sourcename]['type'][$i];
    $files['files']['tmp_name'][$num_sofar] = $files[$sourcename~['tmp_name'][$i];
    $files['files']['error'][$num_sofar] = $files[$sourcename]['error'][$i];
    $files['files']['size'][$num_sofar] = $files[$sourcename]['size'][$i];
    $files['files']['source'][$num_sofar] = $sourcename;
    $num_sofar++;
  }
}

```

The function merges the uploaded arrays to the `$_FILES['files']` array and adds a further sub-array to save where the files came from.

I then modified the submission callback as follows.

```
mymodule_merge_upload_files($_FILES, 'datasources');
mymodule_merge_upload_files($_FILES, 'attaches');
$num_files = count($_FILES['files']['name']);

for ($i = 0; $i < $num_files; $i++) {
  $file = file_save_upload($i, $validators, 'public://', FILE_EXISTS_REPLACE);
  if ($file) {
    $src = 'public://'.$file->filename;
    $dest = 'public://somefolder/'.$_FILES['files']['source'][$i].'/'.$file->filename;
    file_unmanaged_move($src, $dest, FILE_EXISTS_REPLACE);
  }
}

```

The first 2 lines merge both arrays using my function, which I can then upload to specific folders based on the source (`$_FILES['files']['source'][$i]`).

---
Tags: forms, files
---


title: View with url aliases

text:
# Question
Title: View with url aliases
I am writing a view that lists all content of a specific type. I would like to, additionally, be able to set paths to content made by a specific user. For example drupal.dd/content will give all content. Then drupal.dd/%/content will show only the content by a specific user where % is the user's name. The issue I have come across is, when I create the path with /%/content it says the first segment of the path cannot be %. I am using a contextual filter to filter by author. How would I go about doing so. I am using Drupal 8.

# Answer
> 0 votes
You should already have a path for this at drupal.dd/content/\[author\] based on how you have setup the contextual filter. If you are using a contextual filter, they will get appended to the path of the view, and it sounds like your view has a path of "/content".

---
Tags: uri, path-aliases
---


# Question
Title: Date range or date with operation (greater than, etc.) contextual filter
I get date with contextual filter in views and i want set "greater than" my date. This option not exist in contextual filter. I cannot use argument in filter criteria.

In drupal 7 we can use "2017-01-01--2017-12-18" for range date with contextual filter, but in drupal 8, this trick not work.

Someone can help me, with date and contextual filter ?

Thank you

# Answer
I don't understand why we don't have operator (\>=, \<=, etc.) in contextual filter...

Temporary solution... affect all views with argument :

File :

\core\modules\views\src\Plugin\views\argument\Formula.php

Change :

```
$formula = $this->getFormula() . ' = ' . $placeholder;

```

to

```
$formula = $this->getFormula() . ' >= ' . $placeholder;

```

Function :

```
public function query($group_by = FALSE) {
    $this->ensureMyTable();
    // Now that our table is secure, get our formula.
    $placeholder = $this->placeholder();
    $formula = $this->getFormula() . ' >= ' . $placeholder;
    $placeholders = [
      $placeholder => $this->argument,
    ];
    $this->query->addWhere(0, $formula, $placeholders, 'formula');
}

```
> 1 votes

---
Tags: views, datetime
---


# Question
Title: How to define multiple cronjobs within single module?
What would be a good way to define two (or more) cronjobs without creating multiple modules?

As far as I know, in order to define a new cronjob, a hook\_cron needs to be used like following:

function example\_cron(){}

However, I have come to the point where I need to create new cronjob (in order to set different launch times using Ultimate Cron).

At first I looked at Ultimate Cron module and it's hook\_cronapi hook as in documentation. However, that and other hooks doesn't really work - https://www.drupal.org/node/2842834

How should I implement it without creating additional modules and using hook\_cron's?

# Answer
As commented in that that issue and various others before, custom cron jobs are defined using config entities, in the same way that ultimate cron defines the default cron jobs.

Just export what you have by default, copy one and adjust the callback/cron configuration, then import it again or define them in your config/install folder for a new module.
> 1 votes

---
Tags: 8, cron
---


# Question
Title: Programmatically get field values of fields added to custom entity
I created a custom entity in Drupal 8, and I added base fields.

I add the getter/setter functions to my entity definition file. They return `NULL` when called from a preprocess function. (I'm trying to add some variables for the Twig template.)

Why would this be? I'm using the following code.

```
public function getProjectId() {
    return $this->get('project_id')->value;
}

```

*project\_id* is en entity reference field.

# Answer
> 2 votes
The column for an entity reference field is `target_id`, so you should just need to replace the getter with:

```
public function getProjectId() {
    return $this->get('project_id')->target_id;
}

```

---
Tags: entities
---


# Question
Title: How do I update Drupal Distribution (Commerce Kickstart) on shared hosting environments?
We currently run a Drupal Commerce site from GoDaddy C-Panel shared hosting environment.

I created the site with Commerce Kickstart and am now several distribution updates behind.

1. If that's the case, do I need to do the updates sequentially? (e.g. run three updates to get to the current version.)
2. Has anyone been successful with using Drush on GoDaddy to make these updates?

I read through the How-To documentation from Commerce Guys and wanted to run the updates with Drush based on the video posted there.

I followed the instructions on GoDaddy here: How to install Drush on cPanel Shared Hosting Everything seemed to go well, but nothing happens when I try to run the drush commands. Any recommendations on how to troubleshoot this?

So I think I will need to do the security updates all manually for now.

# Answer
1. Use drush and try with this article: https://duntuk.com/how-install-drush-godaddy-cpanel-hosting
or
2. Update manually.

I would avoid the "update" interface in drupal. Reminder: All of the 100 or so modules are stored in the profile folder.
> 0 votes

---
Tags: commerce, updating, distributions
---


# Question
Title: Can a VBO form be integrated with the Commerce Add-to-Cart form to allow adding optional add-on products with checkboxes?
With VBO and Rules I can display a list of Commerce products with checkboxes and a button to add the checked products to the cart (see how).

**Is there a way to integrate these checkboxes with the default Add-to-cart form from Commerce?** I want to have a single Add-to-Cart form with one button, not two forms.

Alternatives I tried:

Is there another way/module?

My goal is to display optional add-on products (with checkboxes) on a primary product page. If the user doesn’t select any add-on product, only the primary product is added to the cart; if the user selects add-on products, the primary product and the selected add-on products get added to the cart.

(The question Drupal Commerce - optional extra products on add to cart form seems to have the same goal, but OP seems to be fine with the Commerce Product Add-on module if it would work for him in his case. The question add to cart - multiple products at once seems to be for adding always the full set of products, so without checkboxes.)

# Answer
> 1 votes
You could do it with Custom Line Item Fields for checkboxes and either just track the add on products using the line item or create a rule that adds the matching product to the cart when an line item is added that has checkbox field values.

PS: If you go with line item fields only approach, you should use pricing rules to change the final price of any line item with those check boxes to add prices to them. If you do that, then you might want this patch that allows line item fields to automatically ajax update the price when something changes:

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

---
Tags: 7, forms, commerce, rules, views
---


# Question
Title: How to decide between 'Hook_preprocessor' or using twig template?
We all know that for a customs web designing issue there are many solutions and various methods and ways, but this question has always existed, i.e about what the advantages/disadvantages (pros/cons) of each of them are.

For example, by using `hook_preprocess` in the theme file we can add our desired styles to custom blocks or regions, and reduce our needs to keeping multiple twig templates compared to times we use twig template to add our styles.

I want to be able to use those criteria (pros/cons) to decide which one is recommended in specific situations by considering indicators such as:

* Stability
* Efficiency and Loading speed
* Maintenance

# Answer
> 3 votes
It's not really an either/or thing. They are used together - preprocess functions are run before a template is used. Templates should only have very simple logic, if/else, and loops for the most part. Any logic more complex than this should go into a preprocess function. If you want to do things like adding classes to the attributes of a variable, this should generally be done in the preprocess function, though if you have a class that will only go in a single template, then it can be done in the template itself.

---
Tags: theming
---


# Question
Title: Can not access to the nth product's variation ( n > 1) programmatically
I have a product type called `gift` with 3 different variations.

I add an attribute to it so that a user can choose a custom variation based on the attribute, attribute (A, B, C).

I also have a custom checkout pane, If a user choose the first variation (by choosing the attribute), i can access the variation that is selected. for example by using 2 lines of code below:

```
<?php
$variations = $gift->variations->getEntity();
?>

```

Or

```
<?php
$gift->variations->target_id
?>

```

But if a user choose another variations except the first variation (for example: variation B), I can not access to that variation.

```
<?php
public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
    $pane_form['#order_entity'] = $this->order;

    $order_items = $this->order->getItems();
    /** @var \Drupal\commerce_order\Entity\OrderItem $item */
    $item = $order_items[0];
    $gift = $item->getPurchasedEntity();
    $gift = Product::load($gift->id());

    $variations = $gift->variations->getEntity(); // Just works for first variation
    drupal_set_message('bundle: ' . $variations->bundle());

    // This line of code works for just first variation too
    // $id = $gift->variations->target_id;
}
?>

```

Regards

# Answer
> 2 votes
Basically, I wanted to get attributes attached to the current variation. According to Bojanz' answer: https://www.drupal.org/node/2893842#comment-12163314, there was no need to use `$gift->variations`. Bojanz corrected and told me `$item->getPurchasedEntity()` is the product variation, not the product

So the code would be:

```
  /**
   * {@inheritdoc}
   */
  public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
    $pane_form['#order_entity'] = $this->order;

    $order_items = $this->order->getItems();
    /** @var \Drupal\commerce_order\Entity\OrderItem $item */
    $item = $order_items[count($order_items) - 1]; // the last item added to the order
    /** @var \Drupal\commerce_product\Entity\ProductVariation $gift */
    $gift = $item->getPurchasedEntity();
    $attribute = $gift->getAttributeValue('attribute_gift_type');
  }

```

# Answer
> 0 votes
You have been using the commerce API so well, except for the last step. If your gift is a Drupal\commerce\_product\Entity\Product entity, it means that it implements Drupal\commerce\_product\Entity\ProductInterface.

This interface already has an function for accessing product variations: `getVariations()`.

You should be able to use `$variations = $gift->getVariations();` to obtain an array of product variations.

---
Tags: 8, commerce
---


# Question
Title: Correct way to alter markup as html within theme_preprocess_container?
On my node edit form I've got a field widget that needs some information added to it. Before my alterations, the kint dump of `$variables['children']` looks like:

However, after manually setting `$variables['children']`, the dump looks like:

Before alteration, html renders correctly. However, afterward it is all just rendered as a string with the HTML displaying on the page.

I've tried using the `create()` method instead that's shown as available under:

...but it doesn't do anything at all.

I've also instead tried changing `$variables['element']['display']['#markup']`, but that doesn't have any visible effect.

# Answer
> 1 votes
You can't modify a markup object, but you can use the `create()` method on a new markup object to replace the old one.

```
$variables['children'] = \Drupal\Core\Render\Markup::create('<div>Manually set</div>');

```

By the way, you are modifying a twig debug message which won't be there in a production environment.

---
Tags: 8, theming, entities
---


title: Canonical link on node's print version

text:
# Question
Title: Canonical link on node's print version
I'm using Metatag and Printer, email and PDF versions modules, and I want to have the canonical link on the print version of the nodes too, but for some reason they're only showing on the regular version.

I'm not sure if the Print module is removing it. Even if I manually add the canonical link, it shows duplicated on the regular version but not in the print version.

Any idea about what's going on?

# Answer
> 0 votes
I solved the issue by adding a canonical link via `hook_html_head_alter()`.

---
Tags: 7, uri, meta-tags
---


title: How do I recreate the accesslog?

text:
# Question
Title: How do I recreate the accesslog?
In Drupal 7, every time a node is viewed the following columns are populated in the {accesslog} table:

* aid: unique accesslog ID
* sid: browser session ID of user that visited page
* title: title of page visited
* path: internal path to page visited (relative to Drupal root)
* url: referrer URI
* hostname: hostname of user that visited the page
* uid: user users.uid that visited the page
* timer: time in milliseconds that the page took to load
* timestamp: timestamp of when the page was visited

In Drupal 8, the accesslog was removed from the statistics module. I would like to recreate some this functionality in a Drupal 8 custom module. I need: \- A hook to fire on every node view \- Capture the relevant information \- Write it to a database table

My plan was to copy from statistics module, because it still counts node views. However, the code is not straight forward. In Drupal 8 the mechanism appears to be:

* Implement hook\_ENTITY\_TYPE\_view(), which attaches some JavaScript and settings to the page build

```
/**
 * Implements hook_ENTITY_TYPE_view() for node entities.
 */
function statistics_node_view(array &$build, EntityInterface $node, EntityViewDisplayInterface $display, $view_mode) {
  if (!$node->isNew() && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) {
    $build['#attached']['library'][] = 'statistics/drupal.statistics';
    $settings = array('data' => array('nid' => $node->id()), 'url' => Url::fromUri('base:' . drupal_get_path('module', 'statistics') . '/statistics.php')->toString());
    $build['#attached']['drupalSettings']['statistics'] = $settings;
  }
}

```
* Implement the following code in statistics.js

```
/**
 * @file
 * Statistics functionality.
 */

(function ($, Drupal, drupalSettings) {

  'use strict';

  $(document).ready(function () {
    $.ajax({
      type: 'POST',
      cache: false,
      url: drupalSettings.statistics.url,
      data: drupalSettings.statistics.data
    });
  });
})(jQuery, Drupal, drupalSettings);

```
* Implement statistics.php, which where information gets written to the database

```
/**
 * @file
 * Handles counts of node views via AJAX with minimal bootstrap.
 */

use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;

chdir('../../..');
$autoloader = require_once 'autoload.php';
$kernel = DrupalKernel::createFromRequest(Request::createFromGlobals(), $autoloader, 'prod');
$kernel->boot();
$views = $kernel->getContainer()
  ->get('config.factory')
  ->get('statistics.settings')
  ->get('count_content_views');

if ($views) {
  $nid = filter_input(INPUT_POST, 'nid', FILTER_VALIDATE_INT);
  if ($nid) {
    \Drupal::database()->merge('node_counter')
      ->key('nid', $nid)
      ->fields(array(
        'daycount' => 1,
        'totalcount' => 1,
        'timestamp' => REQUEST_TIME,
      ))
      ->expression('daycount', 'daycount + 1')
      ->expression('totalcount', 'totalcount + 1')
      ->execute();
  }
}

```

Can anyone explain this code?

# Answer
> 1 votes
There is no official way to do your own thing in statistics.php, it is on purpose kept as light as possible.

But of course, you can duplicate its functionality and do whatever you want. The whole trick is adding a JS file that sends an uncached POST request to the server. That's the only reliable way to get access statistics for anonymous users, as those requests might be cached by the page cache or an external CDN/Varnish.

Given that you already posted all the relevant code, I'm not sure what you are asking exactly. You even linked to the d.o issue that removed that feature, which links to the change record (https://www.drupal.org/node/1900384), which in turn links to the contrib module that provides similar functionality: https://www.drupal.org/project/better\_statistics. So instead of doing it yourself, you could build upon that.

---
Tags: 8
---


# Question
Title: Programmatically created nodes are shown only after re-saving
I'm creating a lot of nodes programmatically in a custom module. These nodes are showing up on admin/content and in a default view display (unformatted/fields), but not in a calendar view display. Only if I open and resave, those nodes will be shown in the calendar view.

Why is this happening? All nodes are published.

# Answer
SOLVED: I was using a timestamp for the generated dates, but it needed to be a string like: "1967-01-15T00:00:00". I needed to look up the values in my database directly, devel / dpm() did not show a difference.
> 0 votes

---
Tags: views, datetime
---


# Question
Title: ubercart product submission form theming
how to render elements in the **mysite/node/add/product** form to make custom tpl in my ubercart product submission form. I tried node--add-product.tpl.php ; nothing is happening. Im a beginner to drupal. can any one help me?

# Answer
Found the solution. TPL file should be page--node--add--product.tpl.php
> 0 votes

---
Tags: theming, ubercart
---


# Question
Title: How can add extra info to the <html> tag?
How can I add extra info like `lang="ar" dir="rtl"` to the `<html>` tag like the following?

```
<html{{ html_attributes }} lang="ar" dir="rtl">

```

# Answer
> 4 votes
You can use the following code, even though for those specific values, I would find a different way (e.g. setting the language for the shown page).

```
{% html_attributes.setAttribute("lang", "ar") %}
{% html_attributes.setAttribute("dir", "rtl") %}
<html{{ html_attributes }}>

```

Inside `hook_preprocess_html()`, since `$variables['html_attributes']` is an `Attribute` object, so you can use `Attribute::setAttribute()`.

```
$variables['html_attributes']->setAttribute("lang", "ar");
$variables['html_attributes']->setAttribute("dir", "rtl");

```

---
Tags: theming
---


title: When do I use views_get_view_result()?

text:
# Question
Title: When do I use views_get_view_result()?
I have basic listing in a View. I can give styles, or unformatted text, provide a link, etc. However, I would need the listing to be a list of linked items, with the destination URL changing depending on context: language, type of user, etc. So I just retrieve the listing with a view, and in the template, I use views\_get\_view\_result to print the fields I need and warp them with the necessary parameters (the dynamic URL, etc.). Is that a good approach or could this be achieve through the config of the View or with aid of another module (Context, Context Views, whatever...). Thanks!

# Answer
Trying to give a reply to the question title:

you use **views\_get\_view\_result()** when you need the result of a view inside your custom code. It works fine inside module or theme files.

For instance: you need to get a list of users inside your custom module. Instead of querying the database with db\_query, yuo can build a **Users** View named **a\_list\_of\_users** and get results with

```
    $res = views_get_view_result($name = "a_list_of_users", $display_id = "default");

```

Any additional parameters will be passed as arguments.

I love this function!
> 1 votes

# Answer
To get the correct translated link you need to use Internationalization Views module which translates the links based on the current language. The `Path Translation` module is also helpful.

Many things can be done by Views directly, but if you really need to customize the view results don't use `views_get_view_result`. You need to use Theme Information template pages of the view under the Advanced section,

These preprocess template pages are called before displaying the view and they are called to build the result of the view. It has three different levels and each one is used to theme its relevant output.

For example `views-view-fields--VIEWNAME.tpl.php` is used to theme the fields of the view and every field is available in this template file.

The THEME\_preprocess\_views\_view\_fields(&$variables) function in the `template.php` file of your theme folder is another available option. you can set or get some attributes of the view (like field views of the view.)

These options bring you lot's of choices, as an example you can define one view template for multiple views, you can theme individual fields or theme a row or theme the entire view (the above mentioned three levels) .
> 0 votes

---
Tags: 7, views
---


# Question
Title: Programmatically create user and add complete address field values
I have an address field on my User entities. I want to programmatically create users and set their address field values, I currently have this:

```
 $values = [
  'mail' => 'chris+7asd7fadf7afdafasdf@example.com',
  'name' => 'chris+7asd7fadf7afdafasdf@example',
  'first_name' => 'First',
  'last_name' => 'Last',
  'roles' => [],
  'pass' => user_password(),
  'status' => 1,
];
$user = User::create($values);
$user->field_contact_information->country = 'US';
$user->field_contact_information->given_name = $values['first_name'];
$user->field_contact_information->family_name = $values['last_name'];
$user->save();

```

But it's not saving the values to `field_contact_information`. Elsewhere in the app, I do access these values with `$user->field_contact_information->given_name`.

# Answer
That was simple - it should be `$user->field_contact_information->country_code = 'US';`
> 2 votes

---
Tags: 8
---


# Question
Title: Custom module with custom node type, error Trying to get property of non-object en comment_node_type_delete()
I'm quite new with Drupal 7 development, after researching and following some tutorials I was able to create my custom module that defines a new node type with some fields, but now I have a problem when I uninstall it, the hook\_uninstall runs almost fine(the node type, the contents from my custom node, and the node fields), except that display this error after the uninstall:

> Notice: Trying to get property of non-object en comment\_node\_type\_delete() (línea 344 de /opt/lampp/htdocs/drupal/modules/comment/comment.module). Notice: Trying to get property of non-object en comment\_node\_type\_delete() (línea 355 de /opt/lampp/htdocs/drupal/modules/comment/comment.module). Notice: Trying to get property of non-object en comment\_node\_type\_delete() (línea 355 de /opt/lampp/htdocs/drupal/modules/comment/comment.module). Notice: Trying to get property of non-object en comment\_node\_type\_delete() (línea 355 de /opt/lampp/htdocs/drupal/modules/comment/comment.module). Notice: Trying to get property of non-object en comment\_node\_type\_delete() (línea 355 de /opt/lampp/htdocs/drupal/modules/comment/comment.module). Notice: Trying to get property of non-object en comment\_node\_type\_delete() (línea 355 de /opt/lampp/htdocs/drupal/modules/comment/comment.module). Notice: Trying to get property of non-object en comment\_node\_type\_delete() (línea 355 de /opt/lampp/htdocs/drupal/modules/comment/comment.module). Notice: Trying to get property of non-object en comment\_node\_type\_delete() (línea 355 de /opt/lampp/htdocs/drupal/modules/comment/comment.module).

This is from mymodule.install:

```
function mynode_uninstall() {

    $ournewtype = 'mynode';
    $sql = 'SELECT nid FROM {node} n WHERE n.type = :type';
    $result = db_query($sql, array(':type' => $ournewtype));
    $nodeids = array();
    foreach ($result as $row) {
        $nodeids[] = $row->nid;
    }
    node_delete_multiple($nodeids);
    node_type_delete($ournewtype);
    field_purge_batch(500);
    drupal_flush_all_caches();
}

```

# Answer
> 1 votes
I believe the problem is that it's expecting an object, and you are passing a string. Try changing this:

```
node_type_delete($ournewtype);

```

To this:

```
$node_type = node_type_load($ournewtype);
node_type_delete($node_type);

```

One other thing, instead of this:

```
$result = db_query($sql, array(':type' => $ournewtype));
$nodeids = array();
foreach ($result as $row) {
    $nodeids[] = $row->nid;
}

```

You can simplify it by using this:

```
$nodeids = db_query($sql, array(':type' => $ournewtype))->fetchCol();

```

---
Tags: 7, nodes
---


# Question
Title: How to omit form's validation at AJAX button click?
I have an AJAX button that should update form fields according to data already provided by user:

```
 'ajax_button' => array(
    '#type' => 'button',
    '#value' => t("Scan for tags"),
    '#ajax' => array(
      'callback' => 'ajax_tag',
      'wrapper' => 'dynamic-tags-fieldset',
      'method' => 'replace',
      'event' => 'click',
      'prevent' => 'submit click mousedown',
    ),
  ),

```

It works, but only if form is valid. Of course I do not want to validate it just yet. I don't care if all fields are filled, I only need my form to be updated at this very moment. How can I make form api **not** to invoke hook\_form\_validate() and not test `#required` fields?

# Answer
> 9 votes
You can use the `#limit_validation_errors` property:

> Provides an array of sections which are parts of $form\_state\['values'\] which should be validated, implying that sections which are not listed should not be validated. This is normally used in multistep forms in the case of a "back" button, for example, where '#limit\_validation\_errors' =\> array() would mean not to validate anything as form values on the current page are to be discarded anyway. #limit\_validation\_errors does not have any effect if #submit is not set. More discussion is in the form\_set\_error() documentation.

e.g.

```
'ajax_button' => array(
    '#type' => 'button',
    '#value' => t("Scan for tags"),
    '#ajax' => array(
      'callback' => 'ajax_tag',
      'wrapper' => 'dynamic-tags-fieldset',
      'method' => 'replace',
      'event' => 'click',
      'prevent' => 'submit click mousedown',
    ),
    '#limit_validation_errors' => array(), // No elements will be validated
    '#submit' => array('custom_function'), // An explicit submit functions array is required for this, but may be empty
  ),

```

However, each validation function is free to respect '#limit\_validation\_errors' or not. If you want your validation functions to respect this parameter, you need to:

* Obtain #limit\_validation\_errors value from clicked button using `$form_state['clicked_button']['#limit_validation_errors']`
* Pass it as a third argument to each form\_set\_error() call

# Answer
> 0 votes
I had similar issues, that I was unable to fix with `#limit_validation_errors`. So I found a dirty hack that I want to share, but strongly advise against, unless you know what you are doing.

Caveat / disclaimer:

* I am still not fully aware myself of the consequences of this hack. I am still experimenting.
* This answer is not a complete tutorial. It is meant for people who already know all the "official" information about form API.
* There may be other, better ways to solve my specific problem. However, I still want to share this, because it provides a way to skip the entire validation + submission + rebuilding step. So even if in my case it turns out to be not necessary, for other it might be useful or interesting.
* As said: Do not try this at home!

## Use case / scenario

I was developing a custom form element type.

The element contains a button to add more items, which should change the form structure and let you continue with the modified form.

## Observations about form API

Currently, if you have a form element with a `'#process'` callback and a `'#value_callback'` callback, and you click a submit button, each of these callbacks will be called twice during the POST request.

Why is this?

Let's have a look at `drupal_process_form()`. At first, this calls `form_builder()` directly, which recursively visits all form elements and calls `#process`, `#value_callback` and other callbacks.

Then, if `$form_state['process_input']` is TRUE, it will call `drupal_validate_form()`, execute the submit handlers, and call `drupal_rebuild_form()`. The `drupal_rebuild_form()` calls `form_builder()`, which again fires all the element callbacks.

Between and during these two steps, there is logic that can mess with `$form_state['values']` and `$form_state['input']`. So, if you have very dynamic form elements, it could happen that on the second call to `#value_callback`, you have a different result than on the first such call.

Overall, it would be nice if we could just skip the entire validation + submission altogether, if there was no actual submit button clicked.

## Skip validation + submission + rebuilding?

In `drupal_process_form()`, we see this code:

```
  $form = form_builder($form_id, $form, $form_state);

  // Only process the input if we have a correct form submission.
  if ($form_state['process_input']) {
    drupal_validate_form($form_id, $form, $form_state);

```

We see that the entire validation, submission, and rebuilding is only done if `$form_state['process_input']` is true.

My first idea was to directly set `$form_state['process_input'] = FALSE;` in my custom form element's `#value_callback`. However, I noticed this has undesirable consequences, because other `form_builder()` logic depends on this being TRUE.

The trick was to set `$form_state['process_input'] = FALSE;` as the last thing that would happen before the check in `drupal_process_form()`.

The place to do this is in a callback registered into `$form_state['complete form']['#after_build']`.

## Step by step

1. In the custom element's `#process` callback, add the button:

$element\['addmore'\] = \[ '#type' =\> 'button', '#name' =\> $element\['#name'\] . '\[addmore\]', '#value' =\> t('Add item'), \];

It is important that the #name of the button is set explicitly, otherwise Drupal will set `$button['#name'] = 'op'`.

Also note that this button does not have a #submit function. This is ok, because all the logic will be in the #value\_callback.

Having the name on the button means that a click will be noticed in the `$input` parameter of the `#value_callback`.

2. In the `'#value_callback'` of the custom form element:

if (isset($input\['addmore'\])) { // Button was clicked. $form\_state\['complete form'\]\['#after\_build'\]\[\] = '\_MYMODULE\_form\_after\_build\_unset\_process\_input'; // Add an "empty" item. $values\[\] = NULL; }

Note: This is not the complete `#value_callback`! It is your job to figure out the rest.

3. Write the callback function:

function \_MYMODULE\_form\_after\_build\_unset\_process\_input(array $form, array &$form\_state) { $form\_state\['process\_input'\] = FALSE; return $form; }

Due to the way this function is registered, it really fires at the correct time.

4. Ajaxify.

The previous instructions give you a non-ajax version.

How to add AJAX behavior depends a lot on the use case, so I am going to omit this part.

Note: With AJAX, we can actually use `$form_state['input']['_triggering_element_name']` in the `#value_callback`, to determine which button was clicked. Note that at this time, `$form_state['triggering_element']` is not yet filled.

---
Tags: ajax, forms
---


# Question
Title: How to display a field collection as a responsive table?
I'm using *field collection* and *field collection table* modules to show the data as a table, but I want that the table is be responsive.

How I do it? I don't found a good solution.

For example, for views table I use responsive\_table\_filter module that accomplishes this task.

# Answer
> 0 votes
Unfortunately there isn't a good solution for displaying tabular data in a responsive way. Even big organizations like Wikipedia, Google, and GitHub display tables as horizontally scrollable entities.

If you can think of a way to display tabular data legibly with variable width, be sure to publish it. :)

---
Tags: views, entities, theming
---


# Question
Title: How do I run a site from a sub-directory?
I want to serve my Drupal site which is installed on example.com/drupal from example.com.

This particular site is an add-on site on my shared host, so the actual file structure is public\_html/example.com/drupal.

What should I do, change the *.htaccess* file or add a redirect from cPanel?

I can't imagine I'm doing anything radical, but I did not find any clear-cut answer.

# Answer
> 4 votes
On an Apache server, adding the following lines to the *.htaccess* file should help.

```
<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{REQUEST_URI} !drupal/
  RewriteRule (.*) /drupal/$1 [L]
</IfModule>

```

Those lines have not been fully tested. Use them at your risk.

---
Tags: 8, installation, uri
---


title: Sql-sync issues with key length

text:
# Question
Title: Sql-sync issues with key length
I'm attempting to set up a new remote website for production, and push my development database to it. I've already rsync'ed the files, and set up a new settings.php for the remote site. However, when running `drush sql-sync @local @remote`, I'm getting a `query failed` error. Manually importing the dump on the remote yields the following error:

`ERROR 1071 (42000) at line 677: Specified key was too long; max key length is 767 bytes`

Manually changing the dump to use CHARSET utf8 on the column where the key is too long fixes the issue. However, this happens in a lot of tables. Besides, not having the same charset on both sites is probably asking for issues.

According to this answer, this is the issue with an InnoDB table. However, this is the `show create table` for one of the tables affected, on the source site:

```
cache_entity_registration_type | CREATE TABLE `cache_entity_registration_type` (
  `cid` varchar(255) NOT NULL DEFAULT '' COMMENT 'Primary Key: Unique cache ID.',
  `data` longblob COMMENT 'A collection of data to cache.',
  `expire` int(11) NOT NULL DEFAULT '0' COMMENT 'A Unix timestamp indicating when the cache entry should expire, or 0 fo
r never.',
  `created` int(11) NOT NULL DEFAULT '0' COMMENT 'A Unix timestamp indicating when the cache entry was created.',
  `serialized` smallint(6) NOT NULL DEFAULT '0' COMMENT 'A flag to indicate whether content is serialized (1) or not (0)
.',
  PRIMARY KEY (`cid`),
  KEY `expire` (`expire`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='Cache table used to store registration_type entity r
ecords.'

```

As you can see, it's also an InnoDB table, with a primary key that's 255 characters long, with an utf8mb4 encoding. That's also longer than the maximum key length of 767 bytes of InnoDB.

What can I change on either the server or client to allow me to use sql-sync to sync between the two sites?

# Answer
I remembered I changed my existing Drupal installation to support utf8mb4 on my tables, as described here: https://www.drupal.org/project/utf8mb4\_convert.

Basically, the answer is that I have to change the settings on my target server as follows:

```
In order to allow for large indexes, MySQL must be set up with the following my.cnf settings:
[mysqld]
 innodb_large_prefix=true
 innodb_file_format=barracuda
 innodb_file_per_table=true

```
> 0 votes

---
Tags: database, drush
---


title: Multistep/wizard forms

text:
# Question
Title: Multistep/wizard forms
I'm trying to create a multistep/wizard form for Drupal 8.

* User fills in a first name, last name fields
* Clicks on the next button
* Fills out more information
* Clicks on the submit button

There are currently many resources devoted to multistep or wizard forms for Drupal 7 like this one and this.

On the other hand, I've had some trouble figuring out which is "Drupal" way of creating Drupal 8 multistep/wizard forms.

I did some research and figured there are several approaches:

Are those valid approaches for Drupal 8?

# Answer
> 13 votes
The easiest way to do this is to use $form\_state. In your formBuild() method, you have an if/else or switch based on something like `$form_state['step']` and display different form elements. Then you either have the same in your submit callback or have multiple submit callbacks, that do something to an object in $form\_state that you're building, change the step and set the `$form_state['rebuild']` flag to TRUE.

There are a few downsides to that approach, which is why (among other reasons) the ctools form wizard was created. It can get complicated if you have multiple steps and have to define all of that in a single form function/class and everything happens in POST requests.

What the ctools form wizard does is group multiple, separate forms together and control the navigation from one to the other. You also use the ctools object cache to store your object instead of $form\_state, because that is no longer shared across your forms.

While that system doesn't exist yet, the ctools object cache has been ported to 8.x and is now called user tempstore, available as a service: `\Drupal::service('user.private_tempstore')` (before *8.0-beta8* called `user.tempstore`). This is a layer on top of the expirable key value store that introduces ownership of stored data in there. So this is what powers the well known message in views that a different user is currently editing that view and it's locked for that reason. Another advantage over using $\_SESSION for that is that your data only has to be loaded when needed, when you are editing 3 views, then using $\_SESSION would mean that you have to load and carry them around on every single page request.

If you don't need that, then you could rely on the session or also directly put it in an expirable key value store ($form\_state is stored there now as well, not a pseudo-cache as it was in 7.x).

The configuration system however isn't a good match. That is not meant for per-user content (or content at all) as it doesn't really scale to store thousands or tens of thousands of records and might make some assumptions to pre-load everything it might need on a given page request (not yet, but there is an issue to make that happen)

# Answer
> 4 votes
Normally you can store form values between steps using either cTools object cache (similar to Multistep forms in Drupal 7), or through the `$form_state` (as per this tutorial).

In Drupal 8 you can inherit `FormBase` class to create a new multistep class.

In the article How to Build Multi-step Forms in Drupal 8 you can find a simple way to create a multistep form in Drupal 8.

First of all, you would need to create the base class which will be in charge of injecting the necessary dependencies.

> We will group all the form classes together and place them inside a new folder called `Multistep` located within the `Form` plugin directory of our demo module. This is purely for having a clean structure and being able to quickly tell which forms are part of our multistep form process.

Here is the demo code (for `MultistepFormBase.php` file):

```
/**
 * @file
 * Contains \Drupal\demo\Form\Multistep\MultistepFormBase.
 */

namespace Drupal\demo\Form\Multistep;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\SessionManagerInterface;
use Drupal\user\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;

abstract class MultistepFormBase extends FormBase {

  /**
   * @var \Drupal\user\PrivateTempStoreFactory
   */
  protected $tempStoreFactory;

  /**
   * @var \Drupal\Core\Session\SessionManagerInterface
   */
  private $sessionManager;

  /**
   * @var \Drupal\Core\Session\AccountInterface
   */
  private $currentUser;

  /**
   * @var \Drupal\user\PrivateTempStore
   */
  protected $store;

  /**
   * Constructs a \Drupal\demo\Form\Multistep\MultistepFormBase.
   *
   * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
   * @param \Drupal\Core\Session\SessionManagerInterface $session_manager
   * @param \Drupal\Core\Session\AccountInterface $current_user
   */
  public function __construct(PrivateTempStoreFactory $temp_store_factory, SessionManagerInterface $session_manager, AccountInterface $current_user) {
    $this->tempStoreFactory = $temp_store_factory;
    $this->sessionManager = $session_manager;
    $this->currentUser = $current_user;

    $this->store = $this->tempStoreFactory->get('multistep_data');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('user.private_tempstore'),
      $container->get('session_manager'),
      $container->get('current_user')
    );
  }

  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // Start a manual session for anonymous users.
    if ($this->currentUser->isAnonymous() && !isset($_SESSION['multistep_form_holds_session'])) {
      $_SESSION['multistep_form_holds_session'] = true;
      $this->sessionManager->start();
    }

    $form = array();
    $form['actions']['#type'] = 'actions';
    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
      '#button_type' => 'primary',
      '#weight' => 10,
    );

    return $form;
  }

  /**
   * Saves the data from the multistep form.
   */
  protected function saveData() {
    // Logic for saving data goes here...
    $this->deleteStore();
    drupal_set_message($this->t('The form has been saved.'));

  }

  /**
   * Helper method that removes all the keys from the store collection used for
   * the multistep form.
   */
  protected function deleteStore() {
    $keys = ['name', 'email', 'age', 'location'];
    foreach ($keys as $key) {
      $this->store->delete($key);
    }
  }
}

```

Then you can create the actual forms class inside a file called `MultistepOneForm.php`:

```
/**
 * @file
 * Contains \Drupal\demo\Form\Multistep\MultistepOneForm.
 */

namespace Drupal\demo\Form\Multistep;

use Drupal\Core\Form\FormStateInterface;

class MultistepOneForm extends MultistepFormBase {

  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'multistep_form_one';
  }

  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $form = parent::buildForm($form, $form_state);

    $form['name'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Your name'),
      '#default_value' => $this->store->get('name') ? $this->store->get('name') : '',
    );

    $form['email'] = array(
      '#type' => 'email',
      '#title' => $this->t('Your email address'),
      '#default_value' => $this->store->get('email') ? $this->store->get('email') : '',
    );

    $form['actions']['submit']['#value'] = $this->t('Next');
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->store->set('email', $form_state->getValue('email'));
    $this->store->set('name', $form_state->getValue('name'));
    $form_state->setRedirect('demo.multistep_two');
  }
}

```

> In the `buildForm()` method we are defining our two dummy form elements. Do notice that we are retrieving the existing form definition from the parent class first. The default values for these fields are set as the values found in the store for those keys (so that users can see the values they filled in at this step if they come back to it). Finally, we are changing the value of the action button to Next (to indicate that this form is not the final one).
>
> In the `submitForm()` method we save the submitted values to the store and then redirect to the second form (which can be found at the route `demo.multistep_two`). Keep in mind that we are not doing any sort of validation here to keep the code light. But most use cases will call for some input validation.

And update your routing file in the demo module (`demo.routing.yml`):

```
demo.multistep_one:
  path: '/demo/multistep-one'
  defaults:
    _form: '\Drupal\demo\Form\Multistep\MultistepOneForm'
    _title: 'First form'
  requirements:
    _permission: 'access content'
demo.multistep_two:
  path: '/demo/multistep-two'
  defaults:
    _form: '\Drupal\demo\Form\Multistep\MultistepTwoForm'
    _title: 'Second form'
  requirements:
    _permission: 'access content'

```

Finally, create the second form (`MultistepTwoForm`):

```
/**
 * @file
 * Contains \Drupal\demo\Form\Multistep\MultistepTwoForm.
 */

namespace Drupal\demo\Form\Multistep;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;

class MultistepTwoForm extends MultistepFormBase {

  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'multistep_form_two';
  }

  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $form = parent::buildForm($form, $form_state);

    $form['age'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Your age'),
      '#default_value' => $this->store->get('age') ? $this->store->get('age') : '',
    );

    $form['location'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Your location'),
      '#default_value' => $this->store->get('location') ? $this->store->get('location') : '',
    );

    $form['actions']['previous'] = array(
      '#type' => 'link',
      '#title' => $this->t('Previous'),
      '#attributes' => array(
        'class' => array('button'),
      ),
      '#weight' => 0,
      '#url' => Url::fromRoute('demo.multistep_one'),
    );

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->store->set('age', $form_state->getValue('age'));
    $this->store->set('location', $form_state->getValue('location'));

    // Save the data
    parent::saveData();
    $form_state->setRedirect('some_route');
  }
}

```

> Inside the `submitForm()` method we again save the values to the store and defer to the parent class to persist this data in any way it sees fit. We then redirect to whatever page we want (the route we use here is a dummy one).
>
> We should now have a working multistep form that uses the `PrivateTempStore` to keep data available across multiple requests. If we need more steps, all we have to do is create some more forms, add them in between the existing ones and make a couple of adjustments.

# Answer
> 1 votes
The multistep wizard that you've mentioned, it's already integrated with CTools, see: Wizard Support for 8.x-3.x, so you may consider extending it in `your_module.services.yml`, e.g.

```
services:
  ctools.wizard.form:
    class: Drupal\MyModuleMultistep\Controller\MyWizardForm

```

then extend the class in `src/Controller/MyWizardForm.php`:

```
<?php

/**
 * @file
 * Contains \Drupal\MyModuleMultistep\Controller\MyWizardForm
 */

namespace Drupal\MyModuleMultistep\Controller;

/**
 * Wrapping controller for wizard forms that serve as the main page body.
 */
class MyWizardForm extends WizardFormController {

}

```

---
Tags: forms, 8
---


# Question
Title: How to Add more option for type radios use Ajax in Drupal 8
Hi I build Add more for radios when click button load ajax. This ajax only add more options for radios . But not working , how to build used ajax add more options for type radios form ? Thanks

This code example my demo:

```
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class DemoForm extends FormBase{

    public function getFormId()
    {
        return 'DemoForm';
    }
    public function buildForm(array $form, FormStateInterface $form_state,$param = array())
    {
        $form['wrapper_data'] = array(
            '#type' => 'container',
            '#attributes' => array('id' => 'wrapper_data'),
        );
        $form['wrapper_data']['data_media'] = array(
            '#type' => 'select',
            '#title' => 'List Media',
            '#options' => array('aaa','bbb','cccc'),

        );
        $form['wrapper_data']['load_more_data'] = array(
            '#type' => 'button',
            '#value' => 'Load More',
            '#ajax' => array(
                'callback' => '::AjaxLoadMore',
                'wrapper' => 'wrapper_data',
            ),
        );

        return $form;
    }

    public function AjaxLoadMore(array &$form,FormStateInterface $formState){

        $form['data_media']['#options'] += array('bbbb'); // Want Add more options for radios

        return $form['wrapper_data'];
    }
}

```

# Answer
> 3 votes
Here is the complete code example:

```
<?php
/**
 * @file
 * File: src/Form/MyExampleForm.php
 * Contains \Drupal\mymodule\Form\MyExampleForm.
 */
namespace Drupal\mymodule\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class MyExampleForm extends FormBase {

  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'example_form';
  }

  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['wrapper'] = array(
        '#type' => 'container',
        '#attributes' => array('id' => 'data-wrapper'),
        );

    /* // or:
    $form['wrapper'] = array(
      '#type' => 'fieldset',
      '#title' => $this->t('Example title'),
      '#tree' => FALSE,
      '#prefix' => "<div id='data-wrapper'>",
      '#suffix' => '</div>',
    );
    */

    /* // or:
    $form['#prefix'] = '<div id="data-wrapper">';
    $form['#suffix'] = '</div>';
    */

    $form['wrapper']['data_media'] = array(
        '#type' => 'radios',
        //'#title' => 'Title',
        '#options' => array('aaa','bbb','cccc'),
        );
    $form['wrapper']['more_data'] = array(
        '#type' => 'button',
        '#required' => TRUE,
        '#value' => 'Show more',
        // @see: https://api.drupal.org/api/drupal/core%21core.api.php/group/ajax/8.3.x
        '#ajax' => array(
          // The callback to invoke to handle the server side of the Ajax event.
          'callback' => [$form_state->getBuildInfo()['callback_object'], 'ajaxLoadMore'],
          // or: //'callback' => [$this, 'ajaxLoadMore'],
          // or: //'callback' => '::ajaxLoadMore',
          // @see: http://api.jquery.com/category/manipulation/
          //'method' => 'replace', // May be: 'replaceWith' (default), 'append', 'prepend', 'before', 'after', or 'html'.
          // The HTML 'id' attribute of the area where the content returned by the callback should be placed.
          'wrapper' => 'data-wrapper',
          ),
        );
    $form['wrapper']['submit'] = array(
        '#type' => 'submit',
        '#value' => $this->t('Confirm'),
        );

    return $form;
  }

  /**
   * Ajax handler for loading more radio options.
   */
  public function ajaxLoadMore(array &$form, FormStateInterface $form_state){
    // Add more options for radios.
    $trigger = $form_state->getTriggeringElement();
    if ($trigger['#value'] == 'Show more') {
      $form['wrapper']['data_media']['#options'] += array_merge($form['wrapper']['data_media']['#options'], ['bbbb']);
    }
    return $form['wrapper'];
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    $trigger = $form_state->getTriggeringElement();
    if ($trigger['#type'] === 'submit') {
      if (is_null($values['data_media'])) {
        $form_state->setErrorByName('data_media', t('Please select the option!'));
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    drupal_set_message($this->t('Your form has been submitted.'));
  }

}

```

# Answer
> 2 votes
Move the code to add more radios to form build:

```
  if ($form_state->getTriggeringElement()['#value'] == 'Load More') {
    $form['wrapper_data']['data_media']['#options'] += array('bbbb');
  }

```

You can use `getTriggeringElemement()` to identify the button by checking a property of the element, if you want this can be the ajax callback itself.

---
Tags: 8, forms, ajax
---


title: How to rebuild form after AJAX call

text:
# Question
Title: How to rebuild form after AJAX call
I'm attempting to allow the user to dynamically choose a number of fields based on a dropdown box using an ajax call, but I can't seem to get the ajax call to rebuild the form afterwards.

```
<?php
class AJAXexample extends BlockBase {
    public function blockForm($form, FormStateInterface $form_state) {
        if (empty($form_state->getValue('number'))) {
            $form_state->setValue('number', 3);
        }
        $form['columnNum'] = [
            '#title'   => t('Number of Columns'),
            '#type'    => 'select',
            '#options' => [
                1         => '1',
                2         => '2',
                3         => '3',
                4         => '4',
            ],
            '#default_value' => $this->configuration['columnNum'],
            '#empty_option'  => t('-select-'),
            '#ajax'          => [
                'callback'      => [$this, 'columnCallback'],
            ],
        ];
        for ($i = 0; $i < $form_state->getValue('number'); $i += 1) {
            $form['column'][$i] = [
                $i => [
                    '#type'       => 'details',
                    '#title'      => t('Column '.$numTitle),
                    '#open'       => FALSE,
                    'columnTitle' => [
                        '#type'      => 'textfield',
                        '#title'     => t('Column Title'),
                        '#value'     => $config[0]['columnTitle'],
                    ],
                ],
            ];
        return $form;
    }

    public function columnCallback(array &$form, FormStateInterface $form_state) {
        $form_state->setValue('number', 10);
        $form_state->setRebuild(true);
        return $form;
    }
}

```

The number of textfields is based on the form\_state variable 'number'. The callback columnCallback changes the form\_state variable to 10, and is fired when the 'columnNum' form field is changed. However the form isn't rebuilt with the new number of fields even though $form\_state-\>setRebuild(); is called. Is there a way to get the form to rebuild after an ajax call?

NOTE: I have already tried techniques such as replacing or appending the items of the form inside of the actual ajax call but when that happens none of the input into the replaced fields get passed to $form\_state.

UPDATE: After attempting 4k4's solution I receive an error

```
Recoverable fatal error: Argument 1 passed to Drupal\Core\Render\MainContent\AjaxRenderer::renderResponse() must be of the type array, null given, called in /Library/WebServer/Documents/aaep/web/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php on line 89 and defined in Drupal\Core\Render\MainContent\AjaxRenderer->renderResponse() (line 45 of /Library/WebServer/Documents/aaep/web/core/lib/Drupal/Core/Render/MainContent/AjaxRenderer.php).

```

The belief is that the error occurs because $form\['column'\] is returning null despite being created as a container in the blockForm function. I've attempted calling the callback in other ways like

```
'#ajax' => [
    'callback' => '::columnCallback',
]

```

and

```
'#ajax' => [
    'callback' => [$this, '\Drupal\my_examples\Plugin\Block\AJAXexample::columnCallback'],
]

```

But I receive the same error. Curiously, when I change the callback to return the entire $form instead of just $form\['column'\] it repeats the form (a copy of the form appears below the current form) and still without the proper number of columns.

# Answer
> 4 votes
First problem is to handle the value for the column number. On the first build get it from configuration, on a rebuild get it from the user input and put it in `$columnNum`.

The second is to decide, what part of the form changes in AJAX and put this in a div container with the id `columns-wrapper`.

```
class AJAXexample extends BlockBase {
    public function blockForm($form, FormStateInterface $form_state) {
        $columnNum = empty($form_state->getValue('columnNum')) ? $this->configuration['columnNum'] : $form_state->getValue('columnNum');
        $form['columnNum'] = [
            '#title'   => t('Number of Columns'),
            '#type'    => 'select',
            '#options' => [
                1         => '1',
                2         => '2',
                3         => '3',
                4         => '4',
            ],
            '#default_value' => $this->configuration['columnNum'],
            '#empty_option'  => t('-select-'),
            '#ajax'          => [
                'callback'      => [$this, 'columnCallback'],
                'wrapper'       => 'columns-wrapper',
            ],
        ];
        $form['column'] = [
            '#type' => 'container',
            '#attributes' => ['id' => 'columns-wrapper'],
        ];
        for ($i = 0; $i < $columnNum; $i += 1) {
            $form['column'][$i] = [
                $i => [
                    '#type'       => 'details',
                    '#title'      => t('Column '.$numTitle),
                    '#open'       => FALSE,
                    'columnTitle' => [
                        '#type'      => 'textfield',
                        '#title'     => t('Column Title'),
                        '#value'     => $config[0]['columnTitle'],
                    ],
                ],
            ];
        return $form;
    }

```

In the callback we only need to return the ajax wrapper.

```
public function columnCallback(array&$form, FormStateInterface $form_state) {
    return $form['column'];
}

```

Drupal rebuilds the form on every ajax request and puts it in the parameter `$form` of the callback. It would make no sense to try to rebuild it again.

# Answer
> 2 votes
I guess you're missing `wrapper` method in your `'#ajax'` (next to `callback`) which consist the HTML `id` attribute of the area where the content returned by the callback should be placed. See: Ajax API. Then you've to make sure such container `id` exist.

Code example (simplified):

```
public function blockForm($form, FormStateInterface $form_state) {
    $form['wrapper'] = array(
        '#type' => 'container',
        '#attributes' => array('id' => 'data-wrapper'),
        );
    $form['wrapper']['columnNum'] = [
        '#title'   => t('Number of Columns'),
        '#type'    => 'select',
        '#options' => [1 => '1', 2 => '2'],
        '#default_value' => $this->configuration['columnNum'],
        '#ajax'          => [
            'callback'   => '::columnCallback',
            'wrapper'    => 'data-wrapper',
        ],
    ];
}
public function columnCallback(array &$form, FormStateInterface $form_state) {
    return $form['wrapper'];
}

```

---

For complete code example, see: How to Add more option for type radios use Ajax in Drupal 8.

---
Tags: forms, 8, ajax
---


title: Image{cache,style} for compression?

text:
# Question
Title: Image{cache,style} for compression?
Has anyone seen modules that provide image effects for post-generation compression?

I'm thinking things like running the image through a tool like optipng, or similar.

# Answer
For Drupal 7, the best thing I've seen/used for this is ImageAPIOptimize.

To use it properly you can either use an external toolkit like Yahoo SmushIT! or different options on your server like optipng as you mention above, among others. See screenshot for partial config screen. I've run tests with GD, ImageMagick and this module and it produces the best results (in my testing).

Config screen from admin/config/media/image-toolkit:
> 6 votes

# Answer
Try reSmush.it image style optimizer. It's implemented as an image style effect. It has no dependency modules or libraries, and no subscription. See https://www.drupal.org/project/resmushit
> 0 votes

---
Tags: media
---


# Question
Title: How to display views titles by categories
I have a content type which has **category** field.

I added few nodes. Each node has a value from **category**.

I would like to display a views block which should display titles grouped by category. That means:

Category 1

title

title

title

Category 2

title

title

title

**I created a views block:**

Format: Unformatted list

Fields: Title

Now, I have list of titles. I am not sure how I can add category(non linked) before the relevant titles?

# Answer
> 1 votes
You can group content based on the field. Click the format settings in View,

select the field here and group the content

**NOTE:** Grouping field should be added in the field area and then field will be shown in the grouping select list.

---
Tags: views
---


# Question
Title: Is translation an option in Drupal 8's logger?
Drupal 7's `watchdog()` function has a transaltable `$message` and a `$variables` argument.

The logger in Drupal 8 doesn't seem to have option. Is it recommended to pass the output of `t()` to logger?

# Answer
> 2 votes
No, don't use `t()` for logger messages. The messages are going to be translated already and you don't want to translate twice.

Example for the cron message:

```
    $logger->notice('Starting execution of @module_cron(), execution of @module_previous_cron() took @time.', [
      '@module' => $module,
      '@module_previous' => $module_previous,
      '@time' => Timer::read('cron_' . $module_previous) . 'ms',
    ]);

```

This is the same as in a `t()` function. The difference is that the messages are stored untranslated and will only be translated on runtime so that the message can be displayed in each user's language.

---
Tags: i18n-l10n
---


title: Install a new module without FTP

text:
# Question
Title: Install a new module without FTP
Am new to drupal, am working on version 8.3.5 trying to install a new module administration menu to my localhost without FTP.

I have extracted all files of module to /sites/all/modules folder.The menu is displaying in 'Extend' section but not displaying in my website.

The modules are 'checked' too, but how to enable it and display in my website? Thanks

I have executed this command sudo chown -R www-data sites/all/modules too.

1. Current output:-(Only one admin toolbar already there after installation of drupal)

2. Current Settings in Extend section: (Admin toolbar always checked and unable to uncheck too.How to activate and deactivate this module here?)
3. Expected Output is two admin toolbar like this:- (Below screenshot is an example of administration menu module in drupal7)

Thanks

# Answer
> 1 votes
You wont get double menu's as shown in screenshot. Admin Toolbar extends core toolbar to show as drop-down. Kindly refer Admin Toolbar for more information

# Answer
> 0 votes
Download module and extract into modules folder (for drupal 8)

or you can run this command

sudo chown www-data:www-data -R /var/www/drupal folder name/ (For ubuntu)

---
Tags: 8, commerce
---


# Question
Title: What is the equivalent of Drupal.settings.basePath?
I'm trying to get the site URL in JavaScript. In Drupal 7, this is stored in `Drupal.settings.basePath`. What's the Drupal 8 equivalent?

# Answer
In Drupal 8 this setting is:

```
drupalSettings.path.baseUrl

```

You find more in `core/module/system/system.module`:

```
function system_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
  ...
    $path_settings = [
    'baseUrl' => $request->getBaseUrl() . '/',
    'pathPrefix' => $pathPrefix,
    'currentPath' => $current_path,
    'currentPathIsAdmin' => $current_path_is_admin,
    'isFront' => \Drupal::service('path.matcher')->isFrontPage(),
    'currentLanguage' => \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId(),
  ];

  ...

```
> 17 votes

# Answer
Use Drupal.url()

ref: docroot/core/misc/drupal.js
> 3 votes

---
Tags: 8, javascript
---


# Question
Title: Users aren't redirected to the front page after account cancellation
I have a problem with account cancellation. The proccess itself executes fine, but after the batch proccess runs, the user isn't redirected to the front page as mentioned in the `UserController::confirmCancel` method:

```
user_cancel($edit, $user->id(), $account_data['cancel_method']);
// Since user_cancel() is not invoked via Form API, batch processing
// needs to be invoked manually and should redirect to the front page
// after completion.
return batch_process('');

```

This results in 403 error, as anonymous users don't have access to `en/user/2/cancel/confirm/...` path. I tested in in 2 different sites, using Drupal 8.2 and 8.3

How can I redirect user properly in this situation?

# Answer
I solved it using custom service. Will post it here shortly.
> 0 votes

---
Tags: users
---


# Question
Title: How can i render webform on custom url with custom html in drupal 8
Basically I am using sample code which shown in below.

public function test(){

```
$webform = \Drupal::entityTypeManager()->getStorage('webform')->load('contact_us');
$webform = $webform->getSubmissionForm();
$dd= drupal_render($webform);

return array(
'#type'=> 'markup',
'#markup' => $dd.'<div><p>test</p></div>'

);

}

```

I'm using return type markup then form is not rendering properly.So any help available. Thank you all in advance.

# Answer
This should work if you `return $webform;` without rendering. Or use the webform render element, then you don't need to load the form:

```
return [
  'test1' => ['#markup' => '<div><p>test1</p></div>'],
  'form' => [
    '#type' => 'webform',
    '#webform' => 'webform_id',
  ],
  'test2' => ['#markup' => '<div><p>test2</p></div>'],
];

```
> 1 votes

---
Tags: theming, 8, webforms, page-controller
---


# Question
Title: How to add AJAX call back from another AJAX result in a form
I want to use 2 AJAX call back within a form. The scenario is like I am having a text field and a Search button which is defined in the form alter function. After entering a text and clicking on the Search button, will display some matching strings with some other information from database as an HTML in **ul li a** format.

I had made each string as a form element **link** and displaying under the search field. Now, I need to add AJAX callback to this link and after clicking on any string, the whole HTML content has to be removed and some other new text fields should be displayed in the form and the selected string should be placed on the text field.

Please see below codes.

FORM ALTER

```
  $form['searchbutton'] = array(
      '#type' => 'button',
      '#value'=> t('Search'),
      '#id'   => 'search_button',
      '#ajax' =>  array(
          'callback' => 'ajax_search_callback',
          'wrapper' => 'search-list-wrapper',
          'method' => 'replace',
          'effect' => 'fade',
          'progress' => array('type' => 'none'),
        )
     );

```

Below code is the first AJAX call on button click

```
/**
     * AJAX call back
     */
function ajax_search_callback($form, $form_state) {

//getting matching list from database with respect to search text
// $search_results

 $form['link-lists'] = array(
        '#type' => 'item',
        '#prefix' => "<ul>",
        '#suffix' => "</ul>",
    );
 foreach ($search_results as $key => $result) {
        $result_html = "<p class=\"matching-title\">" . $result['title'] . "</p>
                <p class=\"matching-desc\">" . $result['description'] . "</p>";

        $form['link-lists']['options'.$key] = array(
            '#type' => 'link',
            '#prefix' => "<li class=\"matching-list-item\">",
            '#suffix' => "</li>",
            '#title' => $result_html,
            '#href' => '#',
            '#options' => array(
              'html' => true,
            ),
            '#ajax' => array(
              'wrapper' => 'search-list',
              //'method' => 'html',
              'callback' => 'select_ajax_callback',
            )
      );

 }
  $commands = array();
  $commands[] = ajax_command_replace('#descriptions-list', drupal_render($form['link-lists']));
  $page = array('#type' => 'ajax', '#commands' => $commands);
  return $page;

}

```

I think, the second AJAX call back **select\_ajax\_callback** given for the form item link is not correct. It would be thankful if anyone can help me on below questions?

1. How to set callback for a form item link? Please correct me.
2. How I will get $form and $form\_state values in the function **select\_ajax\_callback**. And in this function I need to return another form element which is already defined in the form alter.

Thank You.

# Answer
You are adding form elements in the ajax callback. These will never work, as the form has already been cached before the ajax callback is reached. You need to add your form elements in the original form definition, or a \_form\_alter hook. Use values in the form state to determine whether or not the form has already been submitted.
> 0 votes

---
Tags: 7, forms, ajax
---


# Question
Title: Invalid Argument Exception when saving a view using a custom filter handler
I am working on a project which implements a custom views filter; more specifically based on the *InOperator* class.

I have been following the guide below to implement the custom filter: Creating a custom Views filter in Drupal 8 and the repo used in that guide may be obtained here: Accompanying GitHub repo

Everything works with both my custom filter, and the filter provided in the referenced guide whilst inspecting in the views preview, however when the view is saved, the website crashes with the following error:

**InvalidArgumentException: The configuration property display.default.display\_options.filters.node\_titles.value.my\_title doesn't exist. in Drupal\Core\Config\Schema\ArrayElement-\>get() (line 74 of core/lib/Drupal/Core/Config/Schema/ArrayElement.php)**

Any advice on how to fix this or if there are any steps that have been missed out would be greatly appreciated; even if a link could be provided to more recent documentation as I have not found much on this subject other than reading through the base classes. Even then I cannot find any reference to the error which is displayed.

**To reproduce**

* Download the module in the linked repo and enable on a D8 site.
* Create a view of nodes.
* Add the 'Node titles' filter and select an option.
* Save the view.

Many thanks in advance.

# Answer
> 4 votes
The problem here is that there is no schema definition defined for the new custom filter.

You need to create a file in config/schema/YOUR\_MODULE.views.filter.yml

With the following definitions with the machine names to match your specific setup.

```
views.filter.YOUR_VARIABLE:
  type: views_filter
  label: 'Example'

views.filter_value.YOUR_VARIABLE:
  type: views.filter_value.in_operator
  label: 'Example'

```

---
Tags: 8, views
---


title: How to use field_info_instance?

text:
# Question
Title: How to use field_info_instance?
I am currently working with an Entity Reference field in Drupal 7, and I need to alter the results using `field_info_instance`. The field type is Entity Reference. Below are the steps I've taken:

```
$field_instance = field_info_instance('node', 'field_branch_vod', 'employee');
kpr($field_instance);

```

Could you please provide guidance on how to use `field_info_instance` to effectively alter the field results for an Entity Reference field?

# Answer
> 0 votes
Neither of those bits of information relate to the instance, they relate to the field itself (regardless of what it's attached to).

As such you need to use `field_info_field()` to get them:

```
$field_info = field_info_field('field_branch_vod');
$target_type = $field_info['settings']['target_type'];
$target_bundles = $field_info['settings']['handler_settings']['target_bundles'];

```

---
Tags: 7, entities
---


# Question
Title: Is that possible to single sign-on with completely different domains?
we have multilingual Drupal 7 site.

> Swedish Domain : www.swedish.com
>
> English Domain : www.english.com

admin/config/regional/language looks like screenshot.

No Domain access is used. I have tried https://www.drupal.org/project/sso\_multi\_domain but seems there need sub-domains.

Please suggest is there way we can make login working with separate domains which are pointing to same site folder, same database etc

Thanks!

# Answer
Have you tried the Domain module? I've looked into it a bit, and seems to do what you need (though I myself have not set up my site yet with it, so I'm not positive). According to the documentation:

> The module allows you to share users, content, and configurations across a group of sites such as:
>
> * example.com
> * one.example.com
> * two.example.com
> * my.example.com
> * thisexample.com \<-- can use any domain string
> * example.com:3000 \<-- treats non-standard ports as unique

https://www.drupal.org/project/domain
> 0 votes

---
Tags: 7, authentication-authorization
---


# Question
Title: Showing "New content" form on main theme
I'm using drupal 8 I have a page with diferent content types like "beers, wines, etc". I want to let users publish their own content inside this content types, but I want a form in the main theme, no administration theme. How can I do it?

# Answer
> 0 votes
In Drupal 8 there is the entityform\_block module which gives you the option to display an entity form as a block. You just need to go to Blocks, select Place block in the region you want and select Entity form. When you add your from you can select Entity Type + Bundle, where you have to select your content type and also in which pages you what this block being visible.

Keep in mind that using this way, on submit the user will be redirected to the content page but you can write your custom handler using hook\_form\_alter.

---
Tags: theming, nodes, forms, users
---


title: Create node with angularjs

text:
# Question
Title: Create node with angularjs
I have created web service of content and views that will export content in JSON format. Now I'm getting node data with simply call web service path with $http.get(...) It will successfully loads the all node. But Im not able to create(actually don't know how to create) with Drupal web service and angularJs.

# Answer
> 1 votes
You Should mention for which drupal version you needs solution. Anyways, in drupal you need to mention for what you actions you are creating REST service. Like for reading a post, or creating a post or maybe to update or delete a post or user or any other entity. There are several tutorials out there. If you would google, then you will easily find one. However, by following below link you can easily create REST service for creating a node also.

https://www.drupal.org/docs/8/core/modules/rest/javascript-and-drupal-8-restful-web-services

Hope this helps, if you need solution for Drupal 7 then google it, you will get numerous. If you are a visual learner then there are also good quality video tutorials on youtube as well.

---
Tags: nodes
---


# Question
Title: Determining content access by role for viewing content?
Here is the scenario:

* I have 10 roles (plus the 3 core roles, anon, auth, administrator).
* I have 7 roles imported from an outside system.
* Users can belong to multiple roles.
* Editors need to be able to check off in a list of these roles when editing content, as to *whom* can view the content.
* If none are selected, anyone can view.
* A user only needs to possess **one** of the roles checked off in order to have access.

There does not seem to be a solid solution for Drupal 8 out there. Content Access is unfinished, Permissions by Term is too restrictive, and Access by Entity currently does not work.

What is the path of least resistance to enabling view based access if the options are enabled? Where can I start?

# Answer
To further complete the list of content access modules you mentioned, i.e.:

> There does not seem to be a solid solution for Drupal 8 out there. Content Access is unfinished, Permissions by Term is too restrictive, and Access by Entity currently does not work.

I recommend you have a look at the Group module, which allows for creating arbitrary collections of your content and users on your site, and grant access control permissions on those collections.

**Group** creates groups as entities, making them fully fieldable, extensible and exportable. Every group can have users, roles and permissions attached to it. Groups can also act as a parent of any type of entity. Group provides an extensive API to attach entities to groups.

# Sample configuration

Below is an example of a possible configuration, which may help to get you started with possible configurations (using the Group module):

```
Group type ID ! Group type ! Group role ID ! Role
--------------+------------+---------------+------------
 1            ! Class      ! 3             ! Instructor
 1            ! Class      ! 4             ! Student
 2            ! Customers  ! 5             ! Lead
 2            ! Customers  ! 6             ! Prospect
 2            ! Customers  ! 7             ! Licensed Customer
 2            ! Customers  ! 8             ! Sales
 2            ! Customers  ! 9             ! Support
 2            ! Customers  ! 10            ! Accounting
 2            ! Customers  ! 11            ! R&D
 3            ! Project    ! 12            ! Project Manager
 3            ! Project    ! 13            ! Developer
 3            ! Project    ! 14            ! Customer

```

### Group Types

The above example consists of 3 ***group types***:

* Class.
* Customers.
* Project.

### Group Roles

For each of the 3 group types, there are specific ***Roles*** defined, some more details about some of them:

* for the *Class* group, these are the 2 roles that are configured:
    + Instructor.
    + Student.
* for the *Project* group, these are the 3 roles that are configured:
    + Project Manager.
    + Developer.
    + Customer.

These are the *Group Specific Roles*: these roles can be configured per group type and will only be available on groups of that group type. As an example, for group type "*Class*", the defined roles are **Instructor** and **Student** (which are not available for the other group types).

On top of the group specific roles, there are also *Special Global Roles*: These are the special (hardcoded) roles named **Outsider** (= a signed in user that did not join a group) and **Member** (= a signed in user that did join a group). These cannot be defined by the Drupal administrator, and they are always available for any group. These roles can have different permissions sets for each group type. Special case: the role **Anonymous** is related to a user that is not signed.

### Groups

Each of the configured group types can have any number of ***Groups***.

Examples of groups:

* for the *Class* group type, there could be these **Groups**:
    + Getting started with Drupal.
    + Drupal for site builders.
    + Become an expert in using the Rules module.
* for the *Customers* group type, there could be these **Groups**:
    + Service Requests.
    + Order Processing.
    + Sales Orders.
    + Relationship Management.

### Permissions

For each of the configured group types, you can then also configure for each ***Content Type*** which ***Role*** has what kind of access (= none, view, create, edit, delete). Be aware: even though this looks similar to Drupal's permission configuration, these permissions are not the same permissions (they are specific to the Group module).

# Module integrations

The Group module integrates with various other (popular) modules, such as Views, Rules, etc. These integrations are more or less out-of-the box (not dozens of extra modules needed to make those integrations work). Simply because everything is entity based.

# Resources

**PS**: this answer applies to either D7 or D8.
> 1 votes

---
Tags: 8, users
---


# Question
Title: How to install a module which includes a different version of Symfony?
I am a developer and maintainer for the CiviCRM project. We've been trying to make a Drupal 8 version CiviCRM, and have a come a long way. We're beating our heads against our collective keyboards trying to figure a major blocker for the project.

CiviCRM has used Symfony for a while, and the version that is included is different than what ships with Drupal.

We can get CiviCRM installed with Drupal 8, but after you install it, we cannot install any other Drupal module.

I believe it boils down to a situation where somehow the CiviCRM version of Symfony loads before the Drupal version, and this causes problems.

Does anyone know of a Drupal 8 module that includes a different version of Symfony than the one that ships with Drupal?

Recently I ran across the Ludwig project. This module allows the registering of namespaces in a class that extends `ServiceProviderBase`.

Would it be possible for the Drupal 8 version of the CiviCRM module to include a CivicrmServiceProvider.php file, which defines a `CivicrmServiceProvider` class, and a `register()` method that adds a container namespace to allow this to work?

Many CiviCRM files have `use` statements like Drupal starting with Symfony, like here.

We actually put CiviCRM Core into Drupal doc\_root/libraries folder, and use the libraries module.

This is the repo for the CiviCRM Drupal module 8.x version, if somebody wants to look at what we got so far. If somebody has the magic elixir for this, I can tell you there would be many happy folks in our community. So if you know how to help us, please do.

CiviCRM does install, and the CiviCRM pages do work. What doesn't work is that after CiviCRM is installed, we can't install other modules via the admin/modules page. As far as I know that's the only thing that is broken. Also installing modules with Drush, after installing CiviCRM, does work.

Trying to install another module after CiviCRM is installed causes the following error:

> PHP Fatal error: Call to undefined method Symfony\Component\DependencyInjection\Definition::setFactory() in /var/www/html/civi-for-d8/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php on line 206

That's in Drupal 8.3.5. Trying to install CiviCRM for Drupal 8 into a clean Drupal 8.4-dev instance causes the following error:

> Drupal\Component\Serialization\Exception\InvalidDataTypeException: The reserved indicator "@" cannot start a plain scalar; you need to quote the scalar at line 8 (near "arguments: \[@string\_translation, @civicrm.page\_state\]"). in Drupal\Component\Serialization\YamlSymfony::decode() (line 40 of /var/www/html/drupal84/core/lib/Drupal/Component/Serialization/YamlSymfony.php).

# Answer
So, I think if CiviCRM were installed into Drupal 8 via composer (ie. `composer require civicrm/civicrm-core` in the Drupal root) and CiviCRM's use of Symfony was compatible with Symfony 2.8 or 3.x (ie. not using deprecated functionality), this could work.

This would get everything installed in Drupal's vendor directory, rather than having two, and it'd mean that CiviCRM would use the Symfony version in Drupal 8. But if CiviCRM was compatible with later Symfony versions (even if it bundled an older version for Drupal 6 & 7 and other CMS's) it should be fine.

~~I think?~~

**UPDATED:** Yes, it works - I tried it. :-) I originally posted the below in the CiviCRM issue queue (CRM-17652), but re-posting here for completeness.

# The big idea:

Since composer is pretty new to a lot of people, I'm going to attempt to go step by step, from some high-level composer stuff all the way to one way it could be done in CiviCRM:

* Composer allows applications to require the libraries it needs (and libraries, of course, can require other libraries).
* Libraries have a composer.json file which says what other libraries it needs and what versions it's compatible with (but not necessarily a specific single version - usually a range of versions, like `^2.4.3` which says a minimum of 2.4.3 and up to (but not including) 3.0.0)
* Applications have a composer.json which similarly describes needed libraries and compatibility with a range of versions, but the range is really to help with updating. An application will also have a composer.lock which is a specific set of individual versions
* Libraries can also have a composer.lock for their own testing or distribution (like building the release tarball with the dependencies bundled), but this is ignored when an application requires the given library (see https://getcomposer.org/doc/02-libraries.md#lock-file)
* When an application wants to require a new library, composer finds an intersection of version compatibility between all the things the application requires (including all the libraries already installed and their dependencies) and the new library, possibly doing some updates to make everything line up (or erroring out if it can't find a compatible mix of versions)
* In this case, CiviCRM is a library, and a particular Drupal 8 site is the application (Drupal core itself is a library)
* CiviCRM could say it "requires" Symfony `^2.5` in its composer.json which means it is compatible with versions 2.5.0 up to (but not including) 3.0.0
* When a Drupal 8 site wants to use CiviCRM, the site admin uses `composer require civicrm/civicrm-core` to require the CiviCRM library and all it's dependencies. If CiviCRM is compatible with Symfony 2.8 (like used in Drupal 8.3.x) everything will install and work fine, using the single Symfony 2.8 from Drupal. All the dependencies end up in Drupal's vendor directory.
* However, CiviCRM could keep Symfony 2.5 in its composer.lock, which means the tests would use that, and the tarballs for Drupal 6 & 7 and other CMS's would bundle Symfony 2.5

# The proposal:

1. Update the composer.json of CiviCRM so it can be used as a library by composer-based CMS's like Drupal 8 (but probably others could move that way in the future - composer is getting quite popular)
2. Make sure CiviCRM core is *compatible* with Symfony 2.8 and 3.0 (used by Drupal 8.3.x and 8.4.x respectively) but keep the "officially supported" version (currently Symfony 2.5) in the composer.lock for testing and the tarball for distribution. Being compatible with multiple Symfony versions may not be as hard as it sounds - there's a number of libraries out there compatible with both Symfony 2.8 and 3.0. It may just be a matter of avoiding deprecated methods/classes/features! The composer.json will need to be updated to reflect this
3. Use composer to install the CiviCRM library on Drupal 8 rather than copying into the libraries directory. This is becoming the normal way of installing 3rd party PHP libraries in Drupal 8 (this is used extensively by Drupal Commerce, for example)

For composer-based CMS's, I really think this is The Right Way. While this issue is currently affecting Symfony and Drupal, as the PHP community starts using more and more 3rd party libraries via composer, this could very well affect other CMS's with other version conflicts.

# Some working code to test:

So, as promised, I actually got this to work to a limited degree :-) I'm totally coming at this from a Drupal/Composer/Symfony perspective -- I don't have a ton of CiviCRM experience, so there's probably some better ways to do my process below. I welcome any advice!

1. Download and install Drupal 8.3.5 (or the latest dev of Drupal 8.4.x!)
2. Go into the root directory in the shell and run these commands to install CiviCRM via composer: https://gist.github.com/dsnopek/56311dbea347874e75180883efabb620
3. If you use Apache, remove the vendor/.htacess file. This is a security measure from Drupal, which prevents resources like CSS/JS being loaded. This will need some collaboration with the Drupal project to figure out a proper solution because removing this file altogether is a bad idea on production. See: vendor/.htaccess blocking CSS/JS assets from composer libraries.
4. Go into the /modules directory and do `git clone https://github.com/dsnopek/civicrm-drupal.git --branch composer-library`
5. Go to the "Extend" page (`/admin/modules`) and install the CiviCRM module
6. Clear drupal cache via Drush (`drush cr`)
7. Log out and log back in again per CRM-19878
8. CiviCRM works! :-)

After all of this, CiviCRM is using Symfony 2.8 from Drupal and the dependencies in Drupal's vendor directory, and isn't loading anything from it's own vendor directory. Huzzah!

I tested enabling the "Telephone" module which failed before these changes (see my steps to reproduce), but works fine with them. :-)
> 8 votes

# Answer
I don't think this is possible.

Drupal 8.4 actually already switched to Symfony 3 although there are still similar discussions related to drush, which has the same problem. see Drush 8.x doesn't install Drupal 8.4.x and Drush master doesn't install Drupal 8.3.x and Symfony components are updated to 3.2.6

It's not possible to load two different symfony versions, either you break your integration or you break Drupal. Maybe symfony3 will not be in 8.4 yet, but the security support for symfony2 will end before Drupal8 security support, so at some point, we will have to switch.
> 5 votes

# Answer
Theoretically the only issues here are the file location and class namespace. Unfortunately the only tools I know of in composer for doing that don't let you specify per VERSION, just per package name.

Have you tried setting it up as a completely separate autoloader?
> 1 votes

---
Tags: 8, civicrm
---


# Question
Title: How can I alter bundles of commerce_order_item entity type using custom module
I am trying to alter bundles of commerce\_order\_item -

`core.entity_form_mode.commerce_order_item.add_to_cart_confirmation.yml`

```
langcode: en
status: true
dependencies:
  module:
    - commerce_order
  enforced:
    module:
      - commerce_add_to_cart_confirmation
id: commerce_order_item.add_to_cart_confirmation
label: 'Add to Cart Confirmation'
targetEntityType: commerce_order_item
cache: true

```

`.module file`

```
function commerce_add_to_cart_confirmation_entity_bundle_info_alter(&$bundles){
  $storage = \Drupal::entityTypeManager()->getStorage('entity_form_display');
  foreach ($bundles['commerce_order_item'] as $bundle_key => $bundle_value) {
    if($bundle_key !== 'default'){
      $form_display = $storage->load('commerce_order_item.' . $bundle_key . '.add_to_cart_confirmation');
      if (!$form_display) {
        /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
        $form_display = $storage->create([
          'targetEntityType' => 'commerce_order_item',
          'bundle' => $bundle_key,
          'mode' => 'add_to_cart_confirmation',
          'status' => TRUE,
        ]);
        // Hide the unit price by default.
        $form_display->removeComponent('unit_price');
        // Hide the quantity by default.
        $form_display->removeComponent('quantity');
        $form_display->save();
        $form_display->enable();
      }
    }
  }
}

```

But at `$form_display->save();` is am getting below error -

```
Error: Call to a member function getConfigDependencyName() on null in /var/www/drupal/core/lib/Drupal/Core/Entity/EntityDisplayBase.php on line 314 #0 /var/www/drupal/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php(346): Drupal\\Core\\Entity\\EntityDisplayBase->calculateDependencies()\n#1 /var/www/drupal/core/lib/Drupal/Core/Entity/EntityDisplayBase.php(266): Drupal\\Core\\Config\\Entity\\ConfigEntityBase->preSave(Object(Drupal\\Core\\Config\\Entity\\ConfigEntityStorage), true)\n#2 /var/www/drupal/core/lib/Drupal/Core/Entity/EntityStorageBase.php(434): Drupal\\Core\\Entity\\EntityDisplayBase->preSave(Object(Drupal\\Core\\Config\\Entity\\ConfigEntityStorage))\n#3 /var/www/drupal/core/lib/Drupal/Core/Entity/EntityStorageBase.php(389): Drupal\\Core\\Entity\\EntityStorageBase->doPreSave(Object(Drupal\\Core\\Entity\\Entity\\EntityFormDisplay))\n#4 /var/www/drupal/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php(259): Drupal\\Core\\Entity\\EntityStorageBase->save(Object(Drupal\\Core\\Entity\\Entity\\EntityFormDisplay))\n#5 /var/www/drupal/core/lib/Drupal/Core/Entity/Entity.php(377): Drupal\\Core\\Config\\Entity\\ConfigEntityStorage->save(Object(Drupal\\Core\\Entity\\Entity\\EntityFormDisplay))\n#6 /var/www/drupal/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php(637): Drupal\\Core\\Entity\\Entity->save()\n#7 /var/www/drupal/modules/custom/commerce_add_to_cart_confirmation/commerce_add_to_cart_confirmation.module(116)

```

This is annoying because same code is running for hook\_confirmation\_entity\_bundle\_create($entity\_type\_id, $bundle). Please advice what should I do to save the bundle.If there is another way to achieve what I am trying to achieve, please tell me.

Thanks Guys

# Answer
> 1 votes
add\_to\_cart\_confirmation needs to be a a defined entity form mode, that's most likely the error in your case. Provide it as default configuration in your module or check its existence or create it if necessary.

See how node defines the teaser view mode as an example, or user the register form mode.

---
Tags: 8
---