Field Collection, adding new elements to it in form - drupal

I have a $form with a field collection "field_definition" which has 2 fields in it with unlimited cardinality. I can kind of create the fields by doing this in hook_form_alter:
$field_definition_template = $form['field_definition']['und'][0];
for($k=0;$k<count($column_names);$k++)
{
$form['field_definition']['und'][$k] = $field_definition_template;
$form['field_definition']['und'][$k]['#delta'] = $k;
}
The problem is the names are wrong, the ids are wrong and pretty much everything else. Is there a way to do this correctly?

You will want to work with hook_field_presave() in order to add the values to the field itself. Using Form API on fields does work, sometimes, but it will be cleaner if you switch over to using the Field API directly.

Related

How do I query a Drupal Shortcut (8.x/9.x) by its URL or Menu Path?

We're rolling out an update to an in-house Drupal installation profile, and one of the menu paths that is used frequently is getting changed. Most of our installations reference that menu path in a shortcut (via the "Shortcut" module in core). In an update hook, we'd like to be able to query for those shortcuts and update them.
It feels like this should be straightforward, but for some reason we're finding it difficult to query for shortcuts by their url. We can query them by title, but that seems fragile (since the title could be different between installations, might be different by localization, etc.).
We tried the following, but this lead to the error message 'link' not found:
// This does NOT work.
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link' => [
'internal:/admin/timeline-management',
],
]);
// This works, but is fragile.
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'title' => 'My shortcut',
]);
Based on the code in \Drupal\shortcut\Entity\Shortcut::baseFieldDefinitions() and \Drupal\shortcut\Controller\ShortcutSetController::addShortcutLinkInline() it's obvious that Shortcut entities have a property called link that can be set like an array containing a uri key, yet it does not seem possible to query by this property even though it's a base field.
Looking at the database, it appears that Drupal stores the URL in a database column called link__uri:
TL;DR That means that this works:
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link__uri' => 'internal:/admin/old/path',
]
);
Read on if you want to know the subtle reason why this is the case.
Drupal's database layer uses pluggable "table mapping" objects to tell it how to map an entity (like a Shortcut) to one or more database tables and database table columns. The logic for generating a column name for a field looks like this in the default table mapping (\Drupal\Core\Entity\Sql\DefaultTableMapping):
As shown above, if a field indicates it allows "shared" table storage, and the field has multiple properties (uri, title, etc.), then the mapping flattens the field into distinct columns for each property, prefixed by the field name. So, a Shortcut entity with link => ['uri' => 'xyz']] becomes the column link__uri with a value of xyz in the database.
You don't see this often with entities like nodes, which is why this seems strange here. I'm usually accustomed to seeing a separate database table for things like link fields. That's because nodes and other content entities don't usually allow shared table storage for their fields.
How does the mapping determine if a field should use shared table storage? That logic looks like this:
So, the default table mapping will use shared table storage for a field only under specific circumstances:
The field can't have a custom storage handler (checks out here since shortcuts don't provide their own storage logic).
The field has to be a base field (shortcuts are nothing without a link, so that field is defined as a base field as mentioned in the OP).
The field has to be single-valued (checks out -- shortcuts have only one link).
The field must not have been deleted (checks out; again, what is a shortcut without a link field?).
This specific set of circumstances aren't often satisfied by nodes or other content entities, which is why it's a bit surprising here.
We can confirm this by using Devel PHP to ask the table mapping for shortcuts directly, with code like the following:
$shortcut_table_mapping =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->getTableMapping();
$efm = \Drupal::service('entity_field.manager');
$storage_definitions = $efm->getFieldStorageDefinitions('shortcut');
$link_storage_definition = $storage_definitions['link'];
$has_dedicated_storage = $shortcut_table_mapping->requiresDedicatedTableStorage($link_storage_definition);
$link_column = $shortcut_table_mapping->getFieldColumnName($link_storage_definition, 'url');
dpm($has_dedicated_storage, 'has_dedicated_storage(link)');
dpm($link_column, 'link_column');
This results in the following:

Get request data (GET) in a Symfony (5) formType without using data_class

I'm building a formType to filter products on a collection page. You can set multiple select boxes which makes other auto filled or unnecessary. I want to be able to manipulate the formType based on the data like when using a data_class object. I'm not using data_class because the search isn't a persisted object which is saved to the database. I'm using a GET form.
For example 2 select boxes:
category
productType
When setting a category makes some of the productTypes unnecessary. So i want to not show it.
To do so in the formType I need the data of the request (GET) but I can't find a way to do so.
To retrieve data from the form, you can use $form->getData().
As you're in a GET context, I suspect you can take advantage from FormEvents (take a closer look to POST_SET_DATA event) and get rid of values you don't need.
One other thing I would like to point out, is that you still can use some kind of object that's not persisted to DB, like DTO or whatever.
Forms and entities are not related anyhow, neither in the usage nor in the intentions.

Is there anyway to pass dql to doctrine criteria

I am using Symfony3 framework, and I have user entity, and file entity. I wanted to present in sonata administration user list with sum of all size files which are uploaded by user. When I want to make that field sortable I am getting error:
`Catchable Fatal Error: Argument 1 passed to Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery::entityJoin() must be of the type array, null given, called in /home/milos/sites/coinaphoto/vendor/sonata-project/doctrine-orm-admin-bundle/Datagrid/ProxyQuery.php on line 143 and defined`
I have custom function in User entity which is calculating sum of files. It returns string.
My question will be can I somehow pass dql to criteria in order to get sum. Or can you suggest some other way to implement this?
` public function getStoragge(){
$criteria = Criteria::create()
->where(Criteria::expr()->someexpression...);
$matches = $this->file->matching($criteria);
}`
Something similar like when you need to aggregate fields
` $dql = "SELECT SUM(e.amount) AS balance FROM Bank\Entities\Entry e " .
"WHERE e.account = ?1";
$balance = $em->createQuery($dql)
->setParameter(1, $myAccountId)
->getSingleScalarResult();`
I don't know about your dql thing, but some fact about sorting in Sonata Admin table views. The problem is, that sorting actions still be made in the background with database operations, no matter what you are doing "virtual" in your model. If you are adding just a method to your model, the datagrid is not able to involve this method/property in sorting.
My experience is, that you can't sort by fields which are not physically available in the corresponding table. Even if you write the whole query for yourself, if you click on the sort buttons, a complete other query is fired which is ignoring your request.
I'll be pleased if somebody tell me the contrary ...
See also this issue https://github.com/sonata-project/SonataAdminBundle/issues/1077

Is there documentation for non-dynamically adding a 'many' to a 'one' in a 'one-to-many' relationship?

I have a Customer who has several PhoneNumbers.
The user creates a new Customer via a form, and I want him to be able to specify a single PhoneNumber.
Symfony's documentation tells me how to do this if the user were creating a PhoneNumber and had to also specify a Customer (link). It also tells me how to solve my problem using some Javascript, as described by the Cookbook's recipe for dynamically adding entities (link).
What I'm missing is the part of the documentation where it simply describes a non-dynamic form that lets you add a single entity upon submission. So, the user fills out the customer's details, puts a phone number, and everything works out.
I suppose I could make a separate form, give it a PhoneNumberType, and then upon submission, call $customer->addPhoneNumber($phoneNumber). But it seems like there should be a way to handle it through the relationships alone & in a single form.
Coming back to this question, I realize the answer is simple. In my controller,
// CustomerController.php
$customer = new Customer();
$phoneNumber = new PhoneNumber();
$customer->addPhoneNumber($phoneNumber);
Now when I build my form, I'll have a single blank PhoneNumber associated with the new Customer, and everything will persist as expected.

Drupal 6 custom submit function to alter submitted node data

I have written a module that uses hook_form_alter to add a custom submit function to the node form. This function is not intended to remove the original node submit function, it is there simply to alter node data before it is inserted into the database.
The problem is that when I print_r the posted form array from inside my module when a node is added, the array is massive and it seems the posted data repeats numerous times. I need to know, which part(s) of this array I should be altering so that my altered values are inserted into the database.
To expand a little bit, the module works in the following way: My module attaches a custom submit function to the node form. A user submits a node (containing numerous CCK fields). Some of these fields are left empty. My custom submit function finds these fields and adds a value to them. The node is then inserted into the database.
The module and function I am using work perfectly, but I just can't seem to find what part of the submitted array needs to be altered so that the custom data will be inserted by the node module's own submit function. I would post the array but due to the size, it's probably not advisable, although if anyone would like it I could send it somehow.
Finally, I know there are easier ways of doing similar to what I am trying to achieve but unfortunately this is the only option in the circumstances.
Apologies for wasting anyone's time, I was looking at the $form array when in fact the submitted values are stored in $form_state['values'].

Resources