I cannot persist multiple entities inside the controller. I can only save the last one.
My code:
$product = new Product();
$names = ['yellow', 'blue', 'red']; // save these to the table
foreach ($name as $name) {
$product->setName($name);
$em->persist($product);
// $em->flush(); // doesn't work either
}
$em->flush();
I am using Symfony 2.7
You have to create a new Product inside your loop.
Right now it's only taking 1 product, and it's constantly updating that one.
$names = ['yellow', 'blue', 'red']; // save these to the table
foreach ($names as $name) {
$product = new Product();
$product->setName($name);
$em->persist($product);
}
$em->flush();
I created this solution which looks nice:
array_walk($arrayOfEntities, function ($entity) {
$entityManager->persist($entity);
});
Use clone operator (php 5+)
$product = new Product();
$names = ['yellow', 'blue', 'red'];
foreach ($names as $name) {
$tmpProductObj = clone $product;
$em->persist($tmpProductObj);
}
$em->flush();
More information about cloning an object can be found here
You are only creating one Object Product.
Obviously, only one object will be persisted to the database then.
Also at the top your variable is called $Product(capital P) while in the loop it is called $product.
Try this instead:
$NameList = array("yellow","blue","red"); // save these to the table
foreach($NameList as $name){
$product = new Product();
$product->setName($name);
$em->persist($Product);
//$em->flush(); // doesnot work either
}
$em->flush();
If I want add multiple objects after set its value I use clone in loop:
$application = new Application();
$application->setSomething($someting);
for ($i = 1; $i <= $request->get('number_of_applications'); $i++){
$applicationObj = clone $application;
$em->persist($applicationObj);
}
$em->flush();
Related
I have two entities, the scale and scale elements. These are available in a OneToMany relationship. The scale elements have an attribute called "sorting". In this column, I will save the order.
Also i create a form ScaleType with collection ScaleElements. I can sort the scale elements with jquery sortable and post the sorted elements. After i post the form i will get the scale elements in posted order to save the "sorting" column.
My edit action which handle this issue looks like:
public function editAction($id, Request $request)
{
$em = $this->getDoctrine()->getManager();
$scale = $em->getRepository('AppMyBundle:Scale')->find($id);
if (!$scale) {
$this->get('session')->getFlashBag()->add('danger', $this->get('translator')->trans('not found'));
return $this->redirect($this->generateUrl('scale_list'));
}
// Create an ArrayCollection of the current Scaleitems objects in the database
$originalScaleElements = new ArrayCollection();
foreach ($scale->getElements() as $element) {
$originalScaleElements->add($element);
}
$form = $this->createForm($this->get('form.type.scale'), $scale);
$form->handleRequest($request);
if ($form->isValid()) {
// remove the relationship between the scale and the elements
foreach ($originalScaleElements as $element) {
if (false === $scale->getElements()->contains($element)) {
$element->setScale(null);
$em->persist($element);
$em->remove($element);
}
}
// Get elements
$scaleElements = $scale->getElements();
// Init counter
$counter = 1;
foreach ($scaleElements as $element) {
$element->setSorting($itemCounter);
$element->setScale($scale);
$em->persist($element);
$counter++;
}
$em->persist($scale);
$em->flush();
$this->get('session')->getFlashBag()->add('info', $this->get('translator')->trans('object edited', array()));
return $this->redirect($this->generateUrl('scale_list'));
}
return $this->render('AppMyBundle:Scale:edit.html.twig', array("form" => $form->createView()));
}
But the sorting attribute do not change from scale elements. It have the initial state which was set in the add action. In add action exists the same loop which set the sorting attribute for posted scale elements.
How can i solve this issue?
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.
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;
}
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());
I am using Stof's DoctrineExtension bundle to retrieve my Tree, now I want to convert that tree to an array (which will then in turn get converted to json).
The format of NestedTreeRepository->childrenHierarchy() is not in the correct format though, I want to modify the output so only the node "title" property and the "id" property is returned, and put any children in a "children" subarray. In compliance with this format (JSON):
{
label: 'node1',
children: [
{ label: 'child1' },
{ label: 'child2' }
]
},
{
label: 'node2',
children: [
{ label: 'child3' }
]
}
}
I have tried to following code, this returns the same as childrenHierarchy() but would allow me to modify the query.
$query = $em
->createQueryBuilder()
->select('node')
->from('MyBundle:Page', 'node')
->orderBy('node.root, node.lft', 'ASC')
->getQuery()
;
$nodes = $query->getArrayResult();
[Do magic here]
$tree = $pagerepo->buildTree($nodes);
Is it possible to typecast every node into a much simpler object containing only the following property's:
id
title
a few other ints used for positioning
if I would then run that through json_encode() I would have exactly what I needed.
Any other solutions are of course welcome.
my code for this purpose (just made this a few hours ago)
it's a remake of stof's buildTreeArray function
in the controller (I'm writing this for symfony2):
function gettreeAction {
$query = .... // do your query
$tree = $this->buildTree($query->getArrayResult());
$response = new Response(json_encode($tree));
return $response;
}
private function buildTree($nodes)
{
$nestedTree = array();
$l = 0;
if (count($nodes) > 0) {
// Node Stack. Used to help building the hierarchy
$stack = array();
foreach ($nodes as $child) {
$item = array();
$item['name'] = $child['title'];
$item['id'] = 'page_'.$child['id'];
$item['level'] = $child['level'];
$item['children'] = array();
// Number of stack items
$l = count($stack);
// Check if we're dealing with different levels
while($l > 0 && $stack[$l - 1]['level'] >= $item['level']) {
array_pop($stack);
$l--;
}
// Stack is empty (we are inspecting the root)
if ($l == 0) {
// Assigning the root child
$i = count($nestedTree);
$nestedTree[$i] = $item;
$stack[] = &$nestedTree[$i];
} else {
// Add child to parent
$i = count($stack[$l - 1]['children']);
$stack[$l - 1]['children'][$i] = $item;
$stack[] = &$stack[$l - 1]['children'][$i];
}
}
}
return $nestedTree;
}
works perfectly with jqTree...
I have solved it as following:
public function getPageTreeAction() {
$pagerepo = $this->getDoctrine()->getRepository('MyBundle:Page');
$em = $this->getDoctrine()->getEntityManager();
$query = $em
->createQueryBuilder()
->select('node')
->from('MyCorpBundle:Page', 'node')
->orderBy('node.root, node.lft', 'ASC')
->getQuery();
$flatnodearray = $query->getArrayResult();
$flatsimplenodearray = array();
foreach ($flatnodearray as $currentNode) {
$currentSimpleNode = array();
$currentSimpleNode['id'] = $currentNode['id'];
$currentSimpleNode['lft'] =$currentNode['lft'];
$currentSimpleNode['rgt'] = $currentNode['rgt'];
$currentSimpleNode['lvl'] = $currentNode['lvl'];
$currentSimpleNode['title'] = $currentNode['title'];
$flatsimplenodearray[] = $currentSimpleNode;
}
$tree = $pagerepo->buildTree($flatsimplenodearray);
$response = new Response(json_encode($tree));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
I would use the Stofs Repository function to get the nodes in an hierarchical array:
$repo = $em->getRepository('MyBundle:Page');
$arrayTree = $repo->childrenHierarchy();
And I think there is no other solution than modify that array manually. After you have removed some properties that you dont need, you can json_encode the array and return it.