Multiple select DQL - symfony

I have:
if (count($data['paymentTypes'])<5) {
$arr = array();
foreach (array_values($data['paymentTypes']) as $value) { $arr[]=$value->getId(); }
$query = $query->leftJoin('p.payments','g')->where('g.id IN(:num)')->setParameter('num', $arr);
}
if (count($data['expertise']->toArray())>0) {
$arr = array();
foreach (array_values($data['expertise']->toArray()) as $value) { $arr[]=$value->getId(); }
$query = $query->leftJoin('p.expertise','g')->where('g.id IN(:num)')->setParameter('num', $arr);
}
How may I stop the query from breaking in case both statements are true? I would expect leftjoins and wheres to congregate but they throw an exception instead. What is the cleanest way of accomplishing this?

Use different alias and parameter name in the second part than in the first.

Related

Persist multiple entities in symfony2

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();

PHPUnit check method invoked multiple times with multiple parameters

I have the following class:
class Foo
{
public function importBars(array $array)
{
foreach ($array as $key => $value) {
$this->importBar($key, $value);
}
}
public function importBar($key, $value)
{
// do stuff
}
}
I need to test that importBar is called count($array) times, and that it's called with the right parameters. Using $this->at() is not an option, as the order of the $array elements might change. I have:
public function testImportBars(array $array)
{
// Mock invocation ...
$logicalOrs = array();
foreach ($array as $sku => $value) {
$logicalOrs[] = $this->logicalOr($this->equalTo($key), $this->equalTo($value));
}
$mock->expects($this->exactly(count($array)))
->method('importBar')
->with(call_user_func_array(array($this, 'logicalOr'), $logicalOrs));
}
Which passes the tests. However, when I deliberately make it fail:
foreach ($array as $sku => $value) {
$logicalOrs[] = $this->logicalOr($this->equalTo($key), $this->equalTo(null));
}
... it still passes. It only fails if the $key is incorrect:
foreach ($array as $sku => $value) {
$logicalOrs[] = $this->logicalOr($this->equalTo(null), $this->equalTo(null));
}
... which suggests PHPUnit is only checking if the first parameter passed to Foo::importBar() is correct.
Is there a way to tell PHPUnit to verify arguments to methods when there is more than one?
After some trial and error, here is the closest solution I've come up with:
$rows = array();
foreach ($array as $key => $value) {
$rows[] = array($key, $value);
}
$method = $mock->expects($this->exactly(count($array)))
->method('importBar');
call_user_func_array(array($method, 'withConsecutive'), $rows);
See: http://phpunit.de/manual/4.1/en/test-doubles.html#test-doubles.mock-objects

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;
}

Symfony2 / Typecasting query results to simpeler object

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.

symfony2 twig render, exception thrown

So in my base template, I have: {% render "EcsCrmBundle:Module:checkClock" %}
Then I created the ModuleController.php...
<?php
namespace Ecs\CrmBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Ecs\CrmBundle\Entity\TimeClock;
class ModuleController extends Controller
{
public function checkClockAction() {
$em = $this->getDoctrine()->getEntityManager();
$user = $this->get('security.context')->getToken()->getUser();
$today = time();
$start = date('Y-m-d 00:00:00');
$entities = $em->getRepository('EcsCrmBundle:TimeClock');
$query = $entities->createQueryBuilder('tc')
->select('tc.in1, tc.out1, tc.in2, tc.out2, tc.in3, tc.out3')
->where('tc.noteBy = :user')
->andWhere('tc.daydate >= :start')
->setParameter('user', $user->getid())
->setParameter('start', $start)
->setMaxResults('1')
->getQuery();
$entities = $query->getSingleResult();
if (empty($entities)) {
$ents = "clocked_out";
$this->get('session')->set('clockedin', 'clocked_out');
} else {
for ($i=1; $i <= 3; $i++) {
if ($entities["in$i"] != NULL) {
$ents = "clocked_in";
if ($i == 1) {
$this->get('session')->set('nextclock', "out$i");
} else {
$x = $i+1;
$this->get('session')->set('nextClock', "out$x");
}
if ($entities["out$i"] != NULL) {
$ents = "clocked_out";
$x = $i+1;
$this->get('session')->set('nextclock', "in$x");
}
if ($entities["out3"] != NULL) {
$ents = "day_done";
}
}
}
}
return $this->render('EcsCrmBundle:Module:topclock.html.twig', array(
'cstat' => $ents,
));
}
}
The problem is, if there is nothing in the database for the specific day for the specific user yet.. i keep getting:
An exception has been thrown during the rendering of a template ("No result was found for query although at least one row was expected.") in ::base.html.twig at line 161.
500 Internal Server Error - Twig_Error_Runtime
1 linked Exception: NoResultException ยป
I know it has something to do with the fact that is no 'result' from the database... but isn't that what i've accomplished by having the if (empty($entities)) { ?? I have no clue to fix it... any help appreciated...
Replace:
$entities = $query->getSingleResult();
With
$entity = $query->getOneOrNullResult();
If you look in Doctrine\ORM\AbstractQuery you will see that getSingleResult expects one and only one results. 0 will through an exception.
I looked at your code a bit more closely and it looks like you actually expect an array of entities. in which case use:
$entities = $query->getResult();

Resources