Send choice Value instead choice key from Symfony form - symfony

I need to send from Symfony form ChoiceType::class
But I don't need choices keys, I need to send choices values.
Is that is possible?
$form->add('section', ChoiceType::class, array(
'mapped' => false,
'choices' => array(
1 => 'value1',
2 => 'value2'
),
));
I just want to send value1 if I chose value1,
not key 1 as default.

You can use
array_flip ($array)
refer to php docs

[Since Symfony 2.7] In any case you can play with choice value through choice_value option and a Closure function (Reference):
$form->add('section', ChoiceType::class, array(
'choice_value' => function ($value, $key, $index) {
return $value;
}
));
Useful for dynamic choices.

You just need to reverse it. Also, I don't think you need 'mapped'.
Try this:
$form->add(
'section',
ChoiceType::class,
[
'choices' => [
'value1' => 1,
'value2' => 2,
],
]
);
It should work.

Mayby a bit late but i've made this and it works perfect. Without array_flip. Mayby for someone it 'll be usefull.
$dataUsers = [];
$users = [
['id' => 1, 'firstname' => 'joe', 'lastname' => 'doe'],
['id' => 2, 'firstname' => 'will', 'lastname' => 'fog'],
];
foreach ($users as $u) {
$dataUsers[] = (object)['id' => $u['id'], 'label' => $u['firstname']];
}
$builder
->add('users', ChoiceType::class, [
'choices' => $dataUsers,
'choice_label' => function ($value) {
if (is_object($value)) {
return $value->label;
} else {
return 0;
}
},
'choice_value' => function ($value) {
if (is_object($value)) {
return $value->id;
} else {
return 0;
}
},
'data' => (object)[ 'id' => 2]
]);

Related

How to add text that there are no search results for such entered word to a custom block?

I have a view that searches for indexed entity fields using context filters. I added a custom block to the view like this:
{{ drupal_block('result_entity_product_categories', {arguments}) }}
This block displays categories that match the entered word in the search. If you enter something for which there are no search results, for example, bbbbb, I need to display something like this:
Sorry
No results for: "bbbbb"
But here are some of our most popular products
P.S. The option to add text to the No Results Behavior view setting is not suitable. It is necessary to add text in the custom block.
The build() method code of my custom block:
public function build() {
$configuration = $this->getConfiguration();
$term = $configuration['arguments']['0'] ?: '';
if (empty($term)) {
return '';
}
$index = $this->entityTypeManager->getStorage('search_api_index')->load('entity_product_index');
$parse_mode = $this->parseModeManager->createInstance('terms');
$parse_mode->setConjunction('AND');
$search_query = $index->query();
$search_query->setParseMode($parse_mode)
->keys($term);
$search_result = $search_query->execute();
$rows = [];
foreach ($search_result->getResultItems() as $item) {
if (($node = $item->getOriginalObject()->getEntity()) && ($node instanceof NodeInterface)) {
$categoryKey = $node->get('field_entity_product_category')->getString();
if ($categoryKey) {
++$rows[$categoryKey];
}
}
}
$build['container'] = [
'#type' => 'container',
'#attributes' => [
'class' => ['category-counter-wrapper'],
],
];
foreach ($rows as $key => $count) {
if ($node = $this->entityTypeManager->getStorage('node')->load($key)) {
$build['container'][$key] = [
'#type' => 'container',
'#attributes' => [
'class' => ['item'],
],
'label' => [
'#type' => 'container',
'#markup' => $node->getTitle(),
'#attributes' => [
'class' => ['label'],
],
],
'count' => [
'#type' => 'container',
'#markup' => $count,
'#attributes' => [
'class' => ['count'],
],
],
'link' => [
'#type' => 'link',
'#url' => Url::fromUserInput($node->get('field_custom_url')->getString(), ['query' => ['text' => $term]]),
'#attributes' => [
'class' => ['link'],
],
],
];
}
}
return $build;
}

how to map violation to Symfony form manually?

OrderType
$builder
->add('items', FormTypes\CollectionType::class, [
'entry_type' => OrderItemType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => 'acme.form.order.items',
])
->add('channel', ChannelSelectType::class, [
'required' => true,
'label' => 'acme.form.order.channel',
])
OrderItemType
$builder
->add('service', ServiceSelectType::class, [
'label' => 'acme.form.order_item.service',
])
->add('product', ProductSelectType::class, [
'label' => 'acme.form.order_item.product',
])
->add('quantity', FormTypes\IntegerType::class, [
'label' => 'acme.form.order_item.quantity',
]);
How to map the error to OrderItemType product field?
the order item is valid when a product is applied to a specific channel. however we have no way to get the submited channel in OrderItemType,
because child form type is submmited before its parent. so $event->getForm()->getParent()->getData()->getChannel() is empty. the only way I have
is to validate order item in OrderType, or create a validator which is added to Order class. the problem is how can I map the error to OrderItemType product field.
$orderItems = $order->getItems();
$channel = $order->getChannel();
foreach($orderItems as $index => $orderItem) {
$product = $orderItem->getProduct();
if (!$this->isProductAvailableForChannel($channel, $product)) {
$message = sprintf('product %ss is not available for channel "%s"', $product->getName(), $channel->getName());
}
if (null !== $message) {
$this->context
->buildViolation($this->constraint->message)
->setParameter($message)
->atPath("items.children[$index].product") // this doesn't work, the error will be added to root form.
->addViolation()
;
}
}
You are able to get the channel on the pre submit event (Symfony\Component\Form\FormEvents::PRE_SUBMIT)
And there you can add your channel based validation for the order item
$addItems = function (FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
$options = [];
if (is_array($data) && array_key_exists('channel', $data)) {
$options['constraints'] = [
new OrderItemConstraint(['channel' => $data['channel']])
];
}
$form->add('items', FormTypes\CollectionType::class, [
'entry_type' => OrderItemType::class,
'entry_options' => $options,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => 'acme.form.order.items',
]);
};
$builder->addEventListener(FormEvents::PRE_SET_DATA, $addItems);
$builder->addEventListener(FormEvents::PRE_SUBMIT, $addItems);

Sonata Admin - DISTINCT in datagrid filter

I would like to have optional filter where user can select distinct values (emails). Is there a possibility to create custom query builder?
$datagridMapper->add(
'distinctRecords',
'doctrine_orm_callback',
[
'callback' => function ($queryBuilder, $alias, $field, $value) {
if (!$value['value']) {
return;
} else {
// WHAT TO ADD HERE ???
}
}
],
'choice',
[
'choices' => [
'Yes' => true,
'No' => false
],
'expanded' => false,
'multiple' => false
]
);

Generate data attribute to each checkbox in Symfony type

->add('research_subject', EntityType::class, array(
'mapped' => false,
'class' => Subject::class,
'label' => 'Research Subject',
'expanded' => true,
'multiple' => true,
'query_builder' => function (EntityRepository $er) {
$db = $er->createQueryBuilder('w');
$db ->where($db->expr()->andX(
$db->expr()->isNotNull('w.pid')
));
$db->orderBy('w.pid', 'ASC');
return $db;
},
'choice_label' => 'name_system',
))
I need to add to each check box data attribute. Is that is possible?
I need that for extra sort of checkboxes in twig latter. I need to group checkboxes by pid value in separate div section.
'choice_attr' => function($val, $key, $index) {
return ['data-pid' => $val->getPid()];
},
I had use this as solution, like https://stackoverflow.com/users/4224384/yceruto
Suggest.
You would use the "choice_attr" option for this:
[...]
'expanded' => true,
'multiple' => true,
'choice_attr' => function($val, $key, $index) {
return ['data' => $key];
},
[...]

How to get the value of one of the attributes used by Backpack?

For example, I need to take the "id" value and use it to do a search for my model Article, but this value (id) which also appears in the URL: "/article/4/edit" and in the "setColumns" parameters, I don't have any idea how to get it.
I need your help.
This is my sample code:
ArticleCrudController.php
public function __construct()
{
parent::__construct();
$this->crud->setModel('App\Models\Article');
$this->crud->setRoute("admin/article");
$this->crud->setEntityNameStrings('article', 'articles');
$this->crud->setColumns(['id', 'title', 'text']);
// WHERE ARE YOU ID?!?!!!
$article = Article::findOrFail($id);
$pictures = $article->picture()->first()->name;
$this->crud->addFields([
[
'name' => 'title',
'label' => 'Title',
'type' => 'Text'
],
[
'name' => 'text',
'label' => 'Text',
'type' => 'ckeditor'
],
[ // Browse
'name' => 'image',
'label' => 'Article immage',
'type' => 'browse',
'value' => $pictures //Obviously without id don't work :'(
]
]);
}
You could try to override the CrudController::edit method to which is passed the id as first parameter.
public function edit($id)
{
$articlePicture = Article::findOrFail($id)->picture()->first()->name;
$this->crud->addField([
'name' => 'image',
'value' => $articlePicture
]);
return parent::edit($id);
}
This could be a solution but I'm not sure it's the right way to do what you want.
Use getCurrentEntry to get the current model object in crud
$article_id = $this->crud->getCurrentEntry()->id;

Resources