Doctrine2 Insert and retrieve new insert ID - php

In Doctrine2 using some thing like:
$user = array('username' => 'example', 'passsword' => 'changeme');
$conn->insert('users', $user);
How would I then get the last ID of the user I just inserted? If it is not possible to do this then how do you gen a id so that you can the following:
$id = //something here.
$user = array('username' => 'example', 'passsword' => 'changeme', 'id' => $id);
$conn->insert('users', $user);

If you are using the ORM
$em->persist($object);
$em->flush();
$object->getId();
if you are using the DBAL:
$conn->lastInsertId();
http://www.doctrine-project.org/api/dbal/2.5/class-Doctrine.DBAL.Connection.html#_lastInsertId

One can use the Doctrine\DBAL\Connection::lastInsertId() method.
It can be used with native queries as well as manually written inserts.
Example case:
$query = 'INSERT INTO blabla...';
$connection->executeUpdate($query, $params);
var_dump($connection->lastInsertId());
If using the ORM, you can obtain an instance of the connection from the entity manager:
$connection = $em->getConnection();
Note:
Aside from the technical details, I agree with #Layke for using an entity for your specific case.

$conn->lastInsertId();will get you the last inserted ID when only using Doctrine's DBAL (sans ORM).

Providing that your Entity which are you are trying to set has
/**
* #Id #Column(type="integer")
* #GeneratedValue
*/
private $id;
Then when you persist your object, the entity manager will populate the Entity which you are trying to persist with the ID.
Some caveats however, is that you can't do this with composite keys post obviously, and you obviously have to flush all Entities. So if you detach an Entity which has an association to the persisted entity that you are trying to get the ID for, then you won't be able to retrieve the ID.
Aside from that Flask's answer is bang on.
$em->persist($object);
$em->flush();
$object->getId();

Related

phalcon 2.0.13 set data with magic setter to related model

I have a problem with phalcon model magic getter and setter.
I want to update like this tutorial :
https://docs.phalconphp.com/en/latest/reference/models.html#storing-related-records
But the thing is my proj is multi module and separated models folder.
So I have to use alias for hasOne and belongsTo
$this->hasOne('user_id', '\Models\UserProfile', 'user_id', array('alias' => 'UserProfile'));
and
$this->belongsTo('user_id', '\Models\CoreUser', 'user_id', array('alias' => 'CoreUser'));
What i want to do is like this.
$CoreUser = new CoreUser();
$user = $CoreUser->findFirst(array(
//...condition here to find the row i want to update
));
$user->assign($newUserData);
$user->setUserProfile($newProfileData);
$user->update();
But above this code only save user data and don't save Profile data at all. (have profile data -- confirmed)
So do you have any idea what the error is? if u know, Please help me or give me a tip.
I got it now.. when assigning like $user->UserProfile = $newUserProfile;
$newUserProfile should b a Model Object.
So my new code is
$CoreUser = new CoreUser();
$user = $CoreUser->findFirst(array(
//...condition here to find the row i want to update
));
$profile = $user->UserProfile; //$profile is now model object which related to $user
//assign new array data
$profile->assign($newProfileData);
$user->assign($newUserData);
/*
* can also assign one by one like
* $user->first_name = $newProfileData['first_name'];
* but cannot be like $profile = $newProfileData or $user->UserProfile = $newProfile
* since it's gonna override it the model with array
*/
$user->UserProfile = $profile;
$user->update(); // it's working now
Thanks to #Timothy for the tips too .. :)
Instead of doing
$profile = $user->UserProfile;
You should instantiate a new UserProfile object
// find your existing user and assign updated data
$user = CoreUser::findFirst(array('your-conditions'));
$user->assign($newUserData);
// instantiate a new profile and assign its data
$profile = new UserProfile();
$profile->assign($newProfileData);
// assign profile object to your user
$user->UserProfile = $profile;
// update and create your two objects
$user->save();
Note that this will always create a new UserProfile. If you want to use the same code to update and create a UserProfile, you can maybe do something like:
// ...
// instantiate a (new) profile and assign its data
$profile = UserProfile::findFirstByUserId($user->getUserId());
if (!$profile) {
$profile = new UserProfile();
}
$profile->assign($newProfileData);
// ...

Symfony3 doctrine orm find method

I am writing a Symfony3 appusing Doctrine ORM.
SO what i am trying to do is to find if a given email address exists in a table (every email is unique). so i have a user repository with some attributes I can easily persist data to the db but failing to retrive data.
/**
* #param $email
*/
public function findUserByEmail($email)
{
$user = $this->getDoctrine()
->getRepository('TestBundle:TestUser')
->find($email);
if (!$user) {
echo 'Error';die();
}
}
I know the var passed to the function contains a email string, but what i get in return is error and when i var_dump $user before the if statment i get null.
I followed the Symfony docs
Your User probably has a separate primary key field. the find() method on a repo only retrieves by primary key.
Repositories use __call to dynamically process findBy* and findOneBy* methods, so you could call it like this:
$repo = $this->getDoctrine()->getRepository('TestBundle:TestUser');
// magic find method
$user = $repo->findOneByEmail($email);
// explicit find method
$user = $repo->findOneBy(['email' => $email]);
// custom QueryBuilder
$user = $repo->createQueryBuilder('user')
->where('user.email = :email')
->setParameter('email', $email)
->getQuery()
->getSingleResult();
BTW: If you are validating this for a submitted form, there is a contraint that does this check for you: UniqueEntity
I think the problem is because you forgot to call getManager().
So the code would be:
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('TestBundle:TestUser')->findOneBy(['email' => $email]);
Hope it would help you!

Delete records in Doctrine

I'm trying to delete a record in Doctrine, but I don't know why it's not deleting.
Here is my Code:
function del_user($id)
{
$single_user = $entityManager->find('Users', $id);
$entityManager->remove($single_user);
$entityManager->flush();
}
Plus: How can I echo query to see what going on here?
This is an old question and doesn't seem to have an answer yet. For reference I am leaving that here for more reference. Also you can check the doctrine documentation
To delete a record, you need to ( assuming you are in your controller ):
// get EntityManager
$em = $this->getDoctrine()->getManager();
// Get a reference to the entity ( will not generate a query )
$user = $em->getReference('ProjectBundle:User', $id);
// OR you can get the entity itself ( will generate a query )
// $user = $em->getRepository('ProjectBundle:User')->find($id);
// Remove it and flush
$em->remove($user);
$em->flush();
Using the first method of getting a reference is usually better if you just want to delete the entity without checking first whether it exists or not, because it will not query the DB and will only create a proxy object that you can use to delete your entity.
If you want to make sure that this ID corresponds to a valid entity first, then the second method is better because it will query the DB for your entity before trying to delete it.
For my understanding if you need to delete a record in doctrine that have a doctrine relationship eg. OneToMany, ManyToMany and association cannot be easy deleted until you set the field that reference to another relation equal to null.
......
you can use this for non relation doctrine
$entityManager=$this->getDoctrine()->getManager();
$single_user=$this->getDoctrine()->getRepository(User::class)->findOneBy(['id'=>$id]);
$entityManager->remove($single_user);
$entityManager->flush();
but for relation doctrine set the field that reference to another relation to null
$entityManager=$this->getDoctrine()->getManager();
$single_user=$this->getDoctrine()->getRepository(User::class)->findOneBy(['id'=>$id]);
{# assume you have field that reference #}
$single_user->setFieldData(null);
$entityManager->remove($single_user);
$entityManager->flush();
do you check your entity as the good comment annotation ?
cascade={"persist", "remove"}, orphanRemoval=true
In a Silex route I do like this, in case it helps someone:
$app->get('/db/order/delete', function (Request $request) use ($app) {
...
$id = $request->query->get('id');
$em = $app['orm.em']; //or wherever your EntityManager is
$order = $em->find("\App\Entity\Orders",$id); //your Entity
if($order){
try{
$em->remove($order);
$em->flush();
}
catch( Exception $e )
{
return new Response( $e->getMessage(), 500 );
}
return new Response( "Success deleting order " . $order->getId(), 200 );
}else{
return new Response("Order Not Found", 500);
}
}
You first need repository.
$entityManager->getRepository('Users')->find($id);
instead of
$single_user = $entityManager->find('Users', $id);
'Users' String is the name of the Users repository in doctrine ( depends if you are using Symfony , Zend . . etc ).
First, You may need to check if 'Users' is your fully qualified class name. If not check, and update it to your class name with the namespace info.
Make sure the object returned by find() is not null or not false and is an instance of your entity class before calling EM's remove().
Regarding your other question, instead of making doctrine return SQL's I just use my database (MySQL) to log all queries (since its just development environment).
try a var_dump() of your $single_user. If it is "null", it doens't exist ?
Also check if "Users" is a valid Entity name (no namespace?), and does the $id reference the PK of the user?
If you want to see the queries that are executed check your mysql/sql/... log or look into Doctrine\DBAL\Logging\EchoSQLLogger

Elegant way to walk backward through OneToOne table entities with Doctrine

I have a very simply structured entity that contains a simple association
Database_Entity_Tenant
id (primary key)
parentId (id of the parent entry)
code (a simple identifier for the tenant, unique)
I defined parentId in my entity accordingly:
/**
* #Column(type="integer")
* #OneToOne(targetEntity="Tenant")
* #JoinColumn(name="parentTenantId", referencedColumnName="id")
* **/
protected $parentId;
This works fine - the generated database schema resembles my choices and its good.
Now i am writing my first method which basically has to return an array of all the tenants that are chained together, in reverse order (i use this for walking backward through a chain of tenants).
In order to do that i came up with the idea to use a while() loop.
$currentTenant = {DATABASE_ENTITY_TENANT}; // In my real code i fetch the entity object of the current tenant
$chain[] = $currentTenant;
$repository = Database::entityManager()->getRepository('Database_Entity_Tenant');
while(!$currentTenant->getParentId()){
$currentTenant = $repository->findOneBy(array(
'id' => $currentTenant->getParentId()
));
$chain[] = $currentTenant;
}
Any tenant that has no parent (such as the base tenant) will have no parent id (or null), so that would end the while loop.
Now all this may work, but it seems really rough to me. I am fairly new to Doctrine so i don't know much about it but i am sure there is some way to do this more elegantly.
QUESTION
Does Doctrine 2 provide me with any set of functions i could use to solve the above problem in a better way?
If not, then is there any other way to do this more elegantly?
If I'm not getting your problem wrong, you just need to find all the entries in your association table ordered by the parentId. In Doctrine2 you can do the following:
$currentTenant = {DATABASE_ENTITY_TENANT}; // assuming a valid entity
$repository = Database::entityManager()
->getRepository('Database_Entity_Tenant')
->createQueryBuilder('t')
->where('t.parentId IS NOT NULL')
->andWhere('t.parentId < :current') /* < or > */
->setParameter('current', $currentTenant->getParentId()->getId())
->orderBy('t.parentId', 'ASC') /* ASC or DESC, no array_reverse */
->getQuery()
->getResult();
/* At this point $repository contains all what you need because of Doctrine,
* but if you want a chain variable: */
$chain = array();
foreach ($repository as $tenant) {
$chain[] = $tenant->getCode(); // your tenant entity if your entity is mapped correctly
}
Hope this helps!

How to access old values on PrePersist LifecycleCallback in Doctrine2

I have an entity in Doctrine2 and use the HasLivecycleCallbacks with PrePersist. In general this works fine, but I would like to change the version only, when certain fields in my entity change. Do I have a chance to get the old Values? Or just the keys that have been changed?
/**
* #ORM\HasLifecycleCallbacks
*/
class Person {
/**
* #PrePersist
* #PreUpdate
*/
public function increaseVersion() {
if ( $this->version == null ) {
$this->version = 0;
}
// only do this, when a certain attribute changed
$this->version++;
}
}
It depends on which LifecycleEvent we are talking about. PrePersist and PreUpdate are different events.
PreUpdate is fired before an Entity is, well, updated. This will give you a PreUpdateEventArgs object, which is an extended LifecycleEventArgs object. This will allow you to query for changed fields and give you access to the old and new value:
if ($event->hasChangedField('foo')) {
$oldValue = $event->getOldValue('foo');
$newValue = $event->getNewValue('foo');
}
You could also get all the changed field values through getEntityChangeSet(), which would give you an array like this:
array(
'foo' => array(
0 => 'oldValue',
1 => 'newValue'
),
// more changed fields (if any) …
)
PrePersist, on the other hand, assumes a fresh Entity (think insert new row). In PrePersist, you'll get a LifecycleEventArgs object which only has access to the Entity and the EntityManager. In theory, you can get access to the UnitOfWork (which keeps track of all the changes to Entities) through the EntityManager, so you could try to do
$changeSet = $event->getEntityManager()->getUnitOfWork()->getEntityChangeSet(
$event->getEntity()
);
to get the changes for the to be persisted Entity. You could then check this array for changed fields. However, since we are talking about an insert and not an update, I assume all fields wil be considered "changed" and the old values will likely be all null. I am not sure, this will work as you need it.
Further reference: http://docs.doctrine-project.org/en/2.0.x/reference/events.html

Categories