Symfony2 Doctrine Raw SQL Stored Procedure Loop through multiple result sets - symfony

I have managed to execute raw SQL (ie no ResultSetMapping) and can call and execute an MSSQL Stored Procedure.
The code I have is as follows:
$em = $this->get('doctrine')->getManager();
$stmt = $em
->getConnection()
->prepare('EXEC someSP :id,null,:uid');
$stmt->bindValue('id', '629674');
$stmt->bindValue('uid', '217');
$stmt->execute();
$results = $stmt->fetchAll();
No that works fine; however the issue i have is if the SP returns more than one result set the above only returns the first result set. Is there any way to loop through and get each result set?

I had to deal with the similar issue and this is what I came up with. This function is from the class that extends Doctrine\ORM\EntityRepository so I have access to the _em property in general case you can use $this->get('doctrine')->getManager(); to get entity manager.
protected function execMultiSetQuery($query, $params, $connection = 'default') {
// Init
$conn = $this->_em
->getConnection($connection)
->getWrappedConnection();
// Processing
if ($conn instanceof \Doctrine\DBAL\Driver\PDOConnection) {
$stmt = $conn->prepare($query);
$stmt->execute($params);
// Loop through the row sets
$results = array();
do {
try {
$results[] = $stmt->fetch(\PDO::FETCH_ASSOC);
}
catch (\Exception $e) {}
} while($stmt->nextRowset());
$stmt->closeCursor(); // Clean up
return $results;
}
else {
return false;
}
}

OK I was able to do this but i had to create my own wrapper around the connection:
Its a work around at best but the code basically creates a new PDO connection using the DBAL params in conf.yml. it them prepares and executes the statement and returns all the result sets.
code is free to use here:
https://github.com/scott-davidjones/Symfony2DBALSPWrapper

You can try and itterate over each set 1 by one. But really fetchAll should do the same as below, cant hurt to try though...
$em = $this->get('doctrine')->getManager();
$stmt = $em
->getConnection()
->prepare('EXEC someSP :id,null,:uid');
$stmt->bindValue('id', '629674');
$stmt->bindValue('uid', '217');
$stmt->execute();
do{
$results[] = $stmt->fetchAll()
} while($stmt->nextRowset());

Related

onFlush listener, getting entity Id for a scheduled entity insertions

I have a listener for onFlush event.
public function onFlush(OnFlushEventArgs $args) {
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
foreach ($uow->getScheduledEntityInsertions() as $entity) {
$id = ...
}
}
I would like to get the Id of the $entity. If I call getId() then return null. Is there any way to finish the flushing inside this listener and get the $entity's Id?
Thank you advance
Accessing the ID before the SQL INSERT command is executed is impossible but you can access the MySQL table's auto increment value with some tricky ways like this:
$classMeta = $em->getClassMetadata($className);
if ($classMeta->rootEntityName !== $className) {
// if the Entity is inherited, only root entity table may have auto increment ID
$classMeta = $em->getClassMetadata($classMeta->rootEntityName);
}
$tableName = $classMeta->getTableName();
$conn = $em->getConnection();
$stmt = $conn->prepare("SHOW TABLE STATUS LIKE '".$tableName."'");
$stmt->execute();
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
$id = $result['Auto_increment'];
Be aware using this:
this solution is hacky, auto increment value may differ from inserted ID
your MySQL user must have permission to run this SQL command

Symfony call get by Name from variable

I would like to call a getter with the stored fieldname from the database.
For example, there are some fieldnames store like ['id','email','name'].
$array=Array('id','email','name');
Normally, I will call ->getId() or ->getEmail()....
In this case, I have no chance to handle things like this. Is there any possibility to get the variable as part of the get Command like...
foreach ($array as $item){
$value[]=$repository->get$item();
}
Can I use the magic Method in someway? this is a bit confusing....
Symfony offers a special PropertyAccessor you could use:
use Symfony\Component\PropertyAccess\PropertyAccess;
$accessor = PropertyAccess::createPropertyAccessor();
class Person
{
private $firstName = 'Wouter';
public function getFirstName()
{
return $this->firstName;
}
}
$person = new Person();
var_dump($accessor->getValue($person, 'first_name')); // 'Wouter'
http://symfony.com/doc/current/components/property_access/introduction.html#using-getters
You can do it like this :
// For example, to get getId()
$reflectionMethod = new ReflectionMethod('AppBundle\Entity\YourEntity','get'.$soft[0]);
$i[] = $reflectionMethod->invoke($yourObject);
With $yourObject being the object of which you want to get the id from.
EDIT : Don't forget the use to add :
use ReflectionMethod;
Hope this helps.
<?php
// You can get Getter method like this
use Doctrine\Common\Inflector\Inflector;
$array = ['id', 'email', 'name'];
$value = [];
foreach ($array as $item){
$method = Inflector::classify('get_'.$item);
// Call it
if (method_exists($repository, $method))
$value[] = $repository->$method();
}

doctrine 2 - removing all elements from arraycollection does not invoke any Event

I need to invoke event when arraycollection is cleared (has no elements), pre/postUpdate is not invoked then. Only if I change contents of arraycollection and there is at least one element after change pre/postUpdate events are invoked.
Any Idea how to make it work?
public function postUpdate(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$em = $args->getEntityManager();
if ($entity instanceof Track) {
// remove all old statuses
$query = $em->createQuery(
'SELECT os
FROM CuculoERPBundle:OrderStatus os
WHERE os.track = :track'
)
->setParameter(':track', $entity->getId());
$orderStatusArray = $query->getResult();
foreach ($orderStatusArray as $orderStatus) {
$em->remove($orderStatus);
}
// add new statuses
foreach ($entity->getOrders() as $order) {
var_dump($order->getId());
$orderStatus = new OrderStatus();
$orderStatus->setOrder($order);
$orderStatus->setTrack($entity);
$orderStatus->setStep($em->getReference('Cuculo\ERPBundle\Entity\OrderStep', 6));
$em->persist($orderStatus);
}
$this->needsFlush = true;
}//end if
}//end postUpdate()
I managed to do this by copying code after // remove all old statuses to UpdateAction and adding conditional to count ArrayCollection and if 0 exec this code.

Cant flash after preUpdate event

This is what I do in even preUpdate
public function preUpdate(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if ($entity instanceof Order) {
if ($args->hasChangedField('status') && $args->getNewValue('status') == 'stock') {
$this->container->get('activity_logger')->writeLog($entity, 'purchase');
}
}
This is where I have error
FatalErrorException: Error: Maximum execution time of 60 seconds
exceeded in /vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php line 2498
public function writeLog ($object, $comment)
{
$entity = new Stock();
$entity->setCategory($object->getIsotope()->getCategory()->getId());
$entity->setComment($comment);
$entity->setDate(new \DateTime('now'));
$entity->setUser($object->getUser()->getId());
$entity->setChange(TRUE);
$this->em->persist($entity);
$this->em->flush();
}
There are store a new entity another way?
find not very nice solution(do it manually) its save and dont touch events
$sql = "INSERT INTO table (field1, field2) VALUES ('foo', 'var')";
$stmt = $em->getConnection()->prepare($sql);
$stmt->bindValue('invoice', $invoiceId);
$result = $stmt->execute();
I think that you can't do this because the output of a managed Entity contains recursive fields.
Take a look at https://github.com/schmittjoh/JMSSerializerBundle :) And log the serialized version ;)
To do that I store the newly created entities in a private array in the EventSuscriber. Then on the onFlush part of the suscriber if that array length is greater than 0 I persist them with a foreach loop. Then, outside the foreach loop, I clear the array (this is very important to prevent infinite loop) and finally call the flush.

Doctrine get accessor for entities

Is there anyway to access the data of my entity without to use a specific accessor to my column value. Is there any generic accessor? See example:
$em = $this->getDoctrine()->getManager();
$data = $em->getRepository('EgBundle:Table')->findAll()
foreach($data as $row) {
var_dump($row->get('col1')); // I would like to do this
var_dump($row->getCol1()); // instead of this
$col = 'getCol1'; var_dump($row->$col()); // this is my temporary solution
}
You might be able to make use of the symfony2 PropertyAccessor component.
Docs here: http://symfony.com/doc/current/components/property_access/introduction.html
Example:
$accessor = PropertyAccess::createPropertyAccessor();
$accessor->getValue($row, 'col1');
You can get an array if you use DQL
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery('SELECT table FROM EgBundle\Entity\Table table');
$data = $query->getQuery()->getArrayResult();
foreach ($data as $row) {
var_dump($data['col1']);
}
No, not without adding support for that with userland code. You can add something like:
public function get($property) {
return $this->$property;
}

Resources