As I was working on my Symfony2 project a strange bug savagely appeared (again).
I created an entity Check containing a dateCreated attribute and some others attributes so I can link Check to different entities that are extending a ProductBase. Here are samples of Check and a AProduct :
/**
* Check
*
* #ORM\Table(name="check")
* #ORM\Entity
*/
class Check
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="date_created", type="datetime")
*/
private $dateCreated;
[...]
/**
* #ORM\ManyToOne(targetEntity="Acme\BlogBundle\Entity\AProduct", inversedBy="checks")
* #ORM\JoinColumn(name="aproduct_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $aproduct;
[...]
}
/**
* AProduct
*
* #ORM\Table(name="aproduct")
* #ORM\Entity
*/
class AProduct extends ProductBase
{
[...]
/**
* #ORM\OneToMany(targetEntity="Acme\BlogBundle\Entity\Check", mappedBy="product")
* #ORM\OrderBy({"dateCreated" = "DESC"})
*/
protected $checks;
[...]
}
So my problem is that when I am trying to display the dateCreated attribute in one of my controller, see code below, Symfony2 (or Doctrine2) is adding exactly one month to the date stored in the database and I don't know why it's happening :
[...]
$aproduct = $aproducts[0];
$checks = $aproduct->getChecks();
$lastCheck = $checks->toArray()[0]; //I know it's not 'safe' but it's shorter to expose my problem
var_dump($lastCheck->getDateCreated());
Result :
object(DateTime)[854]
public 'date' => string '2014-01-20 16:21:41' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'UTC' (length=3)
Value stored in database :
2013-12-20 16:21:41
What I don't understand the most is that in another controller, with the exact same methods but on a different product (BProduct for instance), I get the correct date...
Has anyone already faced to this problem or have any clue of what to do to solve it?
Thank you again. If you need more information just ask and I will try to help as most as I can.
Edit : The others aproduct stored in aproducts are displaying the correct date...
I see you are using:
#ORM\OrderBy({"dateCreated" = "DESC"})
Might be silly but check the id of returned Check instance.
Well I finally found my problem and my post here was really silly and completely unrelated to Symfony or Doctrine, sorry about that.
I was performing some "tests" on the last instance of my aproduct checks before displaying them and those "tests" were affecting the dateCreated value.
Here is what I was doing :
public static function updateAProductStatus(AProduct $product){
if(($check = $product->getChecks()->first()) instanceof Check){
$date = $check->getDateCreated();
$expiracyDate = $date->add(new \DateInterval('P1M')); //this line is the problem
$status = self::getStatus($expiracyDate); //this is only returning 'expired', 'expiring' or 'good' based on the difference between today's date and dateCreated + 1 month
} else {
$status = 'expired';
}
return $status;
}
So, as written in the code, $date->add(new \DateInterval('P1M')); is changing the stored value of Checks's dateCreated attribute. I don't understand exactly why it's affecting it because I'm not working directly on the Check instance.
The quick way to solve it was to explicitly clone the DateTime instance before adding a DateInterval :
$date = clone $date;
But I will add a new field in my Check or AProduct entity to store the expiracy date instead of calculating it on every update.
Update:
I read that PHP passes objects and arrays as reference and not as value. That's why I was having a problem here. I didn't know PHP was acting like that. I will be more careful in the future then!
Related
Got this entity:
/**
* #ORM\Table(name="shop_payment_details")
* #ORM\Entity(repositoryClass="Acme\ShopBundle\Entity\PaymentRepository")
*/
class Payment extends ArrayObject
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*
* #var integer $id
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
**/
protected $user;
/**
* #ORM\ManyToOne(targetEntity="Acme\ShopBundle\Entity\Item")
* #ORM\JoinColumn(name="item_id", referencedColumnName="id")
**/
protected $item;
/**
* #ORM\Column(name="date", type="datetime", nullable=true)
*/
protected $date;
/**
* #ORM\Column(name="amount", type="float", nullable=true)
*/
protected $amount;
I need to file a sales table between two dates he selected.
The table must contain all days between two dates and reference codes of the objects in the store.
For example:
How can I get it? Can do it just with Doctrine or i must use PHP to build that table?
It is possible, what you need is the orX() function supplied by Doctrine-ORM
You will need to create two expressions using the function exp() then you can put both expressions in the orX() statement to get the wanted results.
For the expressions you need to define you will need the function gt()/lt() - greater than/ lower than
This will give you the possibility to compare two dates
For a further reference check this link:
https://doctrine-orm.readthedocs.org/en/latest/reference/query-builder.html#high-level-api-methods
PS:
For readabilty and logic it should be easier to create the expression before inserting them into your query:
$exp1 = $qb->expr()->gt('..', '?value');
$exp2 = $qb->expr()->gt('..', '?value2'),
...
$qb->where($qb->expr()->orX($exp1, $exp2));
Notice that orX can aggregate an unlimited number of expressions
Create a custom DQL (in a repository I suggest) to retrieve all payments where payment.date => yourSmallerUserDate and payment.date <= yourBiggerUserDate.
The result will be all payments between your two dates.
Within your logic you build a table with a row per day between your two dates. And whenever you have a date in your result matching your row date add it to your output.
I have a field in database (Time) with this value 09:00:00.
I created the Entity and with Time Field
/**
* #var \DateTime
*
* #ORM\Column(name="m_01_ch", type="time")
*/
private $m_01_ch;
In my controller I retrieve the element and when I do:
$val = $myentity->getM01Ch();
My value is (in XDebug)
$val = {DateTime}[3]
date= "2015-07-08 09:00:00.000000"
timezone_type = 3
timezone "Europe/Rome"
If I get $val->date I have All the Date, but I want to get only 09:00:00
Can I take my "original" value without use Regex etc?
You can modify your entity where you are returning your value. In your function getM01Ch() do something like this
/**
* #return \DateTime
*/
public function getM01Ch()
{
$returnValue = $this->m_01_ch->format('h:i:s')
return $returnValue
}
Other than that I don't know if any better approach exists. More info
I have a entity with several fields. Now I have added to my database a new column "date" that is a datetime object.
But when I add a new register to the database this field always have value null, never caught the value that I put in the form.
The entity have the correct values, but if I saw all the values, the entity manager has a variable called "SelectColumnListSQL", and in this SQL action, doesn't appear the field "date".
The logs doesn't write any error, only store in my database the rest of the fields ok but this not.
If hay use dev enviromnent, in this case all works right :S
Any idea??
--- Entity Info ---
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime", nullable=false)
*/
protected $date;
/**
* Set date
*
* #param \DateTime $date
* #return Quotes
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* #return \DateTime
*/
public function getDate()
{
return $this->date;
}
Thanks!
Please, concrete which ORM are you using (Doctrine, Propel...)
Have you already run the following commands?
php app/console doctrine:generate:entities
php app/console doctrine:schema:update
You must include the info in your Entity dir in your Bundle
I am pretty sure that you forget one setter method or the method is misspelled.
See the example below for more details.
Assume that you have this entity
class Entity{
// ...
private field;
// the getter and setter methods
public function getField(){
// ...
}
public function setField(){ // I guess this function is missing or misspelled
// ...
// If the function is missing or misspelled,
// doctrine will not take into account the changes you did for that field
}
}
best,
Check that you have totaly updated your database by this command:
php app/console doctrine:schema:update --dump-sql
I created a Doctrine2 Entity and would like to map a field to timestamp column in MySQL.
/**
* #ORM\Table(name="biz_order")
* #ORM\Entity(repositoryClass="Acme\OrderBundle\Repository\OrderRepository")
*/
class Order
{
/**
* #ORM\Column(name="order_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
// Lots of other fields ...
/**
* #ORM\Column(name="order_timestamp", type="datetime")
*/
private $createdOn;
}
With annotated type as "datetime" I get following error:
Doctrine\DBAL\Types\ConversionException: Could not convert database value "1390362851" to Doctrine Type datetime. Expected format: Y-m-d H:i:s
at n/a
in /var/www/packer/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php line 63
at Doctrine\DBAL\Types\ConversionException::conversionFailedFormat('1390362851', 'datetime', 'Y-m-d H:i:s')
in /var/www/packer/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php line 67
However in Doctrine 2.4 documentation I found following
datetime: Type that maps a SQL DATETIME/TIMESTAMP to a PHP DateTime object.
How can I map timestamp DB column to a PHP class field in Doctrine2?
EDIT:
So far my workaround is using the type="integer" in ORM mapping and returning it as ValueObject
public function getCreatedOn()
{
$createdOn = new \DateTime();
$createdOn->setTimestamp($this->createdOn);
return $createdOn;
}
You can just create a custom doctrine type defined timestamp, see the documentation
You can look at This post: datetime vs timestamp
Since it is a createdAt property, and represents a point in time, you might want to fetch objects that have been created before $createdAt or after $createdAt.
To do that, your best option is to store the datetime exactly the way you've done it but to associate a \Datetime object to that field: $this->createdAt = new \Datetime();
The best way for you would be to use lifecycle callbacks:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="biz_order")
* #ORM\Entity(repositoryClass="Acme\OrderBundle\Repository\OrderRepository")
* #ORM\HasLifecycleCallbacks
*/
class Order
{
/**
* #ORM\Column(name="order_timestamp", type="datetime")
*/
private $createdAt;
/**
* #ORM\PrePersist
*/
public function doStuffOnPrePersist()
{
$this->createdAt= new \DateTime();
}
}
When searching I came up with many results of people having similar problems but they were always related to association errors. I'm trying add a simple text field to a table in a database and, for the life of me, I can't figure out what's different about this time - when I've done it with no problems many times before.
I've added a 'record_checksum' field to 4 different entities, but I will use just one, here to simplify the example. (The same error happens for all 4).
Here is an example of my Entity\Cloud.php file, with the 'record_checksum' field added at the bottom:
use Doctrine\ORM\Mapping as ORM;
namespace Entity;
/**
* Entity\Cloud
*
* #orm:Table(name="cloud")
* #orm:Entity
* #orm:HasLifecycleCallbacks
*/
class Cloud
{
/**
* #var integer $id
*
* #orm:Column(name="id", type="integer", length="13")
* #orm:Id
* #orm:GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var float $position_x
*
* #orm:Column(name="position_x", type="float", length=9)
*/
private $position_x;
/**
* #var float $position_y
*
* #orm:Column(name="position_y", type="float", length=9)
*/
private $position_y;
/**
* #var string $commit_group
*
* #orm:Column(name="commit_group", type="string", length=32, nullable=true)
*/
private $commit_group;
/**
* #var string $commit_key
*
* #orm:Column(name="commit_key", type="string", length=13, nullable=true)
*/
private $commit_key;
/**
* #var string $record_checksum
*
* #orm:Column(name="record_checksum", type="string", length=32, nullable=true)
*/
private $record_checksum;
The rest of the class is getter/setter methods, so I will leave it out. To see the entire Entity file, I put it up on pastebin ( http://pastebin.com/9LheZ6A1 ). The 'commit_key' I'd just added a few weeks ago, with no problems.
Now I update the schema:
$ doctrine orm:schema-tool:update --dump-sql
ALTER TABLE cloud ADD record_checksum VARCHAR(32) DEFAULT NULL;
$ doctrine orm:schema-tool:update --force
Updating database schema...
Database schema updated successfully!
I verified this field now exists in the DB table.
However, when I run a simple DQL query like this:
$dql = "SELECT c.id AS id, c.commit_key AS key, c.record_checksum AS checksum ".
"FROM Entity\\Cloud c WHERE c.commit_group = :commit_group";
I get the error:
[Semantical Error] line 0, col 42 near 'record_checksum': Error: Class Entity\Cloud has no field or association named record_checksum,
I've banged my head on the wall over this for a while now. I'm sure I'm overlooking something really stupid. Any help is greatly appreciated!
-Nick
Try to:
Clear any cache that may contain the config or PHP code.
Rename a field in case the first solution didn't work.
Go to the Entity in question and check the variable name. If it's something like TESTVar, and you're trying to use testVar in the query, it's going to give you the error that the variable doesn't exist in the Entity.
Change the query to use TESTVar instead of testVar, and it will work.