doctrine2 slugable and datafixtures - doctrine-orm

I'm trying to make a Field of a Object slugable.
Model looks like:
namespace myBundle\Bundles\BlogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* myBundle\Bundles\BlogBundle\Entity\Category
*
* #ORM\Table()
* #ORM\Entity
*/
class Category
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $title
*
* #Gedmo\Sluggable
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* #Gedmo\Slug(separator="-", updatable=false, unique=true)
* #ORM\Column(name="slug", type="string", length=255, unique=true)
*/
private $slug;
// other properties and methods
The Fixtures:
namespace myBundle\Bundles\BlogBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use tooMuch\Bundles\BlogBundle\Entity\Category;
class LoadCategoryData extends AbstractFixture implements OrderedFixtureInterface
{
public function load($manager)
{
$this->generateCategory($manager);
}
public function generateCategory($manager)
{
for ($i=0; $i < 10; $i++) {
$category = new Category();
$category->setTitle('Category '.$i);
$manager->persist($category);
$manager->flush();
$this->addReference('category'.$i, $category);
unset($category);
}
}
schema create:
# sf doctrine:schema:create
ATTENTION: This operation should not be executed in a production environment.
Creating database schema...
Database schema created successfully!
but then when I'm trying to add the fixtures:
# sf doctrine:fixtures:load
> purging database
> loading myBundle\Bundles\BlogBundle\DataFixtures\ORM\LoadCategoryData
[PDOException]
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'slug' cannot be null
doctrine:fixtures:load [--fixtures[="..."]] [--append] [--em="…"]
#
any ideas?

The problem isn't in the fixtures, it's in Slug generation itself. If it's properly set up, you should never have $slug as null
Are you sure you have Sluggable listener attached?

Related

How to implement multi user support using fos user bundle

I've been working on a multi users web application using symfony 3.4 framework with fos user bundle in order to easily manipulate users.
I've integrated the bundle and everything work fine except that the bundle features don't match my need when it comes to multi users through inheritance !
Is there any trick to implement the multi user inheritance in fos bundle ?
I've tried a lot of different tricks like changing the roles , changing the user model interface, using symfony groups but all of them seemed to be not working !
The thing that will solve [with an ugly way] my problem is to change the value of the discriminator column .
* #ORM\Table(name="fos_user")
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="typeutilisateur", type="string")
* #ORM\DiscriminatorMap({"Parent"="User","admin" =
"Administrateur","association"
="AsoociationsBundle\Entity\Association",
"Demandeurservice"="EldersStoryBundle\Entity\Demandeurservice",
"Formateur"="FormationBundle\Entity\Formateur"
,"Prestataire"="AnnonceEldersCareBundle\Entity\Prestataireservice"})
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=30, nullable=true)
*/
private $nom;
/**
* #var string
*
* #ORM\Column(name="prenom", type="string", length=30, nullable=true)
*/
private $prenom;
/**
* #var string
*
* #ORM\Column(name="adresse", type="string", length=50)
*/
private $adresse;
/**
* #var string
*
* #ORM\Column(name="telephone", type="integer")
*/
private $telephone;
/**
* #var string
*
* #ORM\Column(name="sexe", type="string", length=30, nullable=true)
*/
private $sexe;
/**
* #var \DateTime
*
* #ORM\Column(name="datecreation", type="datetime")
*/
private $datecreation;
/**
* #var string
*
* #ORM\Column(name="avatar", type="string", length=255)
*/
private $avatar;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Group")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
public function __construct()
{
parent::__construct();
}
}
/*This is the sub class*/
<?php
namespace EldersStoryBundle\Entity;
use AppBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
/**
* Demandeurservice
*
* #ORM\Table(name="demandeurservice")
* #ORM\Entity(repositoryClass="EldersStoryBundle\
Repository\DemandeurserviceRepository")
*/
class Demandeurservice extends User
{
/**
* #var string
*
* #ORM\Column(name="typemaladie", type="string", length=50)
*/
private $typemaladie;
/**
* #var string
*
* #ORM\Column(name="descriptionmaladie", type="string", length=255)
*/
private $descriptionmaladie;
/**
* #var string
*
* #ORM\Column(name="etatmaladie", type="string", length=255)
*/
private $etatmaladie;
/**
* #var int
*
* #ORM\Column(name="pointelderly", type="integer")
*/
private $pointelderly;
}
Everytime i subscribe i get the row in the table but with a discriminator column value ="parent"
So is there any major way to get this done ? or at least to change the value of the discriminator column ?
Remove the DiscriminatorMap. If you don't create one, Doctrine will generate one automagically. So long as you don't go messing around with names of Entity objects (ie, change Person to Persona, or whatever) then that's your best bet. It's also more dynamic because if/when you add additional types, it will update it for you (when cache is removed).
See here, last bullet point quoted:
If no discriminator map is provided, then the map is generated automatically. The automatically generated discriminator map contains the lowercase short name of each class as key.

How to remove a relationship cleanly in Docrine 2?

There are entities Endpoint, EndpointServerConfig, and Server:
/**
* Server
*
* #ORM\Table(
* name="server",
* indexes={
* #ORM\Index(name="fk_server_server_type_idx", columns={"server_type_id"}),
* #ORM\Index(name="fk_server_cluster_idx", columns={"cluster_id"})
* }
* )
* #ORM\Entity
*/
class Server
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=32, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*
* #Groups({"export"})
*/
protected $name;
/**
* #var EndpointServerConfig[]
*/
protected $endpointServerConfigs;
}
/**
* EndpointServerConfig
*
* #ORM\Table(name="endpoint_server_config", indexes={
* #ORM\Index(name="fk_endpoint_server_config_server_idx", columns={"server_name"})}
* )
* #ORM\Entity
*/
class EndpointServerConfig
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var Server
*
* #ORM\ManyToOne(targetEntity="Server")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="server_name", referencedColumnName="name")
* })
*
* #Groups({"export"})
*/
protected $server;
/**
* #var Endpoint
*
* #ORM\OneToOne(targetEntity="Endpoint", mappedBy="endpointServerConfig")
*/
protected $endpoint;
}
/**
* Endpoint
*
* #ORM\Table(
* name="endpoint",
* indexes={
* ...
* #ORM\Index(name="fk_endpoint_endpoint_server_config_idx", columns={"endpoint_server_config_id"}),
* ...
* }
* )
* #ORM\Entity
* ...
*/
class Endpoint
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
}
Now I want to update an entity (e.g. Foo), that contains an Endpoint. Among other changes I want to remove the reference to the Server from the Endpoint's EndpointServerConfig. That means for the database: The endpoint_server_config.server needs to be set to NULL.
I load the Foo to a Zend\Form, disable the server and submit the changes. On the server side I unset the EndpointServerConfig#server over Foo:
/** #var Foo $myFoo */
if(! $myFoo->getEndpoint()->getEndpointServerConfig()->getServer() || ! $myFoo->getEndpoint()->getEndpointServerConfig()->getServer()->getName()) {
$myFoo->getEndpoint()->getEndpointServerConfig()->setServer(null);
}
$this->entityManager->persist($myFoo);
$this->entityManager->flush($myFoo);
It leads to an error:
An exception occurred while executing 'UPDATE server SET name = ? WHERE name = ?' with params ["", "someservername"]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`mydb`.`endpoint_server_config`, CONSTRAINT `fk_endpoint_server_config_server` FOREIGN KEY (`server_name`) REFERENCES `server` (`name`) ON DELETE NO ACTION ON UPDATE NO ACTION)
That means, Doctrine tries to UPDATE the Server, instead of just to remove the reference to it from the EndpointServerConfig. But why?
Only when I manually set endpoint_server_config.server_name to NULL (directly in the database), I can save the changes via form and Doctrine.
How to get it working?
EDIT
Just noticed, that I get the same problem on every update of the EndpointServerConfig. So not only on setServer(null), bu also when I try to set a new Server. In this case the attempts leads to the error:
An exception occurred while executing 'UPDATE server SET name = ? WHERE name = ?' with params ["newservername", "someservername"]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`mydb`.`endpoint_server_config`, CONSTRAINT `fk_endpoint_server_config_server` FOREIGN KEY (`server_name`) REFERENCES `server` (`name`) ON DELETE NO ACTION ON UPDATE NO ACTION)
Add following:-
cascade={"persist", "remove"}
on your relation.
#ORM\ManyToOne(targetEntity="Server", cascade={"persist", "remove"})

Doctrine2, DQL, association not initialized

is here some doctrine expert, who can explain me, why these DQLs will not initialize tallyRevs field on Tally entity? I supposed, that when I fetch TallyRevs (owner side) and fetchJoin Tally entity to them, that field tallyRevs will be initialized. What am I doing wrong? I need to select TallyRev based on some criteria via DQL and since it is a bi-directional association, I would like it to be initialized from the other (Tally.tallyRevs) side also.
Screen of dump
<?php
/**
* #ORM\Entity
* #ORM\Table(name="v3_overview_calloff_tally")
*/
class Tally
{
/**
* #var int
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var TallyRev[]|Collection
* #ORM\OneToMany(targetEntity="STI\Model\Entity\V3\Overview\CallOff\TallyRev", mappedBy="tally")
*/
private $tallyRevs;
}
/**
* #ORM\Entity
* #ORM\Table(name="v3_overview_calloff_tallyrev")
*/
class TallyRev
{
/**
* #var int
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
* #ORM\Column(type="integer", nullable=false)
*/
private $revision;
/**
* #var Tally
* #ORM\ManyToOne(targetEntity="STI\Model\Entity\V3\Overview\CallOff\Tally", inversedBy="tallyRevs")
* #ORM\JoinColumn(name="tally_id", referencedColumnName="id", nullable=false)
*/
private $tally;
}
Here is some repository code:
$qb = $repository->createQueryBuilder();
$qb
->select('tallyRev')
->from(TallyRev::class, 'tallyRev', 'tallyRev.id')
// complicated filtering, this is just an example
->andWhere($qb->expr()->in('tallyRev.revision', ':rev'))
->setParameter('rev', $rev)
;
$tallyRevs = $qb->getQuery()->getResult();
$ids = array_keys($tallyRevs);
$qb2 = $repository->createQueryBuilder();
$qb2
->select('partial tallyRev.{id}')
->from(TallyRev::class, 'tallyRev', 'tallyRev.id')
->andWhere($qb2->expr()->in('tallyRev.id', ':ids'))
->setParameter('ids', $ids)
->leftJoin('tallyRev.tally', 'tally')
->addSelect('tally')
;
$qb2->getQuery()->getResult();
I know, that I can write DQL from the Tally side like this:
$qb
->select('tally')
->from(Tally::class, 'tally', 'tally.id')
->leftJoin('tally.tallyRev', 'tallyRev')
->addSelect('tallyRev')
->andWhere($qb->expr()->in('tallyRev.revision', ':rev'))
->setParameter('rev', $revs)
;
If you want to fetch join tally when you fetch tallyRev you should write something like this in the first qb, and delete qb2
->select(['tallyRev', 'tally'])
->from(TallyRev::class, 'tallyRev', 'tallyRev.id')
->join('tallyRev.tally', 'tally')
// complicated filtering, this is just an example
->andWhere($qb->expr()->in('tallyRev.revision', ':rev'))
->setParameter('rev', $rev)
;

Symfony2 Form with Doctrine Relationship Persistence Issue

So I have 3 entities with their properties.
A USER which has MANY USERSKILLS with each ONE having a single corresponding SKILL
Here are the entities:
/**
* #ORM\Table(name="skills")
* #ORM\Entity()
*/
class Skill
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=30, unique=true)
*/
private $name;
/**
* #ORM\Column(name="active", type="boolean")
* #var bool
*/
private $active = false;
/**
* #ORM\OneToMany(targetEntity="UserSkill", mappedBy="skill")
*/
private $userSkills;
}
/**
* #ORM\Table(name="user_skill")
* #ORM\Entity()
*/
class UserSkill
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="User", inversedBy="skills")
* #var User
*/
private $user;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Skill", inversedBy="userSkills")
* #var Skill
*/
private $skill;
/**
* #ORM\Column(type="integer")
* #var int
*/
private $level = 0;
}
/**
* StartupDriven\UserBundle\Entity\User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="StartupDriven\UserBundle\Entity\UserRepository")
*/
class User implements AdvancedUserInterface, \Serializable
{
/**
* #ORM\OneToMany(targetEntity="UserSkill", mappedBy="user")
* #var ArrayCollection
*/
private $skills;
}
They are created using 2 symfony form objects which works fantastically.
The problem is when I go to persist these objects in the controller.... I get an error
$form->handleRequest($request);
if ($form->isValid()) {
/**
* #var User $user
*/
$user = $form->getData();
/**
* #var UserSkill $userSkill
*/
foreach ($user->getSkills() as $userSkill) {
// No updating skills... Only new ones.
if (!$userSkill->getId()) {
// Check skill name match.
if ($matched_skill = $em->getRepository('StartupDrivenUserBundle:Skill')->findOneBy(array('name' => $userSkill->getName()))) {
$userSkill->setSkill($matched_skill);
}
else {
// No match. Create new generic skill.
$em->persist($userSkill->getSkill());
// THE ERROR HAPPENS ON THE FOLLOWING LINE!
$em->flush();
}
// Set the User
$userSkill->setUser($user);
// Persist the user skill.
$em->persist($userSkill);
$em->flush();
}
}
$em->persist($user);
$em->flush();
Error Message:
A new entity was found through the relationship 'StartupDriven\UserBundle\Entity\User#skills' that was not configured to cascade persist operations for entity: StartupDriven\UserBundle\Entity\UserSkill#0000000053e8628e00007f7f2fd56e1f. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'StartupDriven\UserBundle\Entity\UserSkill#__toString()' to get a clue.
I have tried every combination of persist & flush that I can think of. I have tried the cascade option above (which gives a different error that the "user id which is required by the primary key rules is not set")... I am completely lost. It seems like such a simple relationship... Where am I going wrong?

OneToMany invalid Mapping

i am trying to create a oneToMany relationship. Since Doctrine only offers ManyToOne Unidirectional im using that. Somehow the validation of the mapping fails and I am not able to spot my mistake:
Validation Error:
[Mapping] FAIL - The entity-class 'Strego\TippBundle\Entity\BetRound'
mapping is invalid:
* The association Strego\TippBundle\Entity\BetRound#userStatus refers to the owning side field
Strego\TippBundle\Entity\UserBetRoundStatus#betRound which does not
exist.
My First Entity (BetRound):
<?php
namespace Strego\TippBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection as Collection;
use Strego\AppBundle\Entity\Base as BaseEntity;
/**
* Strego\TippBundle\Entity\BetRound
*
* #ORM\Table()
* #ORM\Entity
*/
class BetRound extends BaseEntity {
//......
/**
*
* #var Collection
* #ORM\OneToMany(targetEntity="UserBetRoundStatus", mappedBy="betRound", cascade={"all"})
*/
protected $userStatus;
}
My related Entity(UserBetRoundStatus)
<?php
namespace Strego\TippBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Strego\AppBundle\Entity\Base as BaseEntity;
/**
* Strego\TippBundle\Entity\Game
*
* #ORM\Table
* #ORM\Entity
* #UniqueEntity(fields={"user", "betRound"}, message="Unique Entity Validator Fails for UserStatus", groups="unique")
*
*/
class UserBetRoundStatus extends BaseEntity {
// .....
/*
* #var BetRound
* #ORM\ManyToOne(targetEntity="BetRound", inversedBy="userStatus")
* #ORM\JoinColumn(name="betround_id", referencedColumnName="id", nullable=false)
* #Assert\NotNull()
*/
protected $betRound;
}
I have found the issue:
/** <--------- you need two *
* #var BetRound
* #ORM\ManyToOne(targetEntity="BetRound", inversedBy="userStatus")
* #ORM\JoinColumn(name="betround_id", referencedColumnName="id", nullable=false)
* #Assert\NotNull()
*/
protected $betRound;