-2

I have problem with @Gedmo\SoftDeleteable when i have unique fields. If I remove some row from table and leather a try put new record and by have this some name give mi error:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'weqwewqe1' for key 'UNIQ_*************'

How change this to validation form message in correct place?

And should send me a message form with the record already exists.

My entity:

    /**
 * @ORM\Entity(repositoryClass = "Eteam\PageBundle\Entity\Repository\PageRepository")
 * @ORM\Table(name = "page")
 * @ORM\HasLifecycleCallbacks
 * @Gedmo\SoftDeleteable(fieldName = "deletedDate", timeAware = false)
 *
 * @UniqueEntity(fields = {"name"})
 * @UniqueEntity(fields = {"slug"})
 */
class Page
{
    /**
     * @ORM\Column(name = "id", type = "integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy = "AUTO")
     */
    private $id;

    /**
     * @ORM\Column(name = "name", type = "string", length = 120, unique = true)
     *
     * @Assert\NotBlank
     * @Assert\Length(
     *      min = 3,
     *      max = 120
     * )
     */
    private $name;

    /**
     * @ORM\Column(name = "slug", type = "string", length = 120, unique = true)
     *
     * @Assert\NotBlank
     * @Assert\Length(
     *      min = 3,
     *      max = 120
     * )
     */
    private $slug;

    /**
     * @ORM\Column(name = "type", type = "string", length = 50)
     */
    private $type;

    /**
     * @ORM\Column(name = "status", type = "string", length = 50)
     */
    private $status;

    /**
     * @ORM\OneToMany(targetEntity = "PageContent", mappedBy = "pageId")
     */
    private $content;

    /**
     * @ORM\Column(name = "parent", type = "string", length = 50, nullable = true)
     */
    private $parent;

    /**
     * @ORM\ManyToOne(targetEntity = "PageTemplate", inversedBy = "page")
     * @ORM\JoinColumn(name = "page_template_id", referencedColumnName = "id", onDelete = "SET NULL")
     */
    private $pageTemplate;

    /**
     * @ORM\ManyToOne(targetEntity = "PageContentMap", inversedBy = "page")
     * @ORM\JoinColumn(name = "page_content_map_id", referencedColumnName = "id", onDelete = "SET NULL")
     */
    private $pageContentMapId;

    /**
     * @ORM\Column(name = "created_date", type = "datetime")
     */
    private $createdDate;

    /**
     * @ORM\Column(name = "updated_date", type = "datetime", nullable = true)
     */
    private $updatedDate;

    /**
     * @var \DateTime deletedDate
     * @ORM\Column(name = "deleted_date", type = "datetime", nullable = true)
     */
    private $deletedDate;


    /**
     * Constructor
     */
    public function __construct()
    {
        $this->content = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Page
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set slug
     *
     * @param string $slug
     *
     * @return Page
     */
    public function setSlug($slug)
    {
        $genSlug = new Slugify();
        $this->slug = $genSlug->slugify($slug);

        return $this;
    }

    /**
     * Get slug
     *
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * Set type
     *
     * @param string $type
     *
     * @return Page
     */
    public function setType($type)
    {
        $this->type = $type;

        return $this;
    }

    /**
     * Get type
     *
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * Set status
     *
     * @param string $status
     *
     * @return Page
     */
    public function setStatus($status)
    {
        $this->status = $status;

        return $this;
    }

    /**
     * Get status
     *
     * @return string
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * Set parent
     *
     * @param string $parent
     *
     * @return Page
     */
    public function setParent($parent)
    {
        $this->parent = $parent;

        return $this;
    }

    /**
     * Get parent
     *
     * @return string
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * Set createdDate
     *
     * @param \DateTime $createdDate
     *
     * @return Page
     */
    public function setCreatedDate($createdDate)
    {
        $this->createdDate = $createdDate;

        return $this;
    }

    /**
     * Get createdDate
     *
     * @return \DateTime
     */
    public function getCreatedDate()
    {
        return $this->createdDate;
    }

    /**
     * Set updatedDate
     *
     * @param \DateTime $updatedDate
     *
     * @return Page
     */
    public function setUpdatedDate($updatedDate)
    {
        $this->updatedDate = $updatedDate;

        return $this;
    }

    /**
     * Get updatedDate
     *
     * @return \DateTime
     */
    public function getUpdatedDate()
    {
        return $this->updatedDate;
    }

    /**
     * Set deletedDate
     *
     * @param \DateTime $deletedDate
     *
     * @return Page
     */
    public function setDeletedDate($deletedDate)
    {
        $this->deletedDate = $deletedDate;

        return $this;
    }

    /**
     * Get deletedDate
     *
     * @return \DateTime
     */
    public function getDeletedDate()
    {
        return $this->deletedDate;
    }

    /**
     * Add content
     *
     * @param \Eteam\PageBundle\Entity\PageContent $content
     *
     * @return Page
     */
    public function addContent(\Eteam\PageBundle\Entity\PageContent $content)
    {
        $this->content[] = $content;

        return $this;
    }

    /**
     * Remove content
     *
     * @param \Eteam\PageBundle\Entity\PageContent $content
     */
    public function removeContent(\Eteam\PageBundle\Entity\PageContent $content)
    {
        $this->content->removeElement($content);
    }

    /**
     * Get content
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * Set pageTemplate
     *
     * @param \Eteam\PageBundle\Entity\PageTemplate $pageTemplate
     *
     * @return Page
     */
    public function setPageTemplate(\Eteam\PageBundle\Entity\PageTemplate $pageTemplate = null)
    {
        $this->pageTemplate = $pageTemplate;

        return $this;
    }

    /**
     * Get pageTemplate
     *
     * @return \Eteam\PageBundle\Entity\PageTemplate
     */
    public function getPageTemplate()
    {
        return $this->pageTemplate;
    }

    /**
     * Set pageContentMapId
     *
     * @param \Eteam\PageBundle\Entity\PageContentMap $pageContentMapId
     *
     * @return Page
     */
    public function setPageContentMapId(\Eteam\PageBundle\Entity\PageContentMap $pageContentMapId = null)
    {
        $this->pageContentMapId = $pageContentMapId;

        return $this;
    }

    /**
     * Get pageContentMapId
     *
     * @return \Eteam\PageBundle\Entity\PageContentMap
     */
    public function getPageContentMapId()
    {
        return $this->pageContentMapId;
    }

    /**
     * @ORM\PrePersist
     * @ORM\PreUpdate
     */
    public function preSave()
    {
        if (null === $this->slug) {
            $this->setSlug($this->getName());
        }

        if (null == $this->status) {
            $this->setStatus('unpublish');
        }

    }

Steel I not fixed yet this problem. I need catch this exception and send to form message this name is ready exist. Please help.

Zemiel
  • 77
  • 11

3 Answers3

3

Do you know what means "soft delete"? It means that every "delete" operation will be converted to SQL that only set some deleted flag to true. And if you will insert another row with the same value of unique field that have soft deleted row you will get this message.

You have two ways to solve this problem:

  • Make your unique index with two columns: your original unique field and deleted flag. Then you will get this error only when you try to add row with the existing unique fields values only for not soft deleted.
  • Avoid making this violation: you should exclude the possibility to add row that duplicates another in unique fields.

The second one is the best approach IMHO.

Michael Sivolobov
  • 12,388
  • 3
  • 43
  • 64
  • Well, all good but still I do not know how to display the exception in the right place in the form of a given name already exists? – Zemiel Nov 11 '15 at 20:41
1

Unique Constraints!

You have to Use UniqueConstraints, not UniqueEntity.

For example, for name, create a UniqueConstraint between name and deletedDate.

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
 * @ORM\Entity(repositoryClass="Eteam\PageBundle\Entity\Repository\PageRepository")
 * @ORM\Table(name="page",uniqueConstraints={@ORM\UniqueConstraint(name="name_unique", columns={"name", "deleted_date"})})
 * @Gedmo\SoftDeleteable(fieldName="deletedDate", timeAware=false)
 */
class Page
{
    //..
}
Community
  • 1
  • 1
Mick
  • 30,759
  • 16
  • 111
  • 130
0

Mick's nice solution:

/** * @ORM\Table(name="page",uniqueConstraints={@ORM\UniqueConstraint(name="name_unique", columns={"name", "deleted_date"})}) */

probably work with postgresql but doesn't work in some versions of mysql (because NULL is an unknown value). How to send to form message this name is ready exist.? For example we can change action newAction and editAction in controller (when CRUD is created in console):

public function newAction(Request $request)
{
    $computer = new Computer();
    $form = $this->createForm('AppBundle\Form\ComputerType', $computer);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $warning = $this->uniqueInventoryNr($computer->getId(),$computer->getInventoryNr()); // added
        if ($warning == '') { // added
               $em = $this->getDoctrine()->getManager();
            $em->persist($computer);
            $em->flush();
            return $this->redirectToRoute('computer_index');
        } else { // added
            $form_error = new \Symfony\Component\Form\FormError($warning); // added
            $form->addError($form_error); // added
        } // added

    }

    return $this->render('computer/new.html.twig', array(
        'computer' => $computer,
        'form' => $form->createView(),
    ));
}    

Edit action:

/**
 * Displays a form to edit an existing computer entity.
 *
 * @Route("/{id}/edit", name="computer_edit")
 * @Method({"GET", "POST"})
 */
public function editAction(Request $request, Computer $computer)
{
    $deleteForm = $this->createDeleteForm($computer);
    $editForm = $this->createForm('AppBundle\Form\ComputerType', $computer);
    $editForm->handleRequest($request);

    if ($editForm->isSubmitted() && $editForm->isValid()) {
        $warning = $this->uniqueInventoryNr($computer->getId(),$computer->getInventoryNr()); // added
        if ( $warning == '') { // added
            $this->getDoctrine()->getManager()->flush();

            return $this->redirectToRoute('computer_edit', array('id' => $computer->getId()));
        } else { // added
            $form_error = new \Symfony\Component\Form\FormError($warning); // added
            $editForm->addError($form_error); // added
        } // added
    }

    return $this->render('computer/edit.html.twig', array(
        'computer' => $computer,
        'edit_form' => $editForm->createView(),
        'delete_form' => $deleteForm->createView(),
    ));
}

checking function:

private function uniqueInventoryNr($computerId,$inventoryNr)
{
    $message = '';
    $em = $this->getDoctrine()->getManager();
    $computer_in = $em->getRepository('AppBundle\Entity\Computer')->findBy(array('inventoryNr' => $inventoryNr));
    if (count($computer_in) > 0) {
        if ($computer_in[0]->getId() != $computerId) // avoid when you edit
        { 
            $message =  'Inventory number is duplicated. '; 
        }
    }
    return $message;
}
Puch
  • 55
  • 7