JsFormValidatorBundle icon indicating copy to clipboard operation
JsFormValidatorBundle copied to clipboard

Update entity with unique constraint

Open georgevlada opened this issue 11 years ago • 4 comments

Hello, We can not make update on entity with unique constraint because the validation does not receive the entity primary key. How can we use the validation with unique constraint for update action?

georgevlada avatar Aug 26 '14 15:08 georgevlada

Hi,

This is a feature we could use too. Seems a form will issue a "duplicate value" error when updating an entity. It does work great for new entities through, problem is you just can't update an entity.

Thanks, Robert

robertsimionescu avatar Aug 27 '14 13:08 robertsimionescu

+1 for this.

The way around it I think it to set up validation groups, and set it up so that the validation group that contains the Unique constraint is only used when creating a new entity, and the group without the unique constraint is used when editing an entity.

However, this won't ensure uniqueness as during an entity edit you could still set a duplicate value.

An alternative approach would be to allow disabling a particular validation rule on the JS side, and leave it fall back to the server side validation in case of an error. However, from what I can see from the docs it is currently only possible to disable either an entire form, or an entire field, and not just a single validation rule.

benr77 avatar Jan 26 '15 09:01 benr77

As a work around I have just replaced the controller with a unique one, and in the custom controller I'm getting the ID of the entity from the URL via the HTTP_REFERER - hacky I know but it's working.

benr77 avatar Jan 26 '15 12:01 benr77

Same here, I followed the idea of @benr77 to create my own validator controller, matching the "ID" parameter from the referer route, but we should get at least the primary index of the current entity in the ajax request to have a clean validator :

So I followed those steps to create my custom unique validator controller

And here is my controller :

<?php
namespace AppBundle\Controller;


use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class AjaxValidatorController extends Controller
{
    /**
     * @param Request $request
     * @return JsonResponse
     */
    public function checkUniqueEntityAction(Request $request)
    {
        $data = $request->request->all();
        foreach ($data['data'] as $value) {
            // If field(s) has an empty value and it should be ignored
            if ((bool) $data['ignoreNull'] && ('' === $value || is_null($value))) {
                // Just return a positive result
                return new JsonResponse(true);
            }
        }

        $entities = $this
            ->get('doctrine')
            ->getRepository($data['entityName'])
            ->{$data['repositoryMethod']}($data['data'])
        ;

        if (!empty($entities)) {
            $sampleEntity = $entities[0];
            $refererParameters = $this->getRefererParameters($request);

            if (!empty($refererParameters['id']) && method_exists($sampleEntity, 'getId')) {
                foreach($entities as $key => $entity) {
                    if ($entity->getId() == $refererParameters['id']) {
                        unset($entities[$key]);
                    }
                }
            }
        }

        return new JsonResponse(empty($entities));
    }

    /**
     * @param Request $request
     * @return array
     */
    private function getRefererParameters(Request $request)
    {
        $referer = $request->headers->get('referer');
        $lastPath = substr($referer, strpos($referer, $request->getBaseUrl()));
        $lastPath = str_replace($request->getBaseUrl(), '', $lastPath);

        $matcher = $this->get('router')->getMatcher();
        $parameters = $matcher->match($lastPath);

        return $parameters;
    }
}

bastos71 avatar Jul 06 '17 09:07 bastos71