I would like to summate or add one up while I update an existing db entry.
For the Reason that I will have to work with MagicCalls, I just wonder how I can handle this.
In raw sql, I would do it like:
UPDATE table SET value= value + 1 WHERE ....
But in this case, I have absolutely no idea how to work it out.
My code looks like:
Entity:
class Properties
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Sport", type="string", length=11, nullable=true)
*/
private $sport;
/**
* #var string
*
* #ORM\Column(name="Entertainment", type="string", length=11, nullable=true)
*/
private $entertainment;
/**
* #var string
*
* #ORM\Column(name="Wellness", type="string", length=11, nullable=true)
*/
private $wellness;
Now, I get those column names by
$metadata = $em->getClassMetadata($className);
$columnNames=$metadata->getColumnNames();
I recieve an array, which I can foreach and add values to each of them which I will have to write back by using an accessor:
$properties= new Properties();
$accessor = PropertyAccess::createPropertyAccessorBuilder()
->enableMagicCall()
->getPropertyAccessor();
foreach($columnNames as $merkmale) {
$accessor->setValue($properties, $merkmale, 1);
}
So how can I handle an update by counting one up ? I missed something I guess
Why don't you use Lifecycle callbacks? This way you can choose doctrine event which suits your case best and increment all values you need in one method.
/**
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks()
*/
class Properties
{
/**
* #var string
*
* #ORM\Column(name="Sport", type="string", length=11, nullable=true)
*/
private $sport;
/**
* #var string
*
* #ORM\Column(name="Entertainment", type="string", length=11, nullable=true)
*/
private $entertainment;
/**
* #var string
*
* #ORM\Column(name="Wellness", type="string", length=11, nullable=true)
*/
private $wellness;
/**
* #ORM\PrePersist
*/
public function incrementValues()
{
$this->entertainment = 1; //you don't need any magic any more
$this->wellness = $this->wellness + 5; //you can access your entity values directly
}
}
All you need to do is annotate your entity with #ORM\HasLifecycleCallbacks() and add method which you also need to annotate with given event, like #ORM\PrePersist and this method will be called by doctrine each time this event occurs
Related
RoundMatch.php
/**
* #ORM\Entity(repositoryClass="MyApp\MyBundle\Repository\RoundMatchRepository")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"team_round_match" = "TeamRoundMatch", "player_round_match" = "PlayerRoundMatch"})
* #ORM\Table("my_round_match")
*/
abstract class RoundMatch
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="match_date", type="datetime")
*/
private $matchDate;
How can I join related entities to discriminated entities?
I cannot get direct access to discriminated table columns to create joins.
I cannot get access to discriminated table columns to create joins.
How can I join children entities to discriminator entities?
I created joins like this:
RoundMatchRepository.php
public function getMatchesWithNoResultsSubmitted()
{
$qb = $this->createQueryBuilder("rm");
$qb->leftJoin("rm.round", "rnd" )
->leftJoin("rnd.group", "sg")
->leftJoin("sg.server", "ss")
->leftJoin("ss.stage", "ts")
->leftJoin("ts.tournament", "t")
->leftJoin("MyAppMyBundle:PlayerRoundMatch", "prm", "WITH", "rm.id = prm.id")
->leftJoin("prm.player1", "p1")
->leftJoin("prm.player2", "p2")
->leftJoin('p1.gameProfiles',"gp1")
->leftJoin('p2.gameProfiles',"gp2")
->leftJoin('p1.gameProfiles', 'gp1', "WITH", $qb->expr()->andX(
$qb->expr()->eq('t.game', 'gp1.game'),
$qb->expr()->eq('prm.player1', 'gp1.player')
))
->leftJoin('p1.gameProfiles', 'gp2', "WITH", $qb->expr()->andX(
$qb->expr()->eq('t.game', 'gp2.game'),
$qb->expr()->eq('prm.player2', 'gp2.player')
));
return $qb->getQuery()->getResult();
}
I want to use result object in a twig and I cannot get joined entities in returned object because they are not joined via object relation.
I don't have object relation created because they are joined one to one via discriminator.
I have achieved dynamic relationships using Single Table Inheritance. This will allow you to write DQL against the relation or against the discriminating class.
You CANNOT "query" the discriminator using DQL. You must INSTANCE OF the entity name, see possible duplicate as per #LBA's comment
In this resulting schema, group_id will mean a different relation depending on the discriminator.
Obviously, this has performance implications on the database, though.
/**
* #ORM\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="type", type="string", length=255)
* #ORM\DiscriminatorMap(
* {"parents" = "Parents", "children" = "Child"}
* )
* #ORM\Table("people")
*/
class Person
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var mixed
*/
private $group;
}
/*
* #ORM\Table("parents")
*/
class Parent extends Person
{
/**
* Many parents have one group.
*
* #ManyToOne(targetEntity="ParentGroups", inversedBy="parents")
* #JoinColumn(name="group_id", referencedColumnName="id")
*/
private $group;
}
/*
* #ORM\Table("children")
*/
class Child extends Person
{
/**
* Many children have one group.
*
* #ManyToOne(targetEntity="ChildGroups", inversedBy="children")
* #JoinColumn(name="group_id", referencedColumnName="id")
*/
private $group;
}
/*
* #ORM\Table("parent_groups")
*/
class ParentGroups
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* One group has many parents.
*
* #OneToMany(targetEntity="Parent", mappedBy="group")
*/
private $parents;
public function __construct() {
$this->parents = new ArrayCollection();
}
}
/*
* #ORM\Table("child_groups")
*/
class ChildGroups
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* One group has many parents.
*
* #OneToMany(targetEntity="Child", mappedBy="group")
*/
private $children;
public function __construct() {
$this->children = new ArrayCollection();
}
}
Effectively the extending tables can override the annotations (if any) of the parent.
It work's a dream and we have multiple uses of this on our monolith :)
Untested code, but it should give you an idea of how I achieved it. If you struggle from here I'll go and make sure it runs.
I am using Doctrine 2.4 and I want to split the table one of my entity is using into several tables to improve querying that table - Horizontal partitioning, if I am not mistaken. The table has a lot of data (> 20 Mio. rows) and queries are always done on a subset (Component.Type).
Here are my entities:
Station:
/**
* #ORM\Id
* #ORM\Column(type="bigint")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
Component:
/**
* #ORM\Id
* #ORM\Column(type="bigint")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $type;
Data
/**
* #ORM\Id
* #ORM\Column(type="bigint")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="datetime")
*/
private $datetime;
/**
* #ORM\Column(type="float", nullable=true)
*/
private $value;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Station")
* #ORM\JoinColumn(name="station_id", referencedColumnName="id")
*
* #var Station $station
*/
private $station;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Component")
* #ORM\JoinColumn(name="component_id", referencedColumnName="id")
*
* #var Component $component
*/
private $component;
At the moment I solved this manually by having one Entity Data[TYPE] for every Component.Type (e.g. DataPollutionNo). All entities Data[TYPE] extent a MappedSuperclass (Data). To query for data, I first get the corresponding Data Entity from the Component.Type and query that Repository (DataPollutionNoRepository). This works out fine but I was wondering if there is a more sophisticated/generic approach to solve this.
Thanks, Hannes
I have an API developed in Symfony2 but when i send a request to it the response returns with 204Mb for only 40 rows... This is the code:
$em = $this->getDoctrine()->getManager();
$themes = $em->getRepository("KlickpagesAdminBundle:Theme")->findAll();
return $themes;
Im use FOSRestBundle to serialize and returns the json.
How i can resolve this?
Aa #Cerad said it is very like because of relations to other entities and lazy loading going in circles
For a quick test exclude all fields from the serilazition, except few scalar ones like so:
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer\Annotation\ExclusionPolicy;
/**
* Group
*
* #ExclusionPolicy("all")
*/
class Group implements GroupInterface
{
/**
* #Expose
* #var integer
*/
private $id;
/**
* #Expose
* #var string
*/
private $title;
/**
* Relation to privilegesis not explicitly exposed.
* #var Privilege[]
*/
private $privileges;
/**
* Relation to Users not explicitly exposed.
* #var User[]
*/
private $users;
...
The important parts are exclusionStrategy and expose antations.
If this will help, you got for sure a circles serialization of your annotations and the right solution is to define serialization groups, lets say like this:
/**
* #Expose
* #Groups({"groupDetail", "userAuthenticate"})
*
* #var Privilege[]
*/
private $privileges;
/**
* #Expose
* #Groups({"groupDetail"})
*
* #var User[]|ArrayCollection
*/
private $users;
You can then define by which group should be the response serialized on your controller or programatically.
// controllerAction
/*
* #Annotations\View(serializerGroups={"Default","groupDetail"})
*/
public function getGroupAction($groupId) { ... }
// programatically
...
/** #var $context SerializationContext */
$context = SerializationContext::create();
$serializationGroups = ['Default', 'GroupDetail'];
$context->setGroups($serializationGroups);
$view = $this->view($collection, 200);
$view->setSerializationContext($context);
return $this->handleView($view);
...
Resources: http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies
Every quartal (each 3-month) i need into table "report" add new "column" - for example "Y2014Q1" where Y=year and Q=quartal (1,2,3,4). After creating I need to make mapping of this new column in to object.
Part of my code is:
namespace backend\backendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* FactSheetData
*
* #ORM\Table(name="report")
* #ORM\Entity
*/
class ReportData
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Y2016Q3", type="string")
*/
private $Y2016Q3;
/**
* #param string $Y2016Q3
*/
public function setY2016Q3($Y2016Q3)
{
$this->Y2016Q3 = $Y2016Q3;
}
/**
* #return string
*/
public function getY2016Q4()
{
return $this->Y2016Q4;
}
....
I need to do something like this when new period comes:
class ReportData {
public function __construct() {
// if new perriod alter table
if (test_new_perriod) {
$new_period='Y2016Q4';
$sql="ALTER TABLE `report` ADD COLUMN `".$new_period."` VARCHAR(50) NULL DEFAULT NULL;";
$stmt = $this->getEntityManager()->getConnection()->prepare($sql);
$stmt->execute();
//and now - this is problem how to do - dynamic maping
/**
* #var string
*
* #ORM\Column(name="$new_period", type="string")
*/
private $new_period;
/**
* #param string $new_period
*/
public function set$new_period($new_period)
{
$this->$new_period =$new_period;
}
/**
* #return string
*/
public function get$new_period()
{
return $this->$new_period;
}
}
}
Hope I describe clear... Thanx for any advice.
I'm having issues setting up my Doctrine request properly.
I have two tables (PROPRIETE and PHOTO), one PROPRIETE can have many PHOTO
Therefore, I'd like to make a SELECT that will return an array of PROPRIETE where which one includes an array of it's own PHOTOs (not sure if I'm clear though...)
This is what my Popriete class looks like
class Propriete
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="libelle", type="string", length=255)
*/
private $libelle;
/**
* #ORM\ManyToOne(targetEntity="VillaPrivee\UserBundle\Entity\User")
* #ORM\JoinColumn(onDelete="CASCADE")
*/
private $proprietaire;
/**
* #ORM\OneToMany(targetEntity="VillaPrivee\MainBundle\Entity\Photo", mappedBy="propriete")
*/
private $photo;
And then the Photo class
class Photo
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="path", type="string", length=255)
*/
private $path;
/**
* #ORM\ManyToOne(targetEntity="VillaPrivee\MainBundle\Entity\Propriete")
* #ORM\JoinColumn(onDelete="CASCADE")
*/
private $propriete;
And finally, my Doctrine request (that successfully returns a list of Propriete, but nothing about their photos)
public function getProprietesByCriteria($ville, $rooms) {
$qb = $this->createQueryBuilder('p');
$qb->where('p.commune = :ville AND p.nbChambres >= :rooms')
->setParameter('ville', $ville)
->setParameter('rooms', $rooms);
return $qb->getQuery()->getResult();
}
I've tried with a leftJoin, but it seems that I don't know how to use that stuff...
Thanks guys for your help
I thing you're mixing different concepts in your code. Using Doctrine you should forget about trying to get multiple arrays with a query.
You only need to invoke the getPhoto() method on any propriete object.
So, you can use a code similar to:
$props = $this->getProprietesByCriteria($ville, $rooms);
foreach($props as $prop)
{
$prop->getPhoto(); // <--will return an array of the `PHOTO` related to this `PROPIETE`
}