Symfony Sonata Admin: how get choices array from DB - symfony

How get all values parent_id from DB?
$category = $this->getSubject();
protected function configureFormFields(FormMapper $formMapper)
{
$fieldOptions = array(); //how get all value `parent_id` from DB
$formMapper->add('parent_id', ChoiceType::class, array(
'expanded' => true,
'multiple' => false,
'choices' => $fieldOptions,
'data' => $category->parent_id
));
}

If "parent" is an entity (Category, perhaps), you might want to look at EntityType. Otherwise, your code needs a lot more context. In what class or file is that snippet located?

Answer:
class CategoryAdmin extends AbstractAdmin
{
$category = $this->getSubject();
protected function configureFormFields(FormMapper $formMapper)
{
$em = $this->modelManager->getEntityManager(Category::class);
$fieldOptions = $em->getRepository(Category::class)->getChoiceParentId();
$formMapper->add('parent_id', ChoiceType::class, array(
'multiple' => false,
'choices' => array_flip($fieldOptions),
'data' => $category->parent_id
));
}
}
class CategoryRepository extends ServiceEntityRepository
{
public function getChoiceParentId()
{
$categories = $this->createQueryBuilder('c')
->select('c.id, c.name')
->getQuery()
->getResult();
$choice_parent_id = [0 => 'Empty'];
foreach ($categories as $category) {
$choice_parent_id[$category['id']] = $category['name'];
}
return $choice_parent_id;
}
}

Related

Symfony dependent dropdown with 3 entities

So I'm about to create a form with three dropdowns which are interdependent.
When one or several channel1s are selected, the choices for channel 3 should change, according to what is selected for channel1. And dependent on that, the last dropdown "agencies" should change its choices.
I've already tried different solutions but none of them has worked so far. Right now I'm stuck on the solution provided by Symfony's documentation, which provides code for two entities but even with that one, my second dropdown doesn't have any values, so it's not working.
Here is my Form Type:
class SelectionType extends AbstractType {
protected $tokenStorage;
// private $manager;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
//solution Symfony Documentation
$channel1s = new Channel1();
$currentuser = $this->tokenStorage->getToken()->getUser();
$builder
->add('channel1s', EntityType::class, array(
'class' => 'AppBundle:Channel1',
'property' => 'name',
'label' => 'label.channel1s',
'empty_value' => 'label.select_channel1s',
'mapped' => false,
'expanded' => false,
'translation_domain' => 'UploadProfile',
'multiple' => true,
'required' => false,
));
$formModifier = function (FormInterface $form, Channel1 $channel1s = null) {
$channel3s = null === $channel1s ? array() : $channel1s->getChannel3();
$form->add('channel3s', EntityType::class, array(
'class' => 'AppBundle:Channel3',
'property' => 'name',
'label' => 'label.channel3s',
'empty_value' => 'label.select_channel3s',
'mapped' => false,
'expanded' => false,
'translation_domain' => 'UploadProfile',
'choices' => $channel3s,
'multiple' => true,
'choices_as_values' => true,
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$data = $event->getData();
$formModifier($event->getForm(), $data->getChannel1s());
}
);
$builder->get('channel1s')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$channel1s = $event->getForm()->getData();
$formModifier($event->getForm()->getparent(), $channel1s);
}
);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'DocumentBundle\Entity\UploadProfile'
));
}
public function getName()
{
return 'uploadprofile';
}
}
I've also tried a solution with Subscribers from that page: http://showmethecode.es/php/symfony/symfony2-4-dependent-forms/ but it didn't work out either..
I think my problem is somewhere around that line:
$channel3s = null === $channel1s ? array() : $channel1s->getChannel3();
but that's just a guess..
I also added that ajax function:
var $channel1s = $('#uploadprofile_channel1s');
$channel1s.change(function() {
var $form = $(this).closest('form');
var data = {};
data[$channel1s.attr('name')] = $channel1s.val();
// data[channel3s.attr('name')] = channel3s.val();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
$('#uploadprofile_channel3s').replaceWith(
$(html).find('#uploadprofile_channel3s')
);
}
});
});
My 3 entities have ManytoMany or OneToMany relationships and I should have all the right getters and setters, but if anyone needs them to varify, let me know and I will upload them!
I've been stuck on this for quite a while now, so I would be happy about any kind of help or advise!
NOTE: there's still a third entity (agency) to be added but since not even the first one's are working, I decided to upload only the first two..
ADDED:
or maybe somebody can explain to my that line:
$channel3s = null === $channel1s ? array() : $channel1s->getChannel3s();
might be, that this is my problem?

configureRoutes() in admin class is not compatible with Sonata\AdminBundle\Admin\Admin::configureRoutes()

Hi I'm trying to 'Create a Custom Admin Action' for sonata admin bundle. But I'm facing this issue,
Runtime Notice: Declaration of
AdminBundle\Admin\VideoAdmin::configureRoutes() should be compatible
with
Sonata\AdminBundle\Admin\Admin::configureRoutes(Sonata\AdminBundle\Route\RouteCollection
$collection) in C:\wamp\www\videocenter\app/config. (which is being
imported from "C:\wamp\www\videocenter\app/config\routing.yml").
This is my configureRoutes() function,
protected function configureRoutes(RouteCollection $collection) {
$collection->add('clone', $this->getRouterIdParameter() . '/clone');
}
This is my complete admin class,
namespace AdminBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use AdminBundle\Entity\Video;
use Doctrine\ORM\Query\ResultSetMapping;
class VideoAdmin extends Admin {
protected function configureFormFields(FormMapper $formMapper) {
$formMapper->add('name', 'text');
$formMapper->add('category', 'sonata_type_model', array(
'class' => 'AdminBundle\Entity\VideoCategory',
'property' => 'name',
));
$formMapper->add('thumbUrl', 'text');
$formMapper->add('url', 'text');
// $formMapper->add('videoKey', 'text');
$formMapper->add('isPublic', 'checkbox', array(
'label' => 'Show public',
'required' => false,
));
$formMapper->add('isEnabled', 'checkbox', array(
'label' => 'Enable',
'required' => false,
));
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper) {
$datagridMapper
->add('name')
->add('category', null, array(), 'entity', array(
'class' => 'AdminBundle\Entity\VideoCategory',
'property' => 'name'))
->add('videoKey');
}
protected function configureListFields(ListMapper $listMapper) {
$listMapper
->addIdentifier('name')
->add('category.name')
->add('url')
->add('videoKey')
->add('isPublic')
->add('isEnabled')
->add('_action', 'actions', array(
'actions' => array(
'show' => array(),
'edit' => array(),
'delete' => array(),
'clone' => array(
'template' => 'AdminBundle:CRUD:list__action_clone.html.twig'
),
)
))
;
}
public function postPersist($object) {
global $kernel;
if ('AppCache' == get_class($kernel)) {
$kernel = $kernel->getKernel();
}
$em = $kernel->getContainer()->get('doctrine.orm.entity_manager');
$query = "select a.random_num from (SELECT FLOOR(RAND() * 99999) AS random_num) a WHERE A.RANDOM_NUM NOT IN (SELECT COALESCE(B.VIDEO_KEY,0) FROM VIDEO B)";
$stmt = $em->getConnection()->prepare($query);
$stmt->execute();
$randum = $stmt->fetchAll();
$video = $em->getRepository('AdminBundle:Video')->find($object->getId());
if ($video) {
$video->setVideoKey($randum[0]['random_num']);
$em->flush();
}
}
public function toString($object) {
return $object instanceof Video ? $object->getName() : 'Video'; // shown in the breadcrumb on the create view
}
public function getBatchActions() {
// retrieve the default batch actions (currently only delete)
$actions = parent::getBatchActions();
if (
$this->hasRoute('edit') && $this->isGranted('EDIT') &&
$this->hasRoute('delete') && $this->isGranted('DELETE')
) {
$actions['merge'] = array(
'label' => 'action_merge',
'translation_domain' => 'SonataAdminBundle',
'ask_confirmation' => true
);
}
return $actions;
}
protected function configureRoutes(RouteCollection $collection) {
$collection->add('clone', $this->getRouterIdParameter() . '/clone');
}
}
Did you import?
use Sonata\AdminBundle\Route\RouteCollection;
I doesn't see that in yours VideoAdmin class

multiple choice dropdown with option groups using symfony “entity”?

I have the entity Property with manyToMany to Feature that is oneToMany of FeatureType. The multi-choice drop-down is being implemented in the Property create form.
PropertyRoomAdmin.php
protected function configureFormFields(FormMapper $formMapper)
{
$property = $this->getProperty();
$featuresChoices = $this->getRepository('TestBundle:Feature')->getChoicesWithCategoryGroup();
$formMapper
->add('features', 'entity', array(
'label' => '設備(こだわり条件?)',
'class' => 'TestBundle:Feature',
'choices' => $featuresChoices,
'property' => 'name'
))
;
}
FeatureRepository.php
public function getChoicesWithCategoryGroup()
{
$choices = array();
$qb = $this->createQueryBuilder('p');
$qb->select('p, c');
$qb->LeftJoin('p.featureCategory', 'c');
$qb->orderBy('c.name', 'DESC')->addOrderBy('p.name', 'DESC');
$products = $qb->getQuery()->execute();
$choices = [];
foreach ($products as $product) {
$choices[$product->getFeatureCategory()->getName()][] = $product;
}
return $choices;
}
Neither the property "features" nor one of the methods "addFeatur()"/"removeFeatur()", "addFeature()"/"removeFeature()",
"setFeatures()", "features()", "__set()" or "__call()" exist and have
public access in class "TestBundle\Entity\PropertyRoom".
I tried 'multiple' => true code got error
->add('features', 'entity', array(
'label' => '設備(こだわり条件?)',
'class' => 'EstateBundle:Feature',
'choices' => $featuresChoices,
'property' => 'name',
'multiple'=> true,
'required' => false
))
ERROR - Failed to create object: EstateBundle\Entity\PropertyRoom
Context: {"exception":"Object(Sonata\AdminBundle\Exception\ModelManagerException)","previous_exception_message":"An exception occurred while executing 'INSERT INTO property_room_features (property_room_id, feature_id) VALUES (?, ?)' with params [168, 50]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '168-50' for key 'PRIMARY'"}
Where you setup your options array:
foreach ($products as $product) {
$choices[$product->getFeatureCategory()->getName()][] = $product;
}
Change it to something like this:
foreach ($products as $product) {
$choices[$product->getFeatureCategory()->getName()][$product->getName()] = $product->getId();
}

Pass/bind data objects to inner/embedded Symfony2 forms

i have the following form where i would like to pass some objects to the inner forms in order to populate them with data when being edited:
public function __construct( $em, $id )
{
$this->_em = $em;
}
public function buildForm( \Symfony\Component\Form\FormBuilderInterface $builder, array $options )
{
$builder->add( 'accessInfo', new AccessInfoType( $this->_em, $options[ 'entities' ][ 'user' ] ) , array(
'attr' => array( 'class' => 'input-medium' ),
'required' => false,
'label' => false
)
);
$builder->add( 'profileInfo', new ProfileInfoType( $this->_em, $options[ 'entities' ][ 'profile' ] ) , array(
'required' => false,
'label' => false
)
);
}
public function setDefaultOptions( \Symfony\Component\OptionsResolver\OptionsResolverInterface $resolver )
{
$resolver->setDefaults( $this->getDefaultOptions( array() ) );
return $resolver->setDefaults( array( ) );
}
/**
* {#inheritDoc}
*/
public function getDefaultOptions( array $options )
{
$options = parent::getDefaultOptions( $options );
$options[ 'entities' ] = array();
return $options;
}
public function getName()
{
return 'UserType';
}
which i instantiate with the following code:
$form = $this->createForm( new UserType( $em ), null, array( 'entities' => array( 'user' => $userObj, 'profile' => $profileObj ) ) );
Once i get, via the constructor, the object containing the needed data does anyone know how could i bind that object to the form?
class ProfileInfoType extends AbstractType
{
private $_em;
public function __construct( $em, $dataObj )
{
$this->_em = $em;
$this->_dataObj = $dataObj;
}
Thanks in advanced!
I was having the same issue and fixed this with inherit_data
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'inherit_data' => true,
));
}
See also http://symfony.com/doc/current/cookbook/form/inherit_data_option.html
Inside your controller yo should get the request data
$request = $this->getRequest();
or request it through the method parameters
public function newAction(Request $request)
and then bind it to the form
$form->bind($request);
For further details have a look at http://symfony.com/doc/2.1/book/forms.html#handling-form-submissions
this works well add an attr for use the html attribute 'value' depends of the form type, maybe this can help you.
Twig
{{ form_label(blogpostform.title) }}
{{ form_widget(blogpostform.title, {'attr': {'value': titleView }}) }}
{{ form_errors(blogpostform.title) }}

Build a form having a checkbox for each entity in a doctrine collection

I'm displaying an html table for a filtered collection of entities and I want to display a checkbox in each row as part of a form which will add the selected entities to a session var.
I'm thinking that each checkbox should have the entity id as its value and I'll get an array of ids from the form field data (ok, so the value ought to be an indirect ref to the entity, but for the sake of simplicity).
I've tried creating a form Type with a single entity type field, mapped to the id property of the entity and embedded into another form Type which has a collection type field.
class FooEntitySelectByIdentityType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('foo_id', 'entity', array(
'required' => false,
'class' => 'MeMyBundle:FooEntity',
'property' => 'id',
'multiple' => true,
'expanded' => true
));
}
# ...
and
class FooEntitySelectionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('identity', 'collection', array(
'type' => new FooEntitySelectByIdentityType,
'options' => array(
'required' => false,
'multiple' => true,
'expanded' => true,
'attr' => array('class' => 'foo')
),
));
}
# ...
and in a controller the form is created with a collection of entities as the initial data
$form = $this
->createForm(
new \Me\MyBundle\Form\Type\FooEntitySelectionType,
$collection_of_foo
)
->createView()
;
When the form is rendered there is a single label for the identity field, but no widgets.
Is it even possible to use entity and collection type fields in this particular way?
If so, what might I be doing wrong?
I think this will answer your question.
Forget the FooEntitySelectionType. Add a property_path field option to FooEntitySelectByIdentityType and set the data_class option to null:
class FooEntitySelectByIdentityType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('foo_id', 'entity', array(
'required' => false,
'class' => 'MeMyBundle:FooEntity',
'property' => 'id',
'property_path' => '[id]', # in square brackets!
'multiple' => true,
'expanded' => true
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => null,
'csrf_protection' => false
));
}
# ...
and in your controller, build the FooEntitySelectByIdentityType:
$form = $this
->createForm(
new \Me\MyBundle\Form\Type\FooEntitySelectByIdentityType,
$collection_of_foo
)
->createView()
;
and then in the controller action which receives the POSTed data:
$form = $this
->createForm(new \Me\MyBundle\Form\Type\FooEntitySelectByIdentityType)
;
$form->bind($request);
if ($form->isValid()) {
$data = $form->getData();
$ids = array();
foreach ($data['foo_id'] as $entity) {
$ids[] = $entity->getId();
}
$request->getSession()->set('admin/foo_list/batch', $ids);
}
and finally, in your twig template:
{# ... #}
{% for entity in foo_entity_collection %}
{# ... #}
{{ form_widget(form.foo_id[entity.id]) }}
{# ... #}
If someone is looking for solution for Symfony >=2.3
You have to change this:
$data = $form->getData();
$ids = array();
foreach ($data['foo_id'] as $entity) {
$ids[] = $entity->getId();
}
to this:
$data = $form['foo_id']->getData();
$ids = array();
foreach ($data as $entity) {
$ids[] = $entity->getId();
}
I create a symfony bundle for render a collection of entities as a checkbox table in a configurable way. Although it has been a while since this question was asked, I hope this can help others with this same kind of problem.

Resources