Skip to content

[Form] DoctrineType, Add widget property to avoid retrieving the whole ChoiceList #3095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from

Conversation

RapotOR
Copy link
Contributor

@RapotOR RapotOR commented Jan 11, 2012

Todo :

  • add some tests
  • Replace queryBuilder by generic EntityLoader

The PR gives a different approach of the PR #1951. Please read the discussion.

The same approach is used for DateType (regarding the widget property).
The entity is retrieved from the the hidden (or another type) field contained in the entitype (which is form and not choice anymore in this case).

How it works?

  • If the widget is not choice, the ChoiceList is not loaded anymore; very useful for a huge table.
  • If the property is given, a second field is added
  • The ID field's type will be the widget value (maybe a retriction to hidden or text?) .

The idea is :

    $builder->add('city', 'entity', array(
        'class'             => 'Acme\DemoBundle\Entity\City',
        'property'          => 'name',
        'widget'            => 'text',
        'required'          => false
    ));

Bug fix: no
Feature addition: yes
Backwards compatibility break: no
Symfony2 tests pass: yes
Fixes the following tickets: #1951, #1946

use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\NoResultException;

class EntityToArrayTransformer implements DataTransformerInterface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is already an EntitiesToArrayTransformer. Do you really need another transformer here ? And if yes, try to change the name to have more differences in the name to avoid confusion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about EntityToIdentifierAndPropertyTransformer?

It is converting a Entity to an array of identifier and property.

@j
Copy link

j commented Jan 16, 2012

This is the exact way I've proposed somewhere. I'll reference the issue later if I haven't closed it already. It only makes sense to be here... Otherwise we should just scrap the whole idea and promote users of sf2 to make their own types for these use cases and use the current entity transformers which is easy to do (as fosuserbundle bundle does I believe). ORMs should be responsible to allow for this functionality. I think the whole new type is kind of pointless as proposed in #1951.

I'm on my iPad, but have a look at fosuserbundle and see how they use the existing entities transformer.

@j
Copy link

j commented Jan 16, 2012

+1 for this way.

@stof
Copy link
Member

stof commented Jan 16, 2012

@jstout24 we don't use the existing transformer. We provide a transformer using our UserManagerInterface and allowing to enter a username and getting a user. It is not a generic implementation at all, but one that work whatever backend you sue for the FOSUserBundle storage.

@j
Copy link

j commented Jan 16, 2012

@stof ah that's right. It's been a while since I looked. I saw someone use it before :p.. Maybe it was lichess or something else. :p

@stof
Copy link
Member

stof commented Jan 16, 2012

yeah, this data transformer has originally been added in FOSUserBundle to be used in lichess as ornicar implemented it there first and thought it may be useful to provide it in the bundle directly.

@j
Copy link

j commented Jan 16, 2012

A quick question.. would using "text" as a widget render a when it should be hidden? or would this end up rendering the hidden field and a text field for autocomplete functionality?

@RapotOR
Copy link
Contributor Author

RapotOR commented Jan 16, 2012

@jstout24
It would be:

  • using the widget to render the identifier field.
  • optionally, using the property option would add an additionnal field to show this property.

So, it would possible to have

  • an identifier text field alone
  • an identifier hidden field alone
  • an identifier hidden field + a property text field (the autocomplete case)

Some pending questions after Stof's remarks:

  • A easier name for EntityToArrayTransformer. I proposed EntityToIdentifierAndPropertyTransformer.
  • The query_builder has to be replaced by a generic loader. I proposed to add a generic find function for the EntityLoaderInterface because we should find the entity in the restricted query and not on the whole list (so not a find on EntityManager).

@Tobion
Copy link
Contributor

Tobion commented Jan 16, 2012

One more case that should be possible from my experience:

  • no or empty identifier hidden field + property text field (autocomplete case when javascript not available)

Then we need to specify a custom transformer for property text field -> entity (maybe using a closure).

Example: I've got a text field for a person which is filled with autocomplete in the format:
firstName lastName [ID]. This way the form could also work when javascript is disabled by letting the user name the person. The problem with transformers is that I can raise a validation error with TransformationFailedException but this is just a generic error. I would like to specify a real error message like "Your input is ambiguos" (when the user left out the ID and there are several people with the same name). This can only be achieved with a Listener. Like I did in https://github.com/Tobion/Tropaion/blob/master/src/Tobion/TropaionBundle/Form/EventListener/TransformAthletesListener.php

I would appreciate if such functionality would be possible with the Entity form type.

@RapotOR
Copy link
Contributor Author

RapotOR commented Jan 17, 2012

@Tobion Yes. Thanks for this comment.

As the transformer convert an entity to an array of identifier and property, I think I could add a case to retrieve an entity from the property if it's defined and if the identifier did not give a valid entity.

Something like:

  $entity = $this->em->find($this->class, $key);
  if ($this->property && !$entity) {
      $entity = $em->getRepository($class)->findOneBy(array($property => $value));
  }

Does it match your case?

Regards,

@Tobion
Copy link
Contributor

Tobion commented Jan 17, 2012

Well, not exactly. The property does not need to be a database column. So you can not simply search for it. I would rather suggest to allow a closure in this case. And we still need to find a way to add real errors.

@RapotOR
Copy link
Contributor Author

RapotOR commented Jan 17, 2012

@Tobion Ok I understand, it's a step further. In a first time, I would like to have at least the basic way. Maybe it could be the subject of an other PR in the future.

@j
Copy link

j commented Jan 17, 2012

@RapotOR killer!

/**
* Return an entity that is valid choice in the corresponding choice list.
*
* @return Object entity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be object

public function getEntity($field, $value)
{
$alias = $this->queryBuilder->getRootAlias();
$where = $this->queryBuilder->expr()->eq($alias.'.'.$field, $value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DQL injection is possible here. you should not pass the value (which is a user input) using string concatenation. You should use a query parameter here and set the value for the parameter

use Symfony\Component\Form\Util\PropertyPath;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\NoResultException;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused use statement

@stof
Copy link
Member

stof commented Jan 22, 2012

@bschussek can you give your mind on this PR ?

Also note that this PR will conflict with the refactoring done in #3156

@webmozart
Copy link
Contributor

I think that the idea behind this PR is good. This should be added as a generic option to ChoiceType though.

After the refactoring done in #3156 this should be quite easy to implement, without even the need of extra value transformers. The tricky question, as already discussed above, is how to exactly design the field options to be versatile yet understandable.

@fabpot
Copy link
Member

fabpot commented Feb 2, 2012

@bschussek: Can you confirm that this PR is better than the approach in #1951?

@webmozart
Copy link
Contributor

@fabpot: Not yet, both of them are on my todo list.

@stof
Copy link
Member

stof commented Apr 4, 2012

@bschussek ping

@RapotOR Please rebase your branch. It conflicts with master because of the move of the tests

@RapotOR
Copy link
Contributor Author

RapotOR commented Apr 23, 2012

@stof difficult for me at this moment.
if i am not wrong, it is not a basic rebase since the ChoiceType has been refactored in #3156.

Btw, there are different concurrent ideas, it could be great to have an official guideline for that.
Concurrent ideas are:

@stof
Copy link
Member

stof commented Apr 23, 2012

@bschussek @fabpot please give your mind about the preferred way

@Narretz
Copy link

Narretz commented Jan 24, 2013

New discussion on this in #6602. Can this be closed?

@webmozart
Copy link
Contributor

Closed in favor of #6602.

@webmozart webmozart closed this Apr 18, 2013
@dbrumann
Copy link
Contributor

I don't mean to be rude, but the last comment is from April 2013 and Symfony 2.5 has not been supported for ages. You should seriously consider upgrading your project to a supported version.

@dbrumann
Copy link
Contributor

You can use a custom query to fetch the entities, see EntityType Field in the docs

@derrabus
Copy link
Member

Please consider using our support channels for this! Thank you!

https://symfony.com/support

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants