I’m trying to create script, that will import keywords from images to database. Keywords in keyword table should be unique, but many images can share the same keyword. So I have wrote those two simple models:
IMAGE:
class Image
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
private $id;
/** @ORM\Column(unique=true, nullable=false) */
private $filename;
/**
* @ORM\ManyToMany(targetEntity="Keyword", inversedBy="images", cascade={"persist"})
* @ORM\JoinTable(name="image_keyword_binder")
*/
private $keywords;
public function __construct()
{
$this->keywords = new \Doctrine\Common\Collections\ArrayCollection();
}
}
KEYWORD:
class Keyword
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
private $id;
/**
* @ORM\Column(type="string", nullable=false, unique=true)
*/
private $text;
/**
* @ORM\ManyToMany(targetEntity="Image", mappedBy="keywords")
*/
private $images;
public function __construct()
{
$this->images = new \Doctrine\Common\Collections\ArrayCollection();
}
}
Now, during import, for every image i want to add to DB only new keywords, and if image is described with existing keyword i want add reference to this existing one. I want to achieve code like this:
$images[] = array('filename'=>'image1.jpg', 'keywords'=>array('blue', 'green', 'yellow'));
$images[] = array('filename'=>'image2.jpg', 'keywords'=>array('pink', 'green', 'yellow'));
$images[] = array('filename'=>'image2.jpg', 'keywords'=>array('black', 'green', 'red'));
foreach($images as $img)
{
$image = new \FL\Entity\Image();
$image->setFilename($image['filename']);
$image->setKeywords($image['keywords']);
// em is Entity Manager Instance
$em->persist($image);
$em->flush();
}
Another thing to know is that I dont want to make a flush in every loop. I will be using something like described here: http://readthedocs.org/docs/doctrine-orm/en/latest/reference/batch-processing.html in Bulk Inserts part.
Is this all possible? Can Doctrine determine if certain keyword exists and automaticly add only refrence to it? Loading all existing keywords from DB in every loop and comparing them with new loaded from image isn’t a solution.
This is not supported by Doctrine2 at the moment. You will have to use your repository through
You can also use DQL if you prefer, but this is the fastest way.
So yes, you will have a lot of overhead.
What you can do to reduce it is building up large chunks of not yet persisted entities, use a
IN(:fileNames)condition and so reduce the number of queries to one per batch chunk.Anyway, the check is still up to you.