Doctrine "on update CURRENT_TIMESTAMP" annotation (Symfony2) - mysql

I need to make annotation for column in my entity - "on update CURRENT_TIMESTAMP" attribute. How can I do that?

You cannot use your own column definition:
/**
* #ORM\Column(type="datetime", columnDefinition="DATETIME on update CURRENT_TIMESTAMP")
*/
private $updatedAt;
The example is for MySQL. Take into account, that columnDefinition is not portable among different databases or even their versions.

The easiest way is to use DoctrineExtensions with Timestampable as described here: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/timestampable.md

Related

Doctrine 2 Uppercase First Letter

I need to uppercase the first letter of word while fetching data using Select query in Doctrine2.
I tried UCASE , but it is not supported in Doctrine 2.
Is there any other way to Uppercase the first letter in Doctrine2 ?
You can achieve same effect by utilizing Lifecycle Callbacks if doing this on database level is not really required.
For example, in your entity, write a post-load method like this:
<?php
namespace MyApp\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\HasLifecycleCallbacks <-- NOTICE THIS ANNOTATION
*/
class MyEntity
{
/**
* #ORM\PostLoad <-- AND THIS
*/
public function capitalizeField()
{
$this->field = mb_ucfirst($this->field);
}
}
Update after two years:
This approach solves the problem. Anyway, in a similar situation I would prefer to change the case before writing the data into the database, if possible. I mean that lifecycle callbacks are not free. Another option is changing the case in presentation/view layer. Today, utilizing the whole event mechanism to change the case of a single value sounds overkill to me.
Do it in MySQL, e.g.
SELECT CONCAT(UPPER(LEFT(the_field, 1)),LOWER(SUBSTRING(the_field, 2))) FROM the_table
or if you don't want to alter the field excpet the first letter:
SELECT CONCAT(UPPER(LEFT(the_field, 1)),SUBSTRING(the_field, 2)) FROM the_table

Add a FULLTEXT index in Doctrine 2 using annotations?

I know that Doctrine 2 doesn't support FULLTEXT indexes. I'm actually using a result set mapping and native queries to FULLTEXT search innodb tables (MySQL 5.6). But I still need to mark one or more entity fields as part of the index.
Is there any way to add the index using annotations? It seems that #Index annotation doesn't specify the type of...
According to DDC-3014 in the issue tracker of Doctrine, the possibility to specify full-text indices using annotations was implemented on April 14 and will be available in release 2.5. If you don't like to wait, you could try to use the unstable, development version or to backport the commit implementing the feature.
Here is a usage example:
/**
* #Entity
* #Table(indexes={#Index(columns={"content"}, flags={"fulltext"})})
*/
class Comment
{
/**
* #Column(type="text")
*/
private $content;
...
}
Here is an example how to make a fulltext index with the yaml mapping driver.
Doctrine\Tests\ORM\Mapping\Comment:
type: entity
fields:
content:
type: text
indexes:
xy_fulltext:
columns: ["name", "content", "keywords"]
flags: fulltext

doctrine 2.0 : use SQL timestamp

I'm looking for a way to make doctrine using TIMESTAMP instead of DATETIME for MySql.
Additionaly I need to set ON UPDATE CURRENT_TIMESTAMP and CURRENT_TIMESTAMP as default values.
I would like to have the possibility to have all this code in PHP annotations to have everything in one central place.
How can I do that?
After hours of searching, I found the answer and I hope this helps anyone else looking for a more satisfactory solution than entity lifecycles and the WRONG column type (because a TIMESTAMP is a particular type with specific behaviours beyond just storing a datetime value)
All you need to do is to add
* #ORM\Column(type="datetime", nullable=false)
* #ORM\Version
to your annotation and Doctrine will both create a TIMESTAMP column with DEFAULT CURRENT_TIMESTAMP and then return the actual table value as a valid \DateTime object.
CTOP (Credits to Original Poster)
There is no such thing like using TIMESTAMP in mysql with Doctrine.
However, I fixed it myself but have to test it:
Create a file: Doctrine\DBAL\Types\TimestampType.php
Copy the code from TimeType.php into TimestampType.php
Rename 'Time' to 'Timestamp' in the code
Create a new constant, and add timestamp to the typesmap in: Doctrine\DBAL\Types\Type.php
Create function called getTimestampTypeDeclarationSQL in Doctrine\DBAL\Platforms\AbstractPlatform.php
And in that function, return TIMESTAMP
I've used yaml to create my Entities and Proxies, so use in yaml:
type: timestamp
I'm going to test this 'fix'/'workaround' now. I'll let you know.
As suggested by Daniel Criconet,
#ORM\Column(type="datetime", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
will make that particular column in the corresponding MySQL table become TIMESTAMP instead of DATETIME.
For YAML version, see the original answer.
/**
* #var \DateTime
* #ORM\Column(type="datetime", columnDefinition="timestamp default current_timestamp")
*/
protected $createdAt;
/**
* #var \DateTime
* #ORM\Column(type="datetime", columnDefinition="timestamp default current_timestamp on update current_timestamp")
*/
protected $updatedAt;
#Polichism provided the right logic, but the patch wasn't accepted. Instead, users were directed to add a custom type. I've implemented that by combining:
The logic in #Polichism's patch
Doctrine's recommended Custom Mapping Types code
Zf2 Application Configuration instructions found here
The final versions can be found on GitHub:
Timestamp Class
See the 'doctrine' part of the Configuration
NOTE: I've linked to specific commits to ensure that the links remain valid if the file is later removed. Use the history to check for newer versions.
/** #ORM\Column(type="datetime", nullable=false ) */
protected $created;
this will create timestamp and return datetime object
public function __construct()
{
$this->created = new \DateTime();
}
/**
* #Column(type="datetime", options={"default": 0})
* #version=true
*/
private $data;
create sql like this:
data TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
tested on version 2.5.4
#ORM\Version works only for one property per entity so it is not an option if you need to have more than one timestamp field in a table.

How to change update statement before executing: Linq2Sql Classes

I have implemented Change Tracking (http://msdn.microsoft.com/en-us/library/cc280462.aspx) on some tables I am using Linq2Sql on.
As a part of this I need to add the below SQL to the start of the update statements generated.
DECLARE #originator_id varbinary(128);
SET #originator_id = CAST('SyncService' AS varbinary(128));
WITH CHANGE_TRACKING_CONTEXT (#originator_id)
....generated statements....
....
....
I know I can create stored procedures and manually map the fiels but I would like to avoid this if possible.
does anyone know a way to override and edit the SQL on SubmitChanges()?
You can override the Update method by implementing partial classes on your datacontext that LINQ to SQL will call instead. Just give it the signature:
partial void UpdateClassName(ClassName instance)
You can also pass through to what it would normally do using:
ExecuteDynamicInsert(instance);
Unfortunately there is no mechanism just to get the intended SQL back for inserts/update/deletes (you can get SELECT statements with GetCommand on the DataContext)

Tell Hibernate's hbm2ddl to add MySQL enum columns for #Enumerated annotated fields

I'm creating a DB table using hbm2ddl with Java code similar to the following:
#Entity
public class Filter {
public enum Type {
TypeA, TypeB;
}
#Enumerated(EnumType.STRING)
private Type type;
}
It works fine, but for "type" a VARCHAR column is created, i.e. the DDL code looks like this:
CREATE TABLE IF NOT EXISTS `filter` (`type` varchar(255) DEFAULT NULL)
But what I want to have is this:
CREATE TABLE IF NOT EXISTS `filter` (`type` enum('TypeA','TypeB') NOT NULL)
Is this possible to declare in Hibernate, preferred with annotations?
Or is there a way to extend SchemaUpdate and overwrite the method that renders the alter script part for enumerated field the way I like it?
Background: The same database is used in a PHP part of the project and I want to prevent that invalid values are inserted.
Although it seems there is no way to handle MySQL enums 100% automatically, as pointed out by Lucas on his answer, there is actually a simple way to contour it. You may use columnDefinition attribute on #Column annotation, which seems to be specifically designed to generate custom DDL code.
See the documentation excerpt describing the attribute:
(Optional) The SQL fragment that is used when generating the DDL for the column.
Defaults to the generated SQL to create a column of the inferred type.
The NOT NULL restriction is quite standard, and is supported by another attribute nullable.
Thus, your property definition would look like this:
#Enumerated(EnumType.STRING)
#Column(columnDefinition = "enum ('TypeA', 'TypeB')", nullable = false)
private Type type;
I believe that's going to be complicated, since the java.sql.Types, which define the sql types treated by java, does not have enum type (since it's not a standardized type according to SQL-92).
If that was the case you could create a hibernate custom UserType extending the EnumType and setting the sqlType accordingly, but since java.sql.Types doesn't handle it I don't see how to use native sql enum.
best regards!