Map array to entity in Symfony2/Doctrine2 - symfony

I'm using the DoctrineFixtures bundle to create example entities during development. In my ORM fixtures load() method, I define the data as associative arrays and create the entity object in a loop.
<?php
// ...
public function load($manager) {
$roleDefs = array(
'role-1' => array(
'role' => 'administrator'
),
'role-2' => array(
'role' => 'user'
),
);
foreach($roleDefs as $key => $roleDef) {
$role = new Role();
$role->setRole($roleDef['role']);
$manager->persist($role);
$this->addReference($key, $role);
}
$manager->flush();
}
I always use the same array schema. Every array element uses the property name (in underscore notation) of the entity as index. If the entity structure becomes more complex, there are a lot of $entity->setMyProperty($def['my_property']); lines.
I think the problem of mapping propertynames to setter methods is a very common problem in Symfony and Doctrine as this type of mapping is found in many situations (e.g. mapping forms to entities).
Now I'm wondering if there is a built-in method that can be used for mapping. It would be nice to have a solution like
foreach($defs as $key => $def) {
$entity = $magicMapper->getEntity('MyBundle:MyEntity', $def);
// ...
}
Has someone an idea how this can be achieved?
Thanks a lot,
Hacksteak

I sometimes use loops when creating fixtures. I'm not sure if this solution fits your requirements, but I find that the most flexible way to build fixtures and quickly add new properties over time if you need is to do the following... Assuming the creation of a bunch of blog posts:
// an array of blog post fixture values
$posts = array(
array(
'title' => 'Foo',
'text' => 'lorem'
'date' => new \DateTime('2011-12-01'),
),
array(
'title' => 'Bar',
'text' => 'lorem'
'date' => new \DateTime('2011-12-02'),
),
// more data...
);
// loop over the posts
foreach ($posts as $post) {
// new entity
$post = new Post();
// now loop over the properties of each post array...
foreach ($post as $property => $value) {
// create a setter
$method = sprintf('set%s', ucwords($property)); // or you can cheat and omit ucwords() because PHP method calls are case insensitive
// use the method as a variable variable to set your value
$post->$method($value);
}
// persist the entity
$em->persist($post);
}
This way you can add more properties by just adding the new values to your array.

Related

How do you modify entity references on a form in a custom ajax action in Drupal 8?

I have added a custom button to a form:
$form['actions']['autotag_content'] = [
'#type' => 'button',
'#value' => 'Autotag Content',
'#ajax' => [
'callback' => ['\Drupal\taxonomy_migrate\taggerService', 'tagContent'],
'wrapper' => ['block-adminimal-theme-content'],
'progress' => [
'type' => 'throbber',
'message' => 'Tagging content',
],
],
];
Then in the callback I want to add or remove entities from an entity reference field on the form. This would then get sent back to the browser and rerendered. I don't want the changes to be save, I just want them populated in the form and then the user can accept the changes.
For the sake of this example, I have simplified this to just demonstrate the point. I would like to add two entity references to field_tax_subjects and have the frontend form rerender. Currently, the frontend form rerenders, but doesn't reflect the changes
public static function tagContent(array &$form, FormStateInterface &$form_state) {
$node = $form_state->getFormObject()->getEntity();
$node->field_tax_subjects[] = 12345;
$node->field_tax_subjects[] = 23456;
$form = \Drupal::service('entity.form_builder')->getForm($node);
$form_state->setRebuild();
return $form;
}
my answer is just for in case your ajax is working
because in your question you have'nt full code of form
also its not clear its node form or something else
any way
If your ajax is working you only have to correct how to set value for entity reference field and term reference filed
for entity reference and term reference
public static function tagContent(array &$form, FormStateInterface &$form_state) {
$node = $form_state->getFormObject()->getEntity();
// for entity refrence
$node->field_tax_subjects[]['target_id'] = 12345;
$node->field_tax_subjects[]['target_id'] = 23456;
// for term reference
//$node->field_tax_subjects[]['tid'] = 12345;
//$node->field_tax_subjects[]['tid'] = 23456;
$form = \Drupal::service('entity.form_builder')->getForm($node);
$form_state->setRebuild();
return $form;
}
HOPE THIS HELP YOU
THANKS

Sonata admin export fields with collection fields

I'm trying to make custom columns for export, but I can't access children. Is there any possibility to do that ?
My code at this moment looks like this:
public function getExportFields()
{
return [
'ID' => 'id',
'Transaction number' => 'transactionNumber',
'Loan account' => 'loan',
'Loan name' => 'loan.name',
'Amount' => 'amount',
//'Amount ($)' => '',
'Transaction type' => 'transactionCategory',
'Reference' => 'transactionAssociation.cashTransaction.transactionNumber',
'Date' => 'date'
];
}
I can't find out a solution. I was thinking to use PropertyAccess, but I don't know how to integrate it here.
I'm using Symfony 3.X with Sonata.
To get the collection records in export you cannot directly do this by specifying the property with association, A workaround for to achieve this you can define a new unmapped property in your entity with a getter function which will get all the collection details like in your main entity define new property as
protected $cashTransactionNumber;
public function getCashTransactionNumber()
{
$cashTransactionNumber = array();
$i = 1;
foreach ($this->getTransactionAssociation() as $key => $transactionAssociation) {
$cashTransactionNumber [] = $i .
') No.:' . $transactionAssociation->somemethod()->__toString()() .
/** Other properties */;
$i++;
}
return $this->cashTransactionNumber = join(' , ', $cashTransactionNumber );
}
then in your getExportFields() method call this property
public function getExportFields(){
return array(
'Reference'=>'cashTransactionNumber ',
....// Other properties
);
}
Reference: Exporting one to many relationship on sonata admin

Drupal fields: Passing a variable to view

I have a custom field plugin. It's widget looks somewhat like this:
function mymodule_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
...
$main_widget = $element + array(
'#test' => 'test',
'#type' => 'textarea',
'#attributes' => array('item_capacity' => 3),
'#theme'=>'mymodule_theme'
);
...
}
I need to get a value of another field, attached to current node, and pass it to this widget's theme file. Can i somehow get at least an id of a node that contains current field from hook_field_widget_form()?
You can use the module Devel to print the value of the $form array which will contain the form information you are looking for.
Example:
dpm($form);
You will be able to easily see the content of the form and access it with php in array form.

Getting random path hierarchy for CCK fields inside form array

I have created a custom entity and i'm using CCK fields. Each bundle has it's own fields. For example:
function MYMODULE_install() {
// Check if our field is not already created.
if (!field_info_field('field_myField')) {
$field = array(
'field_name' => 'date_field',
'type' => 'list_text',
);
field_create_field($field);
}
//Enable is executed only once.
function bundle_callback_enable() {
// Create the instance on the bundle.
$instance = array(
'field_name' => 'date_field',
'entity_type' => 'payment_method',
'label' => 'Expiration Date',
'bundle' => 'card',
'required' => TRUE,
'settings' => array();
field_create_instance($instance);
}
My bundles are created from individual modules, so in each install file i am creating the respective fields.
Yesterday i tried to add validation callback functions in those fields and i saw something weird inside form array. Fields with type="text" had the path:
$form[field_name]['und'][0][value] //<! expectable
but fields with type='list_text' had only the path:
$form[field_name]['und'] //<! unexpectable
I couldn't find any solution and i've solved it with this:
function &get_cck_path_value( $field_name, &$form_path) {
$field = null
if ( isset( $form_path[$field_name][LANGUAGE_NONE] ) ) {
$field = &$form_path[$field_name][LANGUAGE_NONE]
}elseif(isset($form_path[$field_name][LANGUAGE_NONE][0])) {
$field = &$form_path[$field_name][LANGUAGE_NONE][0]['value'];
}
return $field;
}
I don't like this approach. Is too hucky. Can you tell me if that is a cck feature or bug?
I can't understand when it decides where to put the values( All the process is fulfilled through the "field_attach_form( ... )" )?
Have you faced any problem like this?
Thanks in advance.
Thandem.
I believe that you are seeing the abbreviated form field in validation because the field had no value entered into it and no default value was defined for it. There is no value, so no array is present to store the value.

migrating url alias from drupal6 to drupal7 as a part of migration process

I have migrated nodes using migrate module v2. Currently i am running into a problem that the previous site used url aliases,which have not been migrated into drupal7 and will affect the site rank from SEO perspective.
Is there a way i can migrate the path aliases while running the migration classes itself?If not what would be the best way to do so?
You can migrate your legacy aliases directly into the Drupal 7 path field:
$this->addFieldMapping('path', 'my_legacy_alias_field');
Here is a very stripped down migration class that includes an easy method for bringing URLs along for the ride. Intended for use with the Migrate module.
class MyNodeMigration extends Migration {
public function __construct(array $arguments) {
$this->arguments = $arguments;
parent::__construct();
$source_fields = array('nid' => t('The node ID of the page'));
$query = Database::getConnection('default', 'legacy')
->select('node', 'n')
->fields('n');
$query->join('url_alias', 'a', "a.src = CONCAT('node/', n.nid)");
$query->addField('a', 'dst');
$this->source = new MigrateSourceSQL($query, $source_fields);
$this->destination = new MigrateDestinationNode('my_node_type');
$this->map = new MigrateSQLMap($this->machineName,
array('nid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'D6 Unique Node ID',
'alias' => 'n',
)),
MigrateDestinationNode::getKeySchema()
);
$this->addSimpleMappings(array('title', 'created', 'changed', 'status'));
$this->addUnmigratedDestinations(array('sticky', 'log', 'nid'));
$this->addFieldMapping('path', 'dst');
$this->addFieldMapping('is_new')->defaultValue(TRUE);
}
}
As I can see, the url_aliastable is globally the same, expect the name of fields whom changed from srcto sourceand dst to alias. So I guess you can easily copy the content from your Drupal 6 to your Drupal 7.
I never tried, but in theory it should work.
The best way (according to me) to have the same url aliases is :
1> install url_alias module.
2> configure the nodes with patterns similar to drupal6. Now, this step may trouble you, in case the new url-aliases have nids attached to them.(as in my case).
As a solution we can go ahead and create custom tokens using code where the source id can be fetched from the migrate map tables based on the new destination ids which are easily available.
Now, we can go ahead and bulk generate url-aliases.
An example for creating such custom token would be:
/**
* Implements hook_token_info().
*/
function custom_configuration_token_info() {
$type = array(
'node' => array (
'name' => t('Nodes'),
'description' => t('Tokens related to individual nodes.'),
'needs-data' => 'node',
),
'term' => array(
'name' => t('Taxonomy Terms'),
'description' => t('Tokens related to taxonomy terms.'),
'needs-data' => 'term',
)
);
// tokens for node legacy nid.
$tokens['node']['mapid'] = array(
'name' => t("mapid"),
'description' => t("The nid of the node prior to migration."),
);
$tokens['term']['mapid'] = array(
'name' => t('mapid'),
'description' => t('The tid of taxonomy terms prior to migration.'),
);
return array(
'types' => $type,
'tokens' => $tokens,
);
}
now,
function custom_configuration_tokens($type, $tokens, array $data = array(), array $options = array()) {
$url_options = array('absolute' => TRUE);
if (isset($options['language'])) {
$url_options['language'] = $options['language'];
$language_code = $options['language']->language;
}
else {
$language_code = NULL;
}
$sanitize = !empty($options['sanitize']);
$replacements = array();
if ($type == 'node' && !empty($data['node'])) {
$node = $data['node'];
foreach ($tokens as $name => $original) {
switch ($name) {
<write your custom code for the token conditioned by the name attribute in info function>
}
}
}
While writing your custom code, you mite also be needing the legacy table. Drupal 7 supports multiple databases, so just configure the legacy table credentials in settings.php file.
Use drupal_set_active while fetching data from the different tables.
Thanks.

Resources