Here's what I'm having trouble with.
I've a Table which contains a column called shown_on_homepage and only one row should be set to 1, the rest should all be set to 0. I'm trying to add a new row to the database and this one should be set to 1, setting the one that previously had a 1 to 0.
In MySQL I know this can be achieved by issuing an update before the insert:
UPDATE table_name SET shown_on_homepage = 0
Here's my Entity:
class FeaturedPerson {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="content", type="string", length=2500, nullable=false)
*/
private $content;
/**
* #var \DateTime
*
* #ORM\Column(name="date_updated", type="datetime")
*/
private $dateUpdated;
/**
* #var bool
*
* #ORM\Column(name="shown_on_homepage", type="boolean", nullable=false)
*/
private $isShownOnHomepage;
//...
public function getIsShownOnHomepage() {
return $this->isShownOnHomepage;
}
public function setIsShownOnHomepage($isShownOnHomepage) {
$this->isShownOnHomepage = $isShownOnHomepage;
return $this;
}
}
And for the Controller I've:
$featured = new FeaturedPerson();
$featured->setContent('Test content.');
$featured->setDateUpdated('01/02/2013.');
$featured->setIsShownOnHomepage(TRUE);
$em = $this->getDoctrine()->getManager();
$em->persist($featured);
$em->flush();
It does add the new row, but the one that had a shown_on_homepage set to 1 still has it. I've researched but I couldn't find a way to achieve this, I hope you can help me.
You could execute a query prior to your existing code in your controller:
$queryBuilder = $this->getDoctrine()->getRepository('YourBundleName:FeaturedPerson')->createQueryBuilder('qb');
$result = $queryBuilder->update('YourBundleName:FeaturedPerson', 'd')
->set('d.isShownOnHomepage', $queryBuilder->expr()->literal(0))
->where('d.isShownOnHomepage = :shown')
->setParameter('shown', 1)
->getQuery()
->execute();
Change 'YourBundleName' to your bundle name.
Related
I'm building a query that would be for creating a list of Posts that have a Project that is associated to the user, and within that structure hit the right criteria for "tierAccess."
My query builder:
$qb = $this->em->createQueryBuilder();
foreach($subs as $sub)
{
if($sub->getDisabled() == true)
{
continue;
}
$qb->select('p')
->from('App\Entity\ProjectPost', 'p')
->where('project = '.$sub->getProject()->getId())
->andwhere('p.Published = true')
->andwhere('p.TierAccess = '.$sub->getProjectTier()->getId())
->orderBy('p.PostTime', 'DESC');
$query = $qb->getQuery();
$object[] = $query->execute();
}
What I am aiming to do is add posts that the user subscription will allow for, and within that subscription making sure their access to this post is allowed (ie: tierAccess).
I then return the object variable to pass along to my Twig template file.
The error I'm receiving is:
[Semantical Error] line 0, col 45 near 'project = 3 AND': Error: 'project' is not defined.
My ProjectPost entity:
class ProjectPost
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $PostTitle;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $PostHero;
/**
* #ORM\Column(type="string", length=255, nullable=false)
*/
private $PostType;
/**
* #ORM\Column(type="text")
*/
private $PostBody;
/**
* #ORM\ManyToOne(targetEntity=Project::class, inversedBy="projectPosts")
* #ORM\JoinColumn(nullable=false)
*/
private $Project;
/**
* #ORM\Column(type="array", nullable=true)
*/
private $TierAccess = [];
/**
* #ORM\Column(type="datetimetz", nullable=true)
*/
private $PostTime;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="projectPosts")
* #ORM\JoinColumn(nullable=true)
*/
private $PostBy;
/**
* #ORM\Column(type="array", nullable=true)
*/
private $PostCategories = [];
/**
* #ORM\Column(type="boolean")
*/
private $Published;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $PostCover;
/**
* #ORM\Column(type="boolean")
*/
private $PostSupporter = 0;
}
The basic mistake is this one:
->where('p.Project = '.$sub->getProject()->getId())
Notice that you declare p to be the alias of Post, and then you don't use it. And even if you define the property as Project, you were trying to use it as project.
Nevertheless, the whole thing is rather suspect. Executing a query within a loop usually points to something wrong with the design.
A simpler approach, using WHERE IN instead of a loop and multiple selects:
// get the "subs" ids in an array:
$subsIds = array_map(fn($s) => $s->getProject()->getId(), $subs);
qb->select('p')
->from('App\Entity\ProjectPost', 'p')
->where('p.Project IN :subsIds')
->andwhere('p.Published = true')
->andwhere('p.TierAccess = '.$sub->getProjectTier()->getId())
->orderBy('p.PostTime', 'DESC')
->setParameter('subsIds', $subsIds)
;
$result = $qb->getQuery()->getResult;
I use Symfony 2.8. I have two table and in both the primary key is composed by 3 columns:
id, tipo_corso, comune
02, it, devi
01, en, capi
09, es, file
Obviously the two table have other different columns. I can't change the primary key by use only one or two columns. For one record in StranieriCRS table there are many record in EsoneroLingua table (OneToMany):
First entity:
class StranieriCRS
{
/**
* #ORM\Column(type="string")
* #ORM\Id
*/
private $id;
/**
* #ORM\Column(type="string")
* #ORM\Id
*/
private $tipo_corso;
/**
* #ORM\Column(type="string")
* #ORM\Id
*/
private $comune;
public function __construct($id, $tipo_corso, $comune)
{
$this->id = $id;
$this->tipo_corso = $tipo_corso;
$this->comune = $comune;
$this->esonerolingua = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #ORM\OneToMany(targetEntity="EsoneroLingua", mappedBy="stranieriCRS", fetch="EAGER")
*/
private $esonerolingua;
/**
* Get esonerolingua
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEsonerolingua()
{
return $this->esonerolingua;
}
Second entity:
class EsoneroLingua
{
/**
* #ORM\Column(type="string")
* #ORM\Id
*/
private $id;
/**
* #ORM\Column(type="string")
* #ORM\Id
*/
private $tipo_corso;
/**
* #ORM\Column(type="string")
* #ORM\Id
*/
private $comune;
public function __construct($id, $tipo_corso, $comune)
{
$this->id = $id;
$this->tipo_corso = $tipo_corso;
$this->comune = $comune;
}
/**
* #ORM\ManyToOne(targetEntity="StranieriCRS", inversedBy="esonerolingua")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="id", referencedColumnName="id"),
* #ORM\JoinColumn(name="tipo_corso", referencedColumnName="tipo_corso"),
* #ORM\JoinColumn(name="comune", referencedColumnName="comune"),
* )
*/
private $stranieriCRS;
The problem occur when I want get the StranieriCRS object because he give me as result only one result...seems like a OneToOne relation.
My Controller:
$sql = $entityManager->createQuery("
SELECT c
FROM AppBundle:EsoneroLingua c
WHERE c.id = '1546871' and c.tipo_corso = 'C' and c.comune = '7868'
");
$test = $sql->getResult();
In $test I was expect N record of EsoneroLingua with the same record StranieriCRS but I get only one EsoneroLingua with the correct StranieriCRS object. Seems work like OneToOne relation...why? Plus if I made dump($sql->getSql()); I obtain the raw sql...I try to use it directly in my db and he give me the right result. Is it a Doctrine bug?
To make a bidirectionnal One-To-Many, specify the JoinColumns only in the Many-To-One side.
So, in StranieriCRS, remove the following lines :
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="id", referencedColumnName="id"),
* #ORM\JoinColumn(name="tipo_corso", referencedColumnName="tipo_corso"),
* #ORM\JoinColumn(name="comune", referencedColumnName="comune"),
* )
And just let Doctrine guess the columns with the inversedBy and mappedBy attributes.
For more information on the mappings, see this page.
I am facing an issue with UniqueEntity validation.
I have a field "internal_asset_number" which should be unique and it's working fine on create. On update when i edit the existing current data with the same values, it shows "There is already an asset with that internal number!" but it shouldn't because it's the same entry.
The entity:
/**
* Asset
*
* #ORM\Table(schema="assets", name="asset", uniqueConstraints= {#ORM\UniqueConstraint(name="uk_asset_internal_asset_number_client_id", columns={"internal_asset_number", "client_id"})})
* #ORM\Entity(repositoryClass="Api\AssetBundle\Entity\AssetRepository")
* #UniqueEntity(fields={"internalAssetNumber"}, groups={"post", "put"}, message="There is already an asset with that internal number!")
*/
class Asset
{
/**
* #var guid
*
* #ORM\Column(name="id", type="string")
* #ORM\Id
* #ORM\GeneratedValue(strategy="UUID")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="client_id", type="string", length=255, nullable=false)
*/
private $clientId;
/**
* #var string
*
* #ORM\Column(name="internal_asset_number", type="string", length=255, nullable=true, unique=true)
*/
private $internalAssetNumber;
Update method:
public function putAssetAction(Request $request, $id)
{
$data = $this->deserializer('Api\AssetBundle\Entity\Asset', $request, 'put');
if ($data instanceof \Exception) {
return View::create(['error' => $data->getMessage()], 400);
}
$validator = $this->get('validator');
$errors = $validator->validate($data, null, 'put');
if (count($errors) > 0) {
$errorsResponse = [];
foreach ($errors as $error) {
$errorsResponse = $error->getMessage();
}
return View::create(array('error' => $errorsResponse), 400);
}
...
As #xabbuh commented, the problem is that the entity you persist after update is not retrieved through the entityManager so when you persist it the entity manager thinks it is a new entity.
Here is how to solve it:
$entityManager->merge($entity);
This will tell the entitymanager to merge your serialized entity with the managed one
Some more explanation on merge():
https://stackoverflow.com/a/15838232/5758328
Is there a possibility to read all available Values from an entity?
E.G.
class Properties
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="UserID", type="string", length=255)
*/
private $userID;
/**
* #var string
*
* #ORM\Column(name="Sport", type="string", length=1)
*/
private $sport;
.
.
.
So that I will get the name of the Value like: Id, UserID, Sport?
You can read the info you need thru the Doctrine metadata info as follow:
$doctrine = $this->getContainer()->get("doctrine");
$em = $doctrine->getManager();
$className = "Acme\DemoBundle\Entity\Properties";
$metadata = $em->getClassMetadata($className);
$nameMetadata = $metadata->fieldMappings['sport'];
echo $nameMetadata['type']; //print "string"
echo $nameMetadata['length']; // print "1"
// OR query for all fields
// Returns an array with all the identifier column names.
$metadata->getIdentifierColumnNames();
More info on the API DOC
Hope this help
You can make use of ReflectionClass::getProperties() to loop through all properties.
http://php.net/manual/en/reflectionclass.getproperties.php
This question already has answers here:
Doctrine2 ORM does not save changes to a DateTime field
(3 answers)
Closed 8 years ago.
I think I have found a bug which I can not find solution ..
I try to update the datetime field, but do not update it, don't gives me an error.
Move all other fields modifies them correctly, but the datetime field no.
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('MyOwnBundle:Events')->find($id);
$In = $entity->getDateIn();
$In->modify('+1 day');
$entity->setDateIn($In);
$em->flush();
I also tried to insert a DateTime() object directly but does not update at all!
$entity->setDateIn(new \DateTime());
Is there a solution to this problem?
I installed symfony 2.1 and doctrine 2.3.3
EDIT
Event entity:
/**
* Events
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="My\OwnBundle\Entity\EventsRepository")
*/
class Events
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="description", type="text")
*/
private $description;
/**
* #var \DateTime
*
* #ORM\Column(name="dateIn", type="datetime")
*/
private $dateIn;
/**
* #var \DateTime
*
* #ORM\Column(name="dateOut", type="datetime")
*/
private $dateOut;
....
/**
* Set dateIn
*
* #param \DateTime $dateIn
* #return Events
*/
public function setDateIn($dateIn)
{
$this->dateIn = $dateIn;
return $this;
}
/**
* Get dateIn
*
* #return \DateTime
*/
public function getDateIn()
{
return $this->dateIn;
}
/**
* Set dateOut
*
* #param \DateTime $dateOut
* #return Events
*/
public function setDateOut($dateOut)
{
$this->dateOut = $dateOut;
return $this;
}
/**
* Get dateOut
*
* #return \DateTime
*/
public function getDateOut()
{
return $this->dateOut;
}
....
The modify() method will not update the entity since Doctrine tracks DateTime objects by reference. You need to clone your existing DateTime object, giving it a new reference. Modify the new one and then set is as a new timestamp.
For more information, see the article in the Doctrine Documentation.
the entity is right, but you need to persist your entity with $em->persist($entity) and you don't need to set again the date because the datetime is passed by reference
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('MyOwnBundle:Events')->find($id);
$entity->getDateIn()->modify('+1 day');
$em->persist($entity);
$em->flush();