Skip to content

Commit

Permalink
minor #1093 Tweaked the new autocomplete form field (javiereguiluz)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the master branch (closes #1093).

Discussion
----------

Tweaked the new autocomplete form field

Following the #1071 merge, this introduces some minor tweaks.

Commits
-------

f2c7d14 Tweaked the new autocomplete form field
  • Loading branch information
javiereguiluz committed Apr 20, 2016
2 parents 595b933 + f2c7d14 commit 4bace89
Show file tree
Hide file tree
Showing 16 changed files with 294 additions and 53 deletions.
11 changes: 10 additions & 1 deletion Controller/AdminController.php
Expand Up @@ -28,6 +28,7 @@
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;

/**
* The controller used to render all the default EasyAdmin actions.
Expand Down Expand Up @@ -129,14 +130,22 @@ protected function dispatch($eventName, array $arguments = array())
$this->get('event_dispatcher')->dispatch($eventName, $event);
}

/**
* The method that returns the values displayed by an autocomplete field
* based on the user's input.
*
* @return JsonResponse
*/
protected function autocompleteAction()
{
return $this->get('easyadmin.autocomplete')->find(
$results = $this->get('easyadmin.autocomplete')->find(
$this->request->query->get('entity'),
$this->request->query->get('property'),
$this->request->query->get('view'),
$this->request->query->get('query')
);

return new JsonResponse($results);
}

/**
Expand Down
5 changes: 2 additions & 3 deletions Form/Type/Configurator/AutocompleteTypeConfigurator.php
Expand Up @@ -28,13 +28,12 @@ class AutocompleteTypeConfigurator implements TypeConfiguratorInterface
*/
public function configure($name, array $options, array $metadata, FormConfigInterface $parentConfig)
{
// if the autocomplete field doesn't define the mandatory 'class' option,
// guess it from the metadata provided by Doctrine
// by default, guess the mandatory 'class' option from the Doctrine metadata
if (!isset($options['class']) && isset($metadata['targetEntity'])) {
$options['class'] = $metadata['targetEntity'];
}

// settings multiple autocomplete choices by default for OneToMany and ManyToMany association types
// by default, allow to autocomplete multiple values for OneToMany and ManyToMany associations
if (!isset($options['multiple']) && $metadata['associationType'] & ClassMetadata::TO_MANY) {
$options['multiple'] = true;
}
Expand Down
20 changes: 10 additions & 10 deletions Form/Type/EasyAdminAutocompleteType.php
Expand Up @@ -2,7 +2,7 @@

namespace JavierEguiluz\Bundle\EasyAdminBundle\Form\Type;

use JavierEguiluz\Bundle\EasyAdminBundle\Util\LegacyFormHelper;
use JavierEguiluz\Bundle\EasyAdminBundle\Form\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\FormBuilderInterface;
Expand All @@ -14,7 +14,6 @@
/**
* Autocomplete form type.
*
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class EasyAdminAutocompleteType extends AbstractType
Expand All @@ -23,31 +22,31 @@ public function buildForm(FormBuilderInterface $builder, array $options)
{
$preSetDataListener = function (FormEvent $event) use ($options) {
$form = $event->getForm();
// normalize null data
if (null === $data = $event->getData()) {
$data = array();
}
// settings inherited options
$data = $event->getData() ?: array();

// modify some of the settings inherited from the parent form type
$options['compound'] = false;
// normalize choices list
$options['choices'] = is_array($data) || $data instanceof \Traversable ? $data : array($data);

// create autocomplete form field
$form->add('autocomplete', LegacyFormHelper::getType('entity'), $options);
};

$preSubmitListener = function (FormEvent $event) {
$form = $event->getForm();
// normalize null data

if (null === $data = $event->getData()) {
$data = array('autocomplete' => array());
$event->setData($data);
}
// reuse autocomplete options

// reuse autocomplete options, but replace initial choices with submitted data
$options = $form->get('autocomplete')->getConfig()->getOptions();
// replace initial choices with submitted data
$options['choices'] = $options['em']->getRepository($options['class'])->findBy(array(
$options['id_reader']->getIdField() => $data['autocomplete'],
));

// reset autocomplete form field with new choices list
$form->add('autocomplete', LegacyFormHelper::getType('entity'), $options);
};
Expand Down Expand Up @@ -77,6 +76,7 @@ public function configureOptions(OptionsResolver $resolver)
// force display errors on this form field
'error_bubbling' => false,
));

$resolver->setRequired(array('class'));
}

Expand Down
2 changes: 1 addition & 1 deletion Form/Type/EasyAdminFormType.php
Expand Up @@ -13,7 +13,7 @@

use JavierEguiluz\Bundle\EasyAdminBundle\Form\Type\Configurator\TypeConfiguratorInterface;
use JavierEguiluz\Bundle\EasyAdminBundle\Configuration\Configurator;
use JavierEguiluz\Bundle\EasyAdminBundle\Util\LegacyFormHelper;
use JavierEguiluz\Bundle\EasyAdminBundle\Form\Util\LegacyFormHelper;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\Options;
Expand Down
14 changes: 4 additions & 10 deletions Util/LegacyFormHelper.php → Form/Util/LegacyFormHelper.php
Expand Up @@ -9,12 +9,14 @@
* file that was distributed with this source code.
*/

namespace JavierEguiluz\Bundle\EasyAdminBundle\Util;
namespace JavierEguiluz\Bundle\EasyAdminBundle\Form\Util;

/**
* @internal
* Utility class to map Symfony 2.x short form types to Symfony 3.x FQCN form types.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*
* @internal
*/
final class LegacyFormHelper
{
Expand Down Expand Up @@ -86,12 +88,4 @@ public static function useLegacyFormComponent()
{
return false === class_exists('Symfony\\Component\\Form\\Util\\StringUtil');
}

private function __construct()
{
}

private function __clone()
{
}
}
12 changes: 6 additions & 6 deletions Resources/config/form.xml
Expand Up @@ -27,34 +27,34 @@

<service id="easyadmin.form.type.configurator.autocomplete" public="false"
class="JavierEguiluz\Bundle\EasyAdminBundle\Form\Type\Configurator\AutocompleteTypeConfigurator">
<tag name="easyadmin.form.type.configurator" priority="30"/>
<tag name="easyadmin.form.type.configurator" priority="30" />
</service>

<service id="easyadmin.form.type.configurator.collection" public="false"
class="JavierEguiluz\Bundle\EasyAdminBundle\Form\Type\Configurator\CollectionTypeConfigurator">
<tag name="easyadmin.form.type.configurator" priority="20"/>
<tag name="easyadmin.form.type.configurator" priority="20" />
</service>

<service id="easyadmin.form.type.configurator.checkbox" public="false"
class="JavierEguiluz\Bundle\EasyAdminBundle\Form\Type\Configurator\CheckboxTypeConfigurator">
<tag name="easyadmin.form.type.configurator" priority="10"/>
<tag name="easyadmin.form.type.configurator" priority="10" />
</service>

<service id="easyadmin.form.type.configurator.required_option" public="false"
class="JavierEguiluz\Bundle\EasyAdminBundle\Form\Type\Configurator\RequiredOptionConfigurator">
<argument type="service" id="easyadmin.form.type_guesser_chain" />
<tag name="easyadmin.form.type.configurator" priority="-10"/>
<tag name="easyadmin.form.type.configurator" priority="-10" />
</service>

<service id="easyadmin.form.type.configurator.entity" public="false"
class="JavierEguiluz\Bundle\EasyAdminBundle\Form\Type\Configurator\EntityTypeConfigurator">
<argument type="service" id="easyadmin.form.type_guesser_chain" />
<tag name="easyadmin.form.type.configurator" priority="-20"/>
<tag name="easyadmin.form.type.configurator" priority="-20" />
</service>

<service id="easyadmin.form.type.configurator.ivory_ckeditor" public="false"
class="JavierEguiluz\Bundle\EasyAdminBundle\Form\Type\Configurator\IvoryCKEditorTypeConfigurator">
<tag name="easyadmin.form.type.configurator" priority="-130"/>
<tag name="easyadmin.form.type.configurator" priority="-130" />
</service>
</services>
</container>
2 changes: 1 addition & 1 deletion Resources/config/services.xml
Expand Up @@ -40,7 +40,7 @@
<argument type="service" id="doctrine" />
</service>

<service id="easyadmin.finder" class="JavierEguiluz\Bundle\EasyAdminBundle\Search\Finder">
<service id="easyadmin.finder" class="JavierEguiluz\Bundle\EasyAdminBundle\Search\Finder" public="false">
<argument type="service" id="easyadmin.query_builder" />
</service>

Expand Down
17 changes: 8 additions & 9 deletions Resources/doc/book/4-edit-new-configuration.md
Expand Up @@ -356,9 +356,8 @@ defined by EasyAdmin.
### Autocomplete

It's similar to Symfony's `Entity` type, but the values are loaded on demand via
Ajax based on your input. This type is useful when a field is related to an
entity with lots of database records. Autocompleting those fields improve
backend performance and user experience:
Ajax requests based on your input. This type is useful to improve the backend
performance when a field is related to an entity with lots of database records:

```yaml
easy_admin:
Expand All @@ -384,16 +383,16 @@ When the user types in an autocomplete field, EasyAdmin performs a fuzzy search
on all the properties of the related entity. This is the same behavior applied
when using the backend search form.

The autocomplete action sends to the browser a JSON array of `{ id: '...', text: '...' }`
tuples. The `id` is stored as the form field value and `text` is the value
displayed to the user.
The autocomplete action returns to the browser a JSON array of
`{ id: '...', text: '...' }` tuples. The `id` is used as the form field value
and the `text` is the value displayed to the user.

By default, the entity's primary key is used for the `id` property and the
`(string) %entity` conversion is used for the `text` property. Therefore, you
`(string) $entity` conversion is used for the `text` property. Therefore, you
must define the `__toString()` method in any autocomplete entity.

If you need to customize this behavior, override the `autocompleteAction()` in
the `AdminController` as explained later in this chapter.
If you need to customize this behavior, override the `autocompleteAction()`
method in your own `AdminController` as explained later in this chapter.

Advanced Design Configuration
-----------------------------
Expand Down
4 changes: 2 additions & 2 deletions Resources/public/javascript/easyadmin.js
Expand Up @@ -63,11 +63,11 @@ function easyAdminAutoComplete() {
dataType: 'json',
delay: 250,
data: function (params) {
return {'query': params.term};
return { 'query': params.term };
},
cache: true
},
placeholder: "",
placeholder: '',
allowClear: true,
minimumInputLength: 1
});
Expand Down
4 changes: 2 additions & 2 deletions Resources/views/form/bootstrap_3_layout.html.twig
Expand Up @@ -455,8 +455,8 @@

{# EasyAdminAutocomplete form type #}
{% block easyadmin_autocomplete_widget %}
{# display form row, but never its label #}
{{ form_row(form.autocomplete, {'label': false, 'attr': attr|merge({ 'data-easyadmin-autocomplete-url' : path('easyadmin', {
{# display the form row, but don't display its label #}
{{ form_row(form.autocomplete, { label: false, attr: attr|merge({ 'data-easyadmin-autocomplete-url' : path('easyadmin', {
action: 'autocomplete',
entity: easyadmin.entity.name,
property: easyadmin.field.fieldName,
Expand Down
22 changes: 17 additions & 5 deletions Search/Autocomplete.php
Expand Up @@ -12,10 +12,12 @@
namespace JavierEguiluz\Bundle\EasyAdminBundle\Search;

use JavierEguiluz\Bundle\EasyAdminBundle\Configuration\Configurator;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\PropertyAccess\PropertyAccessor;

/**
* It looks for the values of entity which match the given query. It's used for
* the autocomplete field types.
*
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
*/
class Autocomplete
Expand All @@ -34,15 +36,25 @@ public function __construct(Configurator $configurator, Finder $finder, Property
$this->propertyAccessor = $propertyAccessor;
}

/**
* Finds the values of the given entity which match the query provided.
*
* @param string $entity
* @param string $property
* @param string $view
* @param string $query
*
* @return array
*/
public function find($entity, $property, $view, $query)
{
if (empty($entity) || empty($property) || empty($view) || empty($query)) {
return new JsonResponse(array('results' => array()));
return array('results' => array());
}

$backendConfig = $this->configurator->getBackendConfig();
if (!isset($backendConfig['entities'][$entity])) {
throw new \InvalidArgumentException(sprintf('The "entity" argument must contain the name of a entity managed by EasyAdmin ("%s" given).', $entity));
throw new \InvalidArgumentException(sprintf('The "entity" argument must contain the name of an entity managed by EasyAdmin ("%s" given).', $entity));
}

if (!isset($backendConfig['entities'][$entity][$view]['fields'][$property])) {
Expand All @@ -57,7 +69,7 @@ public function find($entity, $property, $view, $query)
$targetEntityConfig = $this->configurator->getEntityConfigByClass($targetEntityClass);
$entities = $this->finder->findByAllProperties($targetEntityConfig, $query, $backendConfig['list']['max_results']);

return new JsonResponse(array('results' => $this->processResults($entities, $targetEntityConfig)));
return array('results' => $this->processResults($entities, $targetEntityConfig));
}

private function processResults($entities, $targetEntityConfig)
Expand All @@ -67,7 +79,7 @@ private function processResults($entities, $targetEntityConfig)
foreach ($entities as $entity) {
$results[] = array(
'id' => $this->propertyAccessor->getValue($entity, $targetEntityConfig['primary_key_field_name']),
'text' => (string) $entity
'text' => (string) $entity,
);
}

Expand Down
2 changes: 1 addition & 1 deletion Search/Finder.php
Expand Up @@ -26,7 +26,7 @@ public function __construct(QueryBuilder $queryBuilder)
$this->queryBuilder = $queryBuilder;
}

public function findByAllProperties(array $entityConfig, $searchQuery, $maxResults = Query::MAX_RESULTS, $sortField = null, $sortDirection = null)
public function findByAllProperties(array $entityConfig, $searchQuery, $maxResults = Finder::MAX_RESULTS, $sortField = null, $sortDirection = null)
{
$queryBuilder = $this->queryBuilder->createSearchQueryBuilder($entityConfig, $searchQuery, $sortField, $sortDirection);

Expand Down

0 comments on commit 4bace89

Please sign in to comment.