In my database I have an entity named Graphique. This the schema for:
class Graphique
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var decimal
*
* #ORM\Column(name="index", type="decimal", precision=9, scale=3, nullable=false)
*/
private $index;
/**
* #var datetime
*
* #ORM\Column(name="date", type="datetime", nullable=false)
*/
private $date;
/*getters and setters*/
This is some values for index, according to my database schema (example):
----------------------------------
id | index | dateTime |
----------------------------------
1 | 1700.000 | dateTime datas|
----------------------------------
2 | 1200.000 | dateTime datas|
----------------------------------
3 | 1200.000 | dateTime datas|
----------------------------------
4 | 1304.000 | dateTime datas|
----------------------------------
etc...| etc... | etc... |
I have this method into a controller:
$em=$this->getDoctrine()->getManager();
$queryIndex = $em->createQuery( 'SELECT g.index
FROM MySpaceMyBundle:Graphique g');
$array = array_map('current', $queryIndex);
$response = new Response();
$data = json_encode($array);
$response->headers->set('Content-Type', 'application/json');
$response->setContent($data);
return $response;
it returns me this into my json response:
["1700.000","1200.000","1200.000","1304.000","1800.000","2012.000","2048.000","1048.000","3000.000","5421.000"]
but I need to have this simple array result (instead the json response I give you just above):
[1700.000,1200.000,1200.000,1304.000,1800.000,2012.000,2048.000,1048.000,3000.000,5421.000]
I need to return a simple array in my json response in order to have this decimal values for displaying them into a highchart graphic.
How can I proceed? I already try some Doctrine methods like ->getArrayresult(), ->getScalarResult(), ->toArray(), but the results are the same. I need to make my query result to a simple array.
json_encode($array, JSON_NUMERIC_CHECK);
This solution should help you.
Related
I've implement Class Table Inheritance using Doctrine 2 in my Symfony 3 project, so as to have one base profile table, that houses both employee and company profiles.
When trying to persist a sub class (EmployeeProfile) of the mapped super class (AbstractProfile), I get the following error:
An exception occurred while executing 'INSERT INTO profile (id) VALUES
(?)' with params [27, 10, 85, \"employee\"]:\n\nSQLSTATE[HY093]:
Invalid parameter number: number of bound variables does not match
number of tokens
I'm not entirely sure what's going wrong, and why Doctrine is generating a query that's entirely ignoring the AbstractProfile's properties. Initially I thought it was due to said properties not being visible to the children, but even after setting the properties to protected, the error remains.
How exactly can I fix this, or am I trying to fit a square peg into a round hole by not using this functionality for what is was intended?
profile DB Table:
+------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
| type | varchar(100) | NO | | NULL | |
| status | int(11) | NO | | NULL | |
| created_at | datetime | NO | | CURRENT_TIMESTAMP | |
| updated_at | datetime | NO | | CURRENT_TIMESTAMP | |
+------------+--------------+------+-----+-------------------+----------------+
AbstractProfile Super Class:
/**
* AbstractProfile
*
* #ORM\Table(name="profile")
* #ORM\Entity(repositoryClass="ProfileBundle\Repository\ProfileRepository")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({
* "employee" = "EmployeeProfile",
* "company" = "CompanyProfile"
* })
*/
abstract class AbstractProfile
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var int
*
* #ORM\Column(name="status", type="integer")
*/
protected $status;
/**
* #ORM\OneToOne(targetEntity="User", inversedBy="profile")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
//... Getters, setters and all the rest
}
EmployeeProfile Sub Entity:
<?php
/**
* EmployeeProfile
*
* #ORM\Table(name="profile")
* #ORM\Entity
*/
class EmployeeProfile extends AbstractProfile
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Skill", inversedBy="profiles")
* #ORM\JoinTable(name="profile_skills",
* joinColumns={#ORM\JoinColumn(name="profile_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="skill_id", referencedColumnName="id", unique=true)}
* )
*/
private $skills;
public function __construct()
{
$this->skills = new ArrayCollection();
}
//... Getters, setters and all the rest
}
CompanyProfile Sub Entity:
<?php
/**
* CompanyProfile
*
* #ORM\Table(name="profile")
* #ORM\Entity
*/
class CompanyProfile extends AbstractProfile
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Event", inversedBy="profiles")
* #ORM\JoinTable(name="profile_events",
* joinColumns={#ORM\JoinColumn(name="profile_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="event_id", referencedColumnName="id", unique=true)}
* )
*/
private $events;
public function __construct()
{
$this->events = new ArrayCollection();
}
//... Getters, setters and all the rest
}
It looks like you are trying to use #ORM\InheritanceType("JOINED") with a single table. You use #ORM\Table(name="profile") in your 3 entities.
The result is that Doctrine don't know what to do with your entities.
You could try replacing #ORM\InheritanceType("JOINED") by #ORM\InheritanceType("SINGLE_TABLE").
I have got two classes which are being associated using one to one uni-direction
{
id: 1,
name: "onetooneuniparent name",
onetooneunichild: {
id: 1,
name: "onetooneunichild name",
__initializer__: null,
__cloner__: null,
__isInitialized__: true
}
}
the above is the result when I do query like following
http://localhost:8000/onetooneRead?id=1
I want to know where and why the following come from
__initializer__: null,
__cloner__: null,
__isInitialized__: true
my expected result is just this
{
id: 1,
name: "onetooneuniparent name",
onetooneunichild: {
id: 1,
name: "onetooneunichild name"
}
}
OnetoOneUniParent.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="onetooneuniparent")
*/
class OnetoOneUniParent{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string",name="name")
*/
private $name;
/**
* #ORM\OneToOne(targetEntity="OnetoOneUniChild",cascade={"persist"})
* #ORM\JoinColumn(name="child_id", referencedColumnName="id")
*/
private $onetooneunichild;
<.... getter and setter here ...>
}
OnetoOneUniChild.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="onetooneunichild")
*/
class OnetoOneUniChild{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string",name="name")
*/
private $name;
<.... getter and setter here ...>
This is the method in controller
/**
* #Route("/onetooneRead")
* #Method("GET")
*/
public function onetooneReadAction(Request $request){
$logger = $this->get('logger');
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$logger->info('onetoone Read');
$id = $request->query->get("id");
$em = $this->getDoctrine()->getManager();
$onetooneuniparent = $em->getRepository('AppBundle:OnetoOneUniParent')->find($id);
$onetooneuniparentJson = $serializer->serialize($onetooneuniparent, 'json');
$response = new JsonResponse();
$response->setContent($onetooneuniparentJson);
return $response;
}
This is what is inside in MySQL
mysql> select * from onetooneuniparent;
+----+----------+------------------------+
| id | child_id | name |
+----+----------+------------------------+
| 1 | 1 | onetooneuniparent name |
| 2 | 2 | onetooneuniparent name |
| 3 | 3 | onetooneuniparent name |
+----+----------+------------------------+
3 rows in set (0.00 sec)
mysql> select * from onetooneunichild;
+----+-----------------------+
| id | name |
+----+-----------------------+
| 1 | onetooneunichild name |
| 2 | onetooneunichild name |
| 3 | onetooneunichild name |
+----+-----------------------+
3 rows in set (0.00 sec)
Those functions are part of the Doctrine proxy coding, since you are using Lazy Loading Doctrine needs to keep track of the child entity if it needs to be loaded or not. Part of that keeping track is these functions (I believe it is in this portion of Doctrine)
There may be a way around this which would be to avoid using lazy loading. To do that you can utilize EAGER loading if you always want the child to load with the parent. Alternatively if you only want to use EAGER for this one query and not every time you would have to switch to DQL as documented here or you could use the JOIN comma (second example down) here
I am using Doctrine2 ORM. I have an order table.
Name | Type | Attributes | Null | Default
--------------------------------------------------------------------------------
order_id | int | | No | None
date_created | timestamp | | No | CURRENT_TIMESTAMP
date_edited | timestamp | on update CURRENT_TIMESTAMP | No | CURRENT_TIMESTAMP
date_sent | timestamp | | No | 0000-00-00 00:00:00
date_cancelled | timestamp | | No | 0000-00-00 00:00:00
requested_ship_date | timestamp | | No | 0000-00-00 00:00:00
I have added the Timestampable Doctrine Extension to use for the date_created and date_edited fields like so:
/**
* #var \DateTime
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $date_created;
/**
* #var \DateTime
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(type="datetime")
*/
private $date_edited;
However, I'm not sure what to do for date_sent and date_cancelled. I want them both to default to 0000-00-00 00:00:00 instead of the current time. I saw this workaround for using timestamps in Doctrine2 without a plugin, but I don't want the default to be the current timestamp for these. The reason being, users can 'save' an order but not 'send' it to someone. Also, I obviously don't want the date_cancelled to be the current timestamp.
Note: I don't want to store nulls in the database, so please don't suggest that.
Thanks in advance.
Update
I currently have this for the three remaining fields in my Order entity.
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", options={"default":"0000-00-00 00:00:00"})
* #ORM\Version
*/
private $date_sent;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", options={"default":"0000-00-00 00:00:00"})
* #ORM\Version
*/
private $date_cancelled;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", options={"default":"0000-00-00 00:00:00"})
* #ORM\Version
*/
private $requested_ship_date;
For some reason, when I try to update the requested_ship_date field, it ends up being "0000-00-00 00:00:00". I leave the date_sent and date_cancelled fields null and they update to my local time, not UTC time. However, the date_created and date_edited fields will be updated to the current time in UTC time (how I want it).
Basically, when I'm saving an order it looks like the first row, but I want it to look like the second row (assuming the user requested a ship date of 2015-06-08).
order_id | date_created | date_edited | date_sent | date_cancelled | requested_ship_date
-----------------------------------------------------------------------------------------------------------------------
1 | 2015-06-05 12:00:00 | 2015-06-05 12:00:00 | 2015-06-05 07:00:00 | 2015-06-05 07:00:00 | 0000-00-00 00:00:00
1 | 2015-06-05 12:00:00 | 2015-06-05 12:00:00 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 | 2015-06-08 00:00:00
I have set the timezone in my index.php file like so date_default_timezone_set('Zulu');. I don't reset the timezone anywhere else.
Okay, I found a crazy workaround for this, but I honestly couldn't find a better solution. So, for anyone else stuck in the same mess I am, you're welcome lol.
First, the rules:
date_created = updated only on creation
date_edited = updated on every update
date_sent = updated when user clicks "submit" instead of "save"
date_cancelled = updated when user decides to cancel the order
requested_ship_date = required when creating a new order, this is the date the customer wants the order to be shipped by.
Some code from my Order entity.
/**
* #var \DateTime
*
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="create")
*/
private $date_created;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="update")
*/
private $date_edited;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", options={"default":"0000-00-00 00:00:00"})
*/
private $date_sent;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", options={"default":"0000-00-00 00:00:00"})
*/
private $date_cancelled;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="change", field="requested_ship_date")
*/
private $requested_ship_date;
/*
* Constructor
*/
public function __construct()
{
if (!$this->date_sent) $this->date_sent = new DateTime("0000-00-00 00:00:00", new DateTimeZone("Zulu"));
if (!$this->date_cancelled) $this->date_cancelled = new DateTime("0000-00-00 00:00:00", new DateTimeZone("Zulu"));
}
/**
* Updates time sent
*
* #return Order
*/
public function send()
{
$this->date_sent = new DateTime("now");
return $this;
}
/**
* Updates time cancelled
*
* #return Order
*/
public function cancel()
{
$this->date_cancelled = new DateTime("now");
return $this;
}
Explanation:
I did not change anything of how I set up my database columns in my order table. I tried using the #Gedmo\Timestampable plugin for my date_sent and date_cancelled fields, but couldn't get it to work. I noticed that the timezones were off, for some weird reason, so I manually set them in the constructor. It is important to not automatically set it, or you will override values previously set. For some reason unknown to me, I couldn't get the requested_ship_date field working without using the #Gedmo\Timestampable plugin. If I took it out, every set up I tried to use with Doctrines type="datetime" would just result in the column equaling 0000-00-00 00:00:00.
If anybody has any questions, let me know. I had to basically poke at things for awhile until I figured it out. The date_sent and date_cancelled fields worked correctly, and were in the right timezone when I updated them.
I have two tables (test and question) and the middle table (n-m). In this point all works fine.
But now, I need to put extra information in the (n-m) table, the order of this question in this test
I need this:
id | test_id | question_id | order
1 | 1 | 1 | 3
2 | 1 | 2 | 2
3 | 1 | 3 | 1
4 | 1 | 4 | 4
All these relationship have made with doctrine annotation...
Test Entity
/**
* #ORM\ManyToMany(targetEntity="Question", inversedBy="tests")
*/
private $questions;
Question Entity
/**
* #ORM\ManyToMany(targetEntity="Test", mappedBy="questions"))
*/
private $tests;
Any help will be appreciated
EDIT
Hi again!
Thanks a lot to #DonCallisto
my entities at the end:
Test
/**
* #ORM\OneToMany(targetEntity="RTestQuestion", mappedBy="question")
*/
private $questions;
Question
/**
* #ORM\OneToMany(targetEntity="RTestQuestion", mappedBy="test"))
*/
private $tests;
My new entity "RTestQuestion"
/**
* ET\BackendBundle\Entity\RTestQuestion
*
* #ORM\Table(name="rtest_question")
* #ORM\Entity
*/
class RTestQuestion {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Question", inversedBy="questions", cascade={"persist", "remove"})
*/
private $question;
/**
* #ORM\ManyToOne(targetEntity="Test", inversedBy="tests", cascade={"persist", "remove"})
*/
private $test;
/**
* #var integer $order
*
* #ORM\Column(name="question_order", type="integer", nullable=true)
*/
private $question_order;
I had to make two changes:
The properties need the cascade on persist and remove actions (doctrine console show errors without this)
And the word "order" are restricted for mysql, and now become a question_order.
And, again, thanks to #DonCallisto!
Split the relationship into a 1-n and m-1 as follows
Test Entity --- (1 - m) ---> RTestQuestion Entity <--- (m - 1) --- Question
So your code will be
Test Entity
/**
* #ORM\OneToMany(targetEntity="RTestQuestion", inversedBy="question")
*/
private $questions;
Question Entity
/**
* #ORM\OneToMany(targetEntity="RTestQuestion", mappedBy="test"))
*/
private $tests;
RTestQuestion Entity
/**
* #ORM\ManyToOne(targetEntity="Question", mappedBy="questions"))
*/
private $question;
/**
* #ORM\ManyToOne(targetEntity="Test", mappedBy="tests"))
*/
private $test;
/**
* EXTRA ATTRIBUTES HERE
*/
Remember that an association with extra fields isn't an association anymore but a new entity!
I would like to know if exist a way to add fields on the fly to any entity on Symfony2. I'm searching on the big internet and I didn't find anything. When I said "a way", I mean if exist a Doctrine Extension with that behavior, a bundle that implement it, design pattern, etc.
My idea is something similar to Translatable behavior of Doctrine Extensions. Supouse I have a Address entity, so I would like to add some attributes on the fly like street, number, intersections, and others but at the begining I didn't know what fields could exist.
I'm thinking something as 2 entities: Address and AddressFieldValues. Address will have specifics attributes like id, foreing keys of relationships with others classess and will be used to inject the dynamic attributes (a collections of field-values). AddressFieldValue will have the reals fields-values of Address, with the following attributes: id, address_id, field_name, field_value.
So, entity Address could be like this:
/**
* Address
*
* #ORM\Entity(repositoryClass="AddressRepository")
* #ORM\Table(name="address")
*/
class Address
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(
* targetEntity="AddressFieldValues",
* mappedBy="object",
* cascade={"persist", "remove"}
* )
*/
private $field_value;
public function __construct()
{
$this->field_value = new ArrayCollection();
}
public function getFieldValue()
{
return $this->field_value;
}
public function addFieldValue(AddressFieldValues $fv)
{
if (!$this->field_value->contains($fv)) {
$this->field_value[] = $fv;
$fv->setObject($this);
}
}
public function getId()
{
return $this->id;
}
}
and AddressFieldValues entity could be like this:
/**
* #ORM\Entity
* #ORM\Table(name="address_field_values",
* uniqueConstraints={#ORM\UniqueConstraint(name="lookup_unique_idx", columns={
* "object_id", "field"
* })}
* )
*/
class AddressFieldValues
{
/**
* #var integer $id
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue
*/
protected $id;
/**
* #var string $field
*
* #ORM\Column(type="string", length=32)
*/
protected $field;
/**
* #ORM\ManyToOne(targetEntity="Address", inversedBy="field_value")
* #ORM\JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $object;
/**
* #var string $content
*
* #ORM\Column(type="text", nullable=true)
*/
protected $content;
/**
* Convenient constructor
*
* #param string $field
* #param string $value
*/
public function __construct($field, $value)
{
$this->setField($field);
$this->setContent($value);
}
/**
* Get id
*
* #return integer $id
*/
public function getId()
{
return $this->id;
}
/**
* Set field
*
* #param string $field
*/
public function setField($field)
{
$this->field = $field;
return $this;
}
/**
* Get field
*
* #return string $field
*/
public function getField()
{
return $this->field;
}
/**
* Set object related
*
* #param string $object
*/
public function setObject($object)
{
$this->object = $object;
return $this;
}
/**
* Get related object
*
* #return object $object
*/
public function getObject()
{
return $this->object;
}
/**
* Set content
*
* #param string $content
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* #return string $content
*/
public function getContent()
{
return $this->content;
}
}
So, if I have the following values on table: address_field_values
id | object | field | content
1 | 1 | street | 1st Ave
2 | 1 | number | 12345
3 | 1 | intersections | 2sd Ave and 4th Ave
4 | 2 | street | 1st Ave
5 | 2 | number | 12347
6 | 2 | intersections | 2sd Ave and 4th Ave
7 | 3 | street | 1st Ave
8 | 3 | number | 12349
9 | 3 | intersections | 2sd Ave and 4th Ave
For now address table only have the following values:
| id |
| 1 |
| 2 |
| 3 |
I could like to inject those fields-values to a Address object on the fly, to do something like this:
// if I need get de Address with id = 2
$addressRepository = $em->getRepository('Address');
$address = $addressRepository->find(2);
sprintf('The address is: "%s", #"%s" between "%s".', $address->getStreet(), $address->getNumber(), $address->getIntersections());
// then it should show: The address is 1st Ave, #12347 between 2sd Ave and 4th Ave.
//
// or if I need add a new Address, do something like this:
$address = new Address();
$address->setStreet('1st Ave');
$address->setNumber('12351');
$address->setIntersections('2sd Ave and 4th Ave');
$em->persist($address);
$em->flush();
then it save the address and address_field_values, and the tables have the following values:
// address
| id |
| 1 |
| 2 |
| 3 |
| 4 |
// address_field_values
id | object | field | content
1 | 1 | street | 1st Ave
2 | 1 | number | 12345
3 | 1 | intersections | 2sd Ave and 4th Ave
4 | 2 | street | 1st Ave
5 | 2 | number | 12347
6 | 2 | intersections | 2sd Ave and 4th Ave
7 | 3 | street | 1st Ave
8 | 3 | number | 12349
9 | 3 | intersections | 2sd Ave and 4th Ave
10 | 4 | street | 1st Ave
11 | 4 | number | 12351
12 | 4 | intersections | 2sd Ave and 4th Ave
So, any ideas how can I do that?
Remember, I have as requirement in my bussiness logic that I didn't know what fields could have a Address at beginig so I need to inject the fields on the fly. I use Address as example but this behavior can be used for any entity.
Thanks in advance
I think that your request is similar to a collection in a form (Doctrine2 documentation).
In the documentation, a collection of Tags entities with name property) is linked to a Task entity. In your case, the entity AddressFieldValue will have the field and content properties and the collection of AddressFieldValue entities will be added to Address entity.
So, by using this documentation and replacing Task by Address and Tag by AddressFieldValue it should works.