For an existing Entity-Relationship diagram, let's say we have Author and Book entities.
Author can have published several Book;
A Book can have several Author.
The database already exists. As the joining table (asso_book_author) is already here, how to manage it with Symfony & Doctrine ?
Thanks a lot by advance.
Are you using Annotations for Doctrine Entities? Hope so... ;-)
Here is an example from the Doctrine Annotations Reference Manual:
http://www.doctrine-project.org/docs/orm/2.0/en/reference/annotations-reference.html#annref-manytomany
<?php
/**
* Owning Side
*
* #ManyToMany(targetEntity="Group", inversedBy="features")
* #JoinTable(name="user_groups",
* joinColumns={#JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
private $groups;
and
/**
* Inverse Side
*
* #ManyToMany(targetEntity="User", mappedBy="groups")
*/
private $features;
Related
Is it possible to make eloquent queries case insensitive? An issue came when I decided to move my website to production (move from my local machine to the host server). MariaDB on my host server is case sensitive and I don't have an access to its config file. The problem is that I have a Users table which is used in laravel auth. The queries of laravel in lower case like:
select * from `users` where `id` = 1 limit 1
I really need to know how to make queries case insensitive, because I have hundreds queries with Users table.
As we've been discussing in the comments, adding the protected $table = 'StRaNgE-tAbLe-NaMe'; to a MyModel.php will work on a case-by-case basis.
If you have a more structured naming convention, but it does not follow laravel's default, then you could create a trait or model base class to override Model getTable().
$model->getTable() looks like this...
/**
* Get the table associated with the model.
*
* #return string
*/
public function getTable()
{
if (! isset($this->table)) {
return str_replace(
'\\', '', Str::snake(Str::plural(class_basename($this)))
);
}
return $this->table;
}
I`m trying to change a table name with doctrine migrations.
Example table name is model and I want to change it to new_model.
/**
* Class Model
*
* #package AppBundle\Entity
*
* #ORM\Table(name="new_model")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ModelRepository")
* #ORM\HasLifecycleCallbacks()
*/
class Model
{
......
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Product", inversedBy="products", fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="product_id", referencedColumnName="id", nullable=false)
private $brand;
.......
To change to column name manually with migration script, I used:
$this->addSql('ALTER TABLE model RENAME new_model');
After running the migration the relations(join columns) are not changed and still reference to the old columnname. I also cleared the cache.
Does someone know how I can change a table name and the foreign key without loosing the relation data?
:(
The normal way of clearing cache was missing the mapping for doctrine.
After running:
php bin/console d:c:clear-metadata
It was working again.
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
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.
I am working with Symfony2 and Doctrine ORM using MySql .
After creating an Entity, I am not able to create the table. It throws an exception.
anu#anu-bridge:/var/www/Symfony$ php app/console doctrine:schema:update --force --dump-sql
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'product' already exists.
doctrine:schema:update [--complete] [--dump-sql] [--force] [--em[="..."]]
I tried to drop it , but still it throws the error.
anu#anu-bridge:/var/www/Symfony$ php app/console doctrine:schema:drop --force
Dropping database schema...
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'product' already exists.
doctrine:schema:drop [--dump-sql] [--force] [--full-database] [--em[="..."]]
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'product' already exists.
There is no tables in the database. Cleared all the cache for symfony and doctrine, but still the error is throwing.
Symfony2 version is 2.0.1 .
I've had a similar problem. Most likely you have two entities named Category inside different Bundles. For instance:
src/Acme/SomeBundle/Entity/Product.php
src/Acme/OtherBundle/Entity/Product.php
Comment one of these files and retry the console command.
I was getting this problem from a conflict with join table defined in an association class annotation and a join table defined in a ManyToMany annotation.
The mapping definitions in two entities with a direct ManytoMany relationship appeared to result in the automatic creation of the join table using the 'joinTable' annotation. However the join table was already defined by an annotation in its underlying entity class and I wanted it to use this association entity class's own field definitions so as to extend the join table with additional custom fields.
The explanation and solution was thanks to this post in the forum 'Doctrine Annotation Question'. This post draws attention to the Doctrine documentation regarding ManyToMany Uni-directional relationships. Look at the note regarding the approach of using an 'association entity class' thus replacing the many-to-many annotation mapping directly between two main entity classes with a one-to-many annotation in the main entity classes and two 'many-to-one' annotations in the Associative Entity class. There is an example provided in this forum post Association models with extra fields:
public class Person
{
/**
* #OneToMany(targetEntity="AssignedItems", mappedBy="person")
*/
private $assignedItems;
}
public class Items
{
/**
* #OneToMany(targetEntity="AssignedItems", mappedBy="item")
*/
private $assignedPeople;
}
public class AssignedItems
{
/**
* #ManyToOne(targetEntity="Person")
* #JoinColumn(name="person_id", referencedColumnName="id")
*/
private $person;
/**
* #ManyToOne(targetEntity="Item")
* #JoinColumn(name="item_id", referencedColumnName="id")
*/
private $item;
}
I got this error when editing my Product.orm.yml file.
I added a new manyToMany relation with a Category entity, and made a mistake on the joinTable line :
manyToMany:
categories:
targetEntity: Acme\ProductBundle\Entity\Category
inversedBy: products
joinTable:
name: Product # My mistake: joinTable should be something like ProductCategory
[...]
Indeed it's a silly error, I share anyway.
If you can, you can do this as this worked for me:
Drop the entire database:
app/console doctrine:schema:drop --force --full-database
Run all DB migrations:
app/console doctrine:migrations:migrate
I imagine It can happen quite often when copying entities. In my case it was a ORM table name annotation that was misfortunately duplicated.
/**
* #ORM\Entity()
* #ORM\Table(name="category")
* */
class Category {
I had this problem with an One-To-Many, Unidirectional with Join Table relation like (see doctrine doc). I did not find this error case with this relation type through the internet or stackoverflow, so i post here my solution for let help others with the same problem.
What caused this problem:
After reverse engineering the legacy db tables with ORM (see doc "How to Generate Entities from an Existing Database"), all tables also only join tables recieved an entity PHP class.
With annotations on a category entity i described the joining. Results this code:
/**
* #ORM\ManyToMany(targetEntity="Category")
* #ORM\JoinTable(name="category_child",
* joinColumns={#JoinColumn(name="category_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="category_child_id", referencedColumnName="id")}
* )
*/
public $children;
The #ORM\JoinTable(name="category_child" caused that doctrine wants to create this table again. One time because of the already existing Category_Child entity, and then the #ORM\JoinTable expression that points to the same table.
Solution
Solution was to delete the Category_Child entity that was created from reverse engineering. If you used Category_Child entity in some $em queries, you have to select those datas othwerwise. E.g. Through the parent that holds those child datas in an ArrayCollection, or over DBAL.