Update an Entity with Unique Key - Insert instead of update - symfony

I have this method in my service:
public function updateCountry($p_entity) {
var_dump($p_entity->getId()); //return 3 (as expected)
var_dump(get_class($p_entity) ); //return Country (as expected)
$this->em->persist($p_entity);
$this->em->flush();
}
I call it by
$country = $em->getRepository('blabla')->find(3);
$my_service->updateCountry($country);
But the request generated is
Doctrine\DBAL\DBALException: An exception occurred while executing
'INSERT INTO country (code, label , created_at, updated_at)
VALUES (?, ?, ?, ?)' with params ["EN", "England", "201
3-08-23 00:00:00", null]:
I have a unique doctrine constraint
this is my country.orm.yml
To\Bundle\Entity\Country:
type: entity
table: country
repositoryClass: To\Bundle\Entity\CountryRepository
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
code:
type: string
length: 255
unique: true
nullable: false
Why have I an insert request generated instead of the update one?

Can you persist new entity at all?
If you can, try merging your object instead:
public function updateCountry($p_entity) {
var_dump($p_entity->getId()); //return 3 (as expected)
var_dump(get_class($p_entity) ); //return Country (as expected)
$this->em->merge($p_entity); // MERGE not PERSIST
$this->em->flush();
}
From official docs:
If X is a new entity instance, a new managed copy X’ will be created
and the state of X is copied onto this managed instance.
So, basically, EntityManager::merge can be used to both persist newly created object and merge exsistent one...

You shouldn't persist existing in DB entity, only new one.
So if you get entity from DB and want to update it
you should
$entity->setName()
$em->flush

Related

No entity manager defined for class DateTime

I have started using the Sonata Admin bundle and I was following the example on how to map an entity with the bundle to create an administrative interface.
I created an entity called Post and this is the configuration yml file:
Emiliano\PostsBundle\Entity\Post:
type: entity
table: null
repositoryClass: Emiliano\PostsBundle\Entity\PostRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
title:
type: string
column: Title
lenght: 100
published:
type: boolean
column: Published
publishingDate:
type: datetime
column: Publishing_Date
nullable: TRUE
lifecycleCallbacks: { }
Then in my Admin class I have the configureFormFields method:
protected function configureFormFields(FormMapper $formMapper) {
$formMapper->add('title', 'text')
->add('published', 'checkbox', array('required' => false))
->add('publishingDate', 'sonata_type_model_hidden');
}
I found the sonata_type_model_hidden on the sonata admin documentation. What I would like to achieve is to programmatically handle the publishing date (e.g. set the date only if the checkbox published is checked) hiding the implementation to the user.
Everything works fine for create, delete and read, when it comes to modify an entity I get this message in the stacktrace:
No entity manager defined for class DateTime
In sonata-project/doctrine-orm-admin-bundle/Sonata/DoctrineORMAdminBundle/Model/ModelManager.php at line 214
If I show the field everything works fine, I tried also to use:
->add('publishingDate', 'hidden');
without success.
What is exactly the problem here? Is it because Sonata Admin tries to fill a form with the entity values and for publishingDate there's a DateTime while in the form specification I wrote a sonata_type_model_hidden? If so, how can I circumvent this?
sonata_type_model_hidden isn't just hidden field genereator, according to documentation:
sonata_type_model_hidden will use an instance of ModelHiddenType to render hidden field. The value of hidden field is identifier of related entity.
If I understand your problem, You want to set publishing date only when field published == true
You could use entity preSave/preUpdate lifecycle callback for eaxmple
public function preSave()
{
/**
* Check if item is published
*/
if($this->getPublished()) {
$this->setPublishingDate(new \DateTime());
} else {
$this->setPublishingDate(null);
}
}
and remove publishingDate field from SonataAdmin form.

Query builder join on one to many relationship

I have a LastTrait object that has a many to one relationship with my user object: one user can have many different lastTrait:
YOP\YourOwnPoetBundle\Entity\LastTrait:
type: entity
table: null
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
traitCategoryID:
type: integer
verseID:
type: integer
manyToOne:
user:
targetEntity: User
inversedBy: lastTrait
joinColumn:
name: user_id
referencedColumnName: id
I need to retrieve the verseID knowing the userID and traitCategoryID. So I created a Repository for my LastTrait object:
<?php
namespace YOP\YourOwnPoetBundle\Repository;
use Doctrine\ORM\EntityRepository;
class LastTraitRepository extends EntityRepository {
public function findOneByTraitCategoryID($userID, $traitCategoryID)
{
return $this->getEntityManager()
->createQuery('SELECT l
FROM YOPYourOwnPoetBundle:LastTrait l
JOIN l.user u
WHERE l.traitCategoryID = :categoryID AND u.id = :userID')
->setParameters(array(
'categoryID' => $traitCategoryID,
'userID' => $userID,
))
->getResult();
}
}
?>
However, when I call :
$lastTrait = $this->getDoctrine()
->getRepository('YOPYourOwnPoetBundle:LastTrait')
->findOneByTraitCategoryID($user->getID(), $collector->getTraitCategory()->getID());
I always get NULL, even though I should get a LastTrait object back!
What am I doing wrong here?
I think you should be thinking more in entities and less in foreign keys.
Try this in your method.
public function findOneByTraitCategoryID($userID, $traitCategoryID)
{
return $this->findOneBy(
array(
'traitcategoryID' => $traitCategoryID,
'user' => $userID
));
}
You can call ->getVerse()->getId(); after this or return the id directly on the method (too narrow for future uses IMO).
This only works if a user only has one trait per category, otherwise you don't have enough data to get a specific trait.
The issue was that I forgot to register the repository in my entity:
YOP\YourOwnPoetBundle\Entity\LastTrait:
repositoryClass: YOP\YourOwnPoetBundle\Repository\LastTraitRepository
type: entity
table: null
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
traitCategoryID:
type: integer
verseID:
type: integer
manyToOne:
user:
targetEntity: User
inversedBy: lastTrait
joinColumn:
name: user_id
referencedColumnName: id
After adding the repositoryClass line, my custom Repository class is called and I get the desired result.
However, #dhunter's answer made me realize that I didn't even need a custom Repository class. I can get the desired by simply using the regular findOneBy function from my controller:
$lastTrait = $this->getDoctrine()
->getRepository('YOPYourOwnPoetBundle:LastTrait')
->findOneBy(
array('user' => $user->getId(), 'traitCategoryID' => $collector->getTraitCategory()->getID())
);
Hard to tell. Try echoing either DQL or SQL before retreiving results:
$q = $this->getEntityManager()->createQuery(....);
die($q->getSql()); //or getDql();
If, for some reason, you have invalid mapping (which I don't see above) you should see it here.
Also, try wrapping method with try-catch with most general Exception catch and seeing if it catches anything...
Furthermore, what is bugging me is the fact that you get NULL back...

Symfony2 - EntityNotFoundException

I have a Stats entity that is related to a Journey entity through a ManyToOne association.
id:
index:
type: integer
fields:
idJourney:
type: string
// data fields...
manyToOne:
journey:
targetEntity: Journey
joinColumn:
name: idJourney
referencedColumnName: idJourney
The Journey is related to the Station entity through two ManyToOne association: one for the first Station of the Journey, one for the last.
id:
idjourney:
type: string
fields:
idFirstStation:
type: string
idLastStation:
type: string
// other info fields
manyToOne:
firstStation:
targetEntity: Station
joinColumn:
name: idFirstStation
referencedColumnName: idStation
lastStation:
targetEntity: Station
joinColumn:
name: idLastStation
referencedColumnName: idStation
Finally, the Station entity :
id:
idStation:
type: string
fields:
name:
type: string
// other station info
I retrieve a collection of Stats objects with all related sub-objects via a custom Repository method which works fine.
$statCollection = $statsRepository->getStatsByDateAndArea($date, $area);
//This retrieves the expected data
$statCollection[0]->getJourney()->getFirstStation()->getName();
However, iterating through the collection with a foreach loop doesn't work:
foreach($statCollection as $stat) {
$journey = $stat->getJourney(); // works fine
$firstStationId = $journey->getFirstStationId(); // works too
$firstStation = $journey->getFirstStation(); // still works, but returns a Proxies\AcmeAppPathWhateverBundleEntityStationProxy object instead of a AcmeAppPathWhateverBundleEntityStation, but this should be transparent (as per Doctrine documentation)
$firstStationName = $firstStation->getName(); // throws an EntityNotFoundException
}
Any idea what's going on ? Should I force Doctrine to fetch all sub entities ?
EDIT
The error message is fairly laconic :
EntityNotFoundException: Entity was not found.
Not very helpful...
I ended up querying explicitly for the full set of sub-entities in my custom repository method...
I changed this query :
->select('stats')
->leftJoin('stats.journey', 'j')
->leftJoin('j.firstStation', 'fs')
->leftJoin('j.lastStation', 'ls')
to :
->select('stats, j, fs, ls')
->leftJoin('stats.journey', 'j')
->leftJoin('j.firstStation', 'fs')
->leftJoin('j.lastStation', 'ls')
I guess Doctrine's use of Proxy objects are not all that transparent...

Database Searching Using Doctrine and Symfony2

So I'm currently trying to perform a simple search using Symfony2 and Doctrine. Something similar to this: http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/searching.html
I've currently got the following YAML file setup to generate my entities. It generates my class Style entity correctly as a class.
...\Style:
type: entity
table: styles
id:
id:
type: integer
generator:
strategy: IDENTITY
actAs:
Searchable:
fields: [title]
batchUpdates: true
fields:
title:
type: string
length: 150
unique: true
In my controller, I'm trying to run a search on that table based on a string.
public function searchAction($pattern)
{
$repository = $this->getDoctrine()->getRepository('..:Style');
$search = $repository->search($pattern);
return $this->outputize($search);
}
However, when I try executing the code, I get the following exception.
Undefined method 'search'. The method name must start with either findBy or findOneBy!
Am I generating my entities correctly or is there something I'm clearly missing?
On a side note, when I look at my Entity/Style.php after generating, there is no clear method ->search(), is the function supposed to be generated by Symfony here?
search() is not a function supported in Symfony2. You're looking at the Symfony 1.x documentation, and Symfony2 is really different from Symfony 1.x so for reference, you should always use the doc.
There are several ways to fetch entities in Symfony2. Here are a few examples:
Find
$user = $this->getDoctrine()
->getRepository('UserBundle:User')
->find($user_id)
;
DQL:
$query = $em->createQuery(
'SELECT b FROM YourBundle:Bid b WHERE b.property_id = :property_id ORDER BY b.amount DESC'
)->setParameter('property_id', $property_id);
try {
$bids = $query->getResult();
} catch (\Doctrine\Orm\NoResultException $e) {
//Handle No Result Exception here
}
Refer to the Doctrine guide for Symfony2 here: http://symfony.com/doc/current/book/doctrine.html
Hello you can do it in symfony 3
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p
FROM AppBundle:Hotel p
WHERE p.address like :location
ORDER BY p.address ASC'
)->setParameter('location','%'.$request->get('location').'%' );
$hotel = $query->getResult();

symfony2 doctrine:generate:CRUD error

I am new to symfony2 framework. I have a mysql db that I have prior to installing symfony. So I was able to generate schema based on the db.
I am trying to generate the CRUD controller for one of the tables. This is a user table and the primary key is UserId. However, when I run doctrine:generate:CRUD, I get the following error
The CRUD generator expects the entity object has a primary key field named "id" with a getId() method.
Do I have to have Id as the PK identifier? is that the best practice? All my PKs for the tables are defined by tablenameid.
I have the get method for the User entity class as getUserid().
How can I let the CRUD generator know that?
Thanks
I don't think it has to be 'id' as PK identifier. I think there might be some error in your entity.
/** #Id #Column(type="integer") #GeneratedValue */
private $userid;
YML File:
Bundle\BundleBundle\Entity\Example:
type: entity
table: Example
fields:
userid:
id: true
type: integer
generator:
strategy: AUTO

Resources