0
votes

So I am using Symfony 2, and sometimes when calling the updateAction I get the following 500 error kicked back from symfony:

"An exception occurred while executing 'INSERT INTO topic_sources (platform, authors, keywords, rss_feeds, topic_id) VALUES (?, ?, ?, ?, ?)' with params ["facebook", "153213781413350", null, "https://www.facebook.com/HuffPostWomen", 4641]: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '4641-facebook' for key 'PRIMARY'"...etc

I understand that the issue is in relation to the fact that it is trying to insert into a row that already exists, but I don't understand WHY this would happen... I was under the impression symfony and Doctrine manage this. Here is the code for my updateAction:

public function updateAction($id) {
        $topic = $this->getTopic($id);

        if (!$topic) {
            throw $this->createNotFoundException('No topic found for id ' . $id);
    }

    $originalTopicSources = new ArrayCollection();

    // Grab all the topic sources on the page 
    foreach ($topic->getTopicSources() as $topicSource) {
        $originalTopicSources->add($topicSource);
    }

    // Get all the Request Data
    $request = $this->getRequest();
    $requestData = $request->request->all();
    $imageData = $request->get("topic-image");

    $em = $this->getDoctrine()
            ->getManager();


    // Bind the form for validation
    $editTopicForm = $this->createForm(new TopicType($em), $topic);
    $editTopicForm->bind($request);


    if ($editTopicForm->isValid()) {
        // Grab image and decode
        if ($imageData) {
            list($type, $imageData) = explode(';', $imageData);
            list(, $imageData) = explode(',', $imageData);
            $data = base64_decode($imageData);
            $filename = "$id." . explode("/", $type)[1];

            $topic->setImage($filename);
            file_put_contents($this->get('kernel')->getRootDir() . "/../web/uploads/topics/$filename", $data);
        }

        set_time_limit(10);

        // Compare the original topic sources with the newly passed in form and remove any topic sources that aren't common between the two
        foreach ($originalTopicSources as $topicSource) {

            if (false === $topic->getTopicSources()->contains($topicSource)) {
                $em->remove($topicSource);
            }
        }

        $em->persist($topic);
        $em->flush();

        $this->addFlash('success','The topic has been updated successfully :)');
    }


    $project = $topic->getProject();
    $projectForm = $this->createForm(new ProjectType(array("user" => $this->getUser())), $project);

    $newTopic = new Topic();
    $newTopicForm = $this->createForm(new NewTopicType(), $newTopic);

    // Get tag names
    $em = $this->getDoctrine()
            ->getEntityManager();

    $response = array();
    $tags = $em->getRepository('AppBundle:Tag')->findAll();
    $tagNames = array();

    foreach ($tags as $tag) {
        array_push($tagNames, $tag->getName());
    }

    return $this->render('AppBundle:Topic:edit.html.twig', array(
        'project' => $topic->getProject(),
        'projectForm' => $projectForm->createView(),
        'newTopicForm' => $newTopicForm->createView(),
        'tags' => $tagNames,
        'topic' => $topic,
        'editTopicForm' => $editTopicForm->createView(),
        'facebook_app_id' => $this->container->getParameter('facebook_app_id_'.$this->get('kernel')->getEnvironment()),
        'facebook_app_secret' => $this->container->getParameter('facebook_app_secret_'.$this->get('kernel')->getEnvironment()),
        'facebook_app_access_token' => $this->container->getParameter('facebook_app_access_token_'.$this->get('kernel')->getEnvironment())
    ));
}

Any help would be greatly appreciated... I'm losing my mind here!

***** UPDATE As requested, here is the entity associated:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Validator\Constraints as Assert;
use JMS\Serializer\Annotation\Exclude;
use JMS\Serializer\Annotation\MaxDepth;

/**
 * Topic
 *
 * @ORM\Table(name="topics", indexes={@ORM\Index(name="project_id", columns={"project_id"})})
 * @ORM\Entity(repositoryClass="AppBundle\Entity\Repository\TopicRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class Topic {

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     * @Assert\NotBlank(message="Listeners require a name")
     *
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text")
     *
     */
    private $description;

    /**
     * Image file
     *
     * @var File
     *
     * @Assert\File(
     *     maxSize = "5M",
     *     mimeTypes = {"image/jpeg", "image/gif", "image/png", "image/tiff"},
     *     maxSizeMessage = "The maxmimum allowed file size is 5MB.",
     *     mimeTypesMessage = "Only the filetypes image are allowed."
     * )
     */
    protected $imageFile;

    /**
     * @ORM\Column(type="string", length=255, name="image_file")
     *
     * @var string $image
     */
    protected $image;

    /**
     * @var boolean
     *
     * @ORM\Column(name="exclude_from_api", type="boolean", nullable=true, options={"default": false})
     */
    protected $excludeFromApi = false;

    /**
     * @var integer
     *
     * @ORM\Column(name="feed_size", type="integer", options={"default": 50})
     * @Assert\GreaterThanOrEqual(
     *      message = "A listener's feed size cannot be less than 0",
     *      value = 0
     * )
     *
     */
    private $feedSize = 50;

    /**
     * @var boolean
     *
     * @ORM\Column(name="include_parents", type="boolean", nullable=true, options={"default": false})
     */
    private $includeParents = false;

    /**
     * @var boolean
     *
     * @ORM\Column(name="track_urls", type="boolean", nullable=true, options={"default": false})
     */
    private $trackUrls = false;

    /**
     * @var boolean
     *
     * @ORM\Column(name="active", type="boolean", nullable=true, options={"default": true})
     */
    private $active = true;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="updated_at", type="datetime", nullable=false)
     */
    private $updatedAt;

    /**
     * @var \AppBundle\Entity\Project
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Project", inversedBy="topics")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="project_id", referencedColumnName="id")
     * })
     *
     * @Exclude
     *
     */
    private $project;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Rule", mappedBy="topics", cascade={"all"})
     * @ORM\JoinTable(name="topics_rules",
     *   joinColumns={
     *     @ORM\JoinColumn(name="topic_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="rule_id", referencedColumnName="id")
     *   }
     * )
     */
    private $rules;

    /**
     * @var \AppBundle\Entity\TopicSource
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\TopicSource", mappedBy="topic", cascade={"all"})
     */
    private $topicSources;

    /**
     * @var \AppBundle\Entity\Historical
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Historical", mappedBy="topic", cascade={"all"})
     *
     * @MaxDepth(1)
     *
     */
    private $historicals;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Entry", inversedBy="topics")
     * @ORM\JoinTable(name="entries_topics",
     *   joinColumns={
     *     @ORM\JoinColumn(name="topic_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="entry_id", referencedColumnName="id"),
     *     @ORM\JoinColumn(name="platform", referencedColumnName="platform")
     *   }
     * )
     */
    private $entries;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Tag", inversedBy="topics", cascade={"persist"})
     * @ORM\JoinTable(name="topics_tags",
     *   joinColumns={
     *     @ORM\JoinColumn(name="topic_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="tag_id", referencedColumnName="id")
     *   }
     * )
     */
    private $tags;

    /**
     * Constructor
     */
    public function __construct() {
        $this->topicSources = new \Doctrine\Common\Collections\ArrayCollection();
        $this->historicals = new \Doctrine\Common\Collections\ArrayCollection();
        $this->rules = new \Doctrine\Common\Collections\ArrayCollection();
        $this->entries = new \Doctrine\Common\Collections\ArrayCollection();
        $this->tags = new \Doctrine\Common\Collections\ArrayCollection();

        $this->setUpdatedAt(new \DateTime());
    }

    /**
     * @ORM\PreUpdate
     */
    public function setUpdatedAtValue() {
        $this->setUpdatedAt(new \DateTime());
    }

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

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

        return $this;
    }

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

    /**
     * Get Exclude from API
     *
     * @return boolean
     */
    public function getExcludeFromApi() {
        return $this->excludeFromApi;
    }

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

    /**
     * Set description
     *
     * @param string $description
     * @return Topic
     */
    public function setDescription($description) {
        $this->description = $description;

        return $this;
    }

    /**
     * Set Exclude From API
     *
     * @param boolean $excludeFromApi
     * @return Topic
     */
    public function setExcludeFromApi($excludeFromApi) {
        $this->excludeFromApi = $excludeFromApi;

        return $this;
    }

    /**
     * Set feedSize
     *
     * @param integer $feedSize
     * @return Topic
     */
    public function setFeedSize($feedSize) {
        $this->feedSize = $feedSize;

        return $this;
    }

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

    /**
     * Set includeParents
     *
     * @param boolean $includeParents
     * @return Topic
     */
    public function setIncludeParents($includeParents) {
        $this->includeParents = $includeParents;

        return $this;
    }

    /**
     * Get includeParents
     *
     * @return boolean
     */
    public function getIncludeParents() {
        return $this->includeParents;
    }

    /**
     * Set trackUrls
     *
     * @param boolean $trackUrls
     * @return Topic
     */
    public function setTrackUrls($trackUrls) {
        $this->trackUrls = $trackUrls;

        return $this;
    }

    /**
     * Get trackUrls
     *
     * @return boolean
     */
    public function getTrackUrls() {
        return $this->trackUrls;
    }

    /**
     * Set active
     *
     * @param boolean $active
     * @return Topic
     */
    public function setActive($active) {
        $this->active = $active;

        return $this;
    }

    /**
     * Get active
     *
     * @return boolean
     */
    public function getActive() {
        return $this->active;
    }

    /**
     * Set updatedAt
     *
     * @param \DateTime $updatedAt
     * @return Topic
     */
    public function setUpdatedAt($updatedAt) {
        $this->updatedAt = $updatedAt;

        return $this;
    }

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

    /**
     * Set project
     *
     * @param \AppBundle\Entity\Project $project
     * @return Topic
     */
    public function setProject(\AppBundle\Entity\Project $project = null) {
        $this->project = $project;

        # ~EN (2015): feed size is not set properly when topic is init'd, only updating $project would update this topic's feed size
        if($feedSize = $this->project->getFeedSize()){
            $this->feedSize = $feedSize;
        }

        return $this;
    }

    /**
     * Get project
     *
     * @return \AppBundle\Entity\Project
     */
    public function getProject() {
        return $this->project;
    }

    /**
     * Add rule
     *
     * @param \AppBundle\Entity\Rule $rule
     * @return Topic
     */
    public function addRule(\AppBundle\Entity\Rule $rule) {
        $rule->addTopic($this);
        $this->rules[] = $rule;

        return $this;
    }

    /**
     * Remove rule
     *
     * @param \AppBundle\Entity\Rule $rule
     */
    public function removeRule(\AppBundle\Entity\Rule $rule) {
        $this->rules->removeElement($rule);
    }

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

    /**
     * Add topicSource
     *
     * @param \AppBundle\Entity\TopicSource $topicSource
     * @return Topic
     */
    public function addTopicSource(\AppBundle\Entity\TopicSource $topicSource) {
        $topicSource->setTopic($this);
        $this->topicSources[] = $topicSource;

        return $this;
    }

    /**
     * Remove topicSource
     *
     * @param \AppBundle\Entity\topicSource $topicSource
     */
    public function removeTopicSource(\AppBundle\Entity\TopicSource $topicSource) {
        $this->topicSources->removeElement($topicSource);
    }

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

    /**
     * @var \Doctrine\Common\Collections\Collection
     */
    private $topicSource;

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

    /**
     * Add historical
     *
     * @param \AppBundle\Entity\Historical $historical
     * @return Historical
     */
    public function addHistorical(\AppBundle\Entity\Historical $historical) {
        $this->historicals[] = $historical;

        return $this;
    }

    /**
     * Remove historical
     *
     * @param \AppBundle\Entity\Historical $historical
     */
    public function removeHistorical(\AppBundle\Entity\Historical $historical) {
        $this->historicals->removeElement($historical);
    }

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

    /**
     * Add entry
     *
     * @param \AppBundle\Entity\Entry $entry
     * @return Topic
     */
    public function addEntry(\AppBundle\Entity\Entry $entry) {
        $this->entries[] = $entry;

        return $this;
    }

    /**
     * Remove entry
     *
     * @param \AppBundle\Entity\Entry $entry
     */
    public function removeEntry(\AppBundle\Entity\Entry $entry) {
        $this->entries->removeElement($entry);
    }

    /**
     * Get entries
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getEntries($limit = null) {
        $to_return      = array();
        $max_entries    = ($limit != null)?$limit:$this->getFeedSize();
        foreach ($this->entries as $entry) {
            if (--$max_entries <= 0)
                break;
            $to_return[] = $entry;
        }
        return $to_return;
        //return new ArrayObject(array_slice((array) $this->entries, 0, $this->getFeedSize()));
    }

    /**
     * Add tags
     *
     * @param \AppBundle\Entity\Tag $tags
     * @return Topic
     */
    public function addTag(\AppBundle\Entity\Tag $tags) {
        $this->tags[] = $tags;

        return $this;
    }

    /**
     * Remove tags
     *
     * @param \AppBundle\Entity\Tag $tags
     */
    public function removeTag(\AppBundle\Entity\Tag $tags) {
        $this->tags->removeElement($tags);
    }

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

    /**
     * Sets imageFile.
     *
     * @param File $imageFile
     */
    public function setImageFile(File $imageFile = null) {
        $this->imageFile = $imageFile;
        // check if we have an old image path
        if (isset($this->image)) {
            // store the old name to delete after the update
            $this->temp = $this->image;
            $this->image = null;
        } else {
            $this->image = 'initial';
        }
    }

    /**
     * @return File
     */
    public function getImageFile() {
        return $this->imageFile;
    }

    /**
     * @param string $imageName
     */
    public function setImage($image) {
        $this->image = $image;
    }

    /**
     * @return string
     */
    public function getImage() {
        return $this->image;
    }

    /**
     * Called before saving the entity
     *
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload() {
        $filename = sha1(uniqid(mt_rand(), true));
        if (null !== $this->imageFile) {
            $this->image = $filename . '.' . $this->imageFile->guessExtension();
        }
    }

    /**
     * Called before entity removal
     *
     * @ORM\PreRemove()
     */
    public function removeUpload() {
//        if ($file = $this->getAbsolutePath()) {
//            unlink($file);
//        }
    }

    /**
     * Called after entity persistence
     *
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload() {
        // The file property can be empty if the field is not required
        if (null === $this->imageFile) {
            return;
        }

        // Use the original file name here but you should
        // sanitize it at least to avoid any security issues
        // move takes the target directory and then the
        // target filename to move to
        $this->imageFile->move(
                "%kernel.root_dir%/../web/uploads/topics", $this->image
        );

        // Set the path property to the filename where you've saved the file
        //$this->path = $this->file->getClientOriginalName();
        // Clean up the file property as you won't need it anymore
        $this->imageFile = null;
    }

}

1
Could you post the definition of your entity?Diego Ferri
Added, thanks for the help :)Addison Rodomista
Post the code for getTopic() and your mysql table by using "SHOW CREATE TABLE topic_sources;". I suspect you have a unique key on the platform field and you are trying to insert a new record where platform="facebook";crafter

1 Answers

1
votes

This is because one of the fields in your database is empty. So, try to delete everything in your table and generate again the command.