Doctrine2: how to remove leftJoin part of QueryBuilder - doctrine-orm

I have big fat QueryBuilder that generates sql like in this question. Apparently, all those leftJoins makes my query to crawl.
So I figured I need to fetch only the IDs that match it and later, append
$ids = $cloneOfqb->select("o.id")->resetDqlPart("join")....->getResult() ;
return $qb->andWhere("o.id IN (:ids)")->setParameter("ids", $ids)
The problem:
This would work nicely but resetDqlPart("join") removes all joins, both leftJoin and innerJoin. I use innerJoins a lot as it makes code readable. Is there a way I can reset only leftJoins but leave innerJoins? It doesn't have to be QueryBuilder object, it can be a child like Doctrine\ORM\Query if needed.

There is no way to reset only certain Joins.
I found a little discussion here, and the proposed solution (although no source code is provided) is to override the resetDqlPart() function in Doctrine's QueryBuilder.php.
Dumping $this->_dqlParts['join'] inside that function, the structure for joins appears to be the following: (my example query has an inner join and a left join, and 'e', 'ed', 'eaf' are table aliases)
array (size=1)
'e' =>
array (size=2)
0 =>
object(Doctrine\ORM\Query\Expr\Join)[666]
protected 'joinType' => string 'LEFT' (length=4)
protected 'join' => string 'e.date' (length=6)
protected 'alias' => string 'ed' (length=2)
protected 'conditionType' => null
protected 'condition' => null
protected 'indexBy' => null
1 =>
object(Doctrine\ORM\Query\Expr\Join)[654]
protected 'joinType' => string 'INNER' (length=5)
protected 'join' => string 'e.area_formativa' (length=16)
protected 'alias' => string 'eaf' (length=3)
protected 'conditionType' => null
protected 'condition' => null
protected 'indexBy' => null

You can use "getDqlPart('join')" from query builder to get applied joins, reset them via "resetDqlPart('join')" and then manually remove it from array and add it again through method "add". Not very convenient, but yet possible. Short example:
$joinDqlPart = $queryBuilder->getDQLPart('join');
$queryBuilder->resetDQLPart('join');
unset($joinDqlPart['alias'][0]);
foreach ($joinDqlPart['alias'] as $join) {
$queryBuilder->add('join', [$join->getAlias() => $join], true);
}

Related

How to update values dynamically for the individual match sections within sshd config file using puppet

i am able to update the value to the sections "User foo" and "Host *.example.net" by passing the index. If i pass index 1 or 2 the respective value is getting updated.
my code:
$sections = ['Host *.example.net', 'User foo']
$sections.each |String $section| {
sshd_config_match { "${section}":
ensure => present,
}
}
$settings = [['User foo', 'X11Forwarding yes', 'banner none'],['Host *.example.net', 'X11Forwarding no', 'banner none']]
$settings.each |Array $setting| {
$setting_array = split($setting[1],/ /)
sshd_config { "${setting_array[0]} ${setting[0]}":
ensure => present,
key => "${setting_array[0]}",
condition => "${setting[0]}",
value => "${setting_array[1]}",
}
}
current result:
Match Host *.example.net
# Created by Puppet
X11Forwarding no
Match User foo
# Created by Puppet
X11Forwarding yes
Expected results:
Match Host *.example.net
# Created by Puppet
X11Forwarding no
Banner none
Match User foo
# Created by Puppet
X11Forwarding yes
Banner none
i am able to update only one value mentioned in the index but am looking a way to update more or all the values mentioned in the list.
It's not clear what module is providing your sshd_config_match and sshd_config resource types, nor, therefore, exactly what they do. Nevertheless, if we consider this code ...
$settings = [['User foo', 'X11Forwarding yes', 'banner none'],['Host *.example.net', 'X11Forwarding no', 'banner none']]
$settings.each |Array $setting| {
$setting_array = split($setting[1],/ /)
sshd_config { "${setting_array[0]} ${setting[0]}":
ensure => present,
key => "${setting_array[0]}",
condition => "${setting[0]}",
value => "${setting_array[1]}",
}
}
... we can see that each element of $settings is a three-element array, of which the each call accesses only those at indexes 0 and 1. That seems to match up with the result you see, which does not contain anything corresponding to the data from the elements at index 2.
You could iterate over the inner $setting elements, starting at index 1, instead of considering that element only, but I would suggest instead restructuring the data more naturally, and writing code suited to the restructured data. You have data of mixed significance in your arrays, and you are needlessly jamming keys and values together such that you need to spend effort to break them back apart. Structuring the data as a hash of hashes instead of an array of arrays could be a good start:
$settings = {
'User foo' => { 'X11Forwarding' => 'yes', 'banner' => 'none'},
'Host *.example.net' => { 'X11Forwarding' => 'no', 'banner' => 'none'},
}
Not only does that give you much enhanced readability (mostly from formatting), but it also affords much greater usability. To wit, although I'm guessing a bit here, you should be able to do something similar to the following:
$settings.each |String $condition, Hash $properties| {
$properties.each |String $key, String $value| {
sshd_config { "${condition} ${key}":
ensure => 'present',
condition => $condition,
key => $key,
value => $value,
}
}
}
Again, greater readability, this time largely from a helpful choice of names, and along with it greater clarity that something like this is in fact the right structure for the code (supposing that I have correctly inferred enough about the types you are using).

cakephp 2.6 controller test case throwing MissingActionException on duplicate testAction()-call

I hope anyone can help me out with my testing environment.
my setup
I am implementing unit tests based on phpunit 3.7.22 with the cake release 2.6.9. Running on ubuntu 12.04 LTS with PHP 5.4.43-1 and postgresql 9.1.
I immplemented controller tests mocking cakes Auth Component to have a user in the session, since my tests depent on that. My controllers return json results, since its an API for a JS-based frontend. I call my controller methods using the testAction() call of a generated controller.
<?php
App::uses('RequesttypesController', 'Svc.Controller');
class RequesttypesWithResultControllerTest extends ControllerTestCase
{
public $fixtures = array(
'app.requesttype',
'app.user',
'app.privilege',
'app.groupsprivilege',
'app.groupsuser',
'app.groupscompany',
'app.company',
);
/**
* Mock the requesttype object so that it can return results depending on the desired outcome
*
* #see CakeTestCase::setUp()
*/
public function setUp()
{
parent::setUp();
$this->controller = $this->generate('Svc.Requesttypes', array(
'models' => array(
'Requesttype'
),
'components' => array(
'Auth' => array(
'user'
),
'Session',
'RequestHandler'
)
));
$this->controller->Auth->staticExpects($this->any())
->method('user')
->will($this->returnValue(array(
'id' => 123,
'username' => 'myTestUser',
'company' => 'myTestCompany',
'usertype_id' => '456',
))
);
$authResult = $this->controller->Auth->user();
}
public function tearDown()
{
parent::tearDown();
unset($this->controller);
}
/**
* A logged in user produces a number of requesttypes
*/
public function testLoggedInUser()
{
$result = $this->testAction('/svc/requesttypes/getMyRequesttypes', array('return' => 'vars'));
$this->assertNotEmpty($this->vars, 'Did not receive webservice response');
$this->assertTrue(isset($this->vars['data']['code']), 'Received invalid webservice response');
$this->assertEqual($this->vars['data']['code'], SvcAppController::RESPONSE_CODE_SUCCESS);
}
}
?>
This test passes without errors. Now I want to test my controller-action with different setups, for example users with a different usertype, from a different company, and so on. If I now create a second test-method in my RequesttypesWithResultControllerTest-class, calling the same testAction-url, i get a MissingActionException saying:
"Action RequesttypesController::() could not be found."
It seems that the testAction calls an empty controller-action, even if the action-url is passed as a parameter. I tried reinitializing the controller by nulling it and calling $this->generate() again, but this does not help either.
Of course I can help myself out by creating an own test-controller for every test ending up in a bunch of duplicate test-code, but this somehow seems not right to me.
Am I misusing the test-environment or how can this exception be explained? Any ideas?
Thanks in advance for sharing my headache!
After some further code debugging we finally found the error. We accidently changed the require statement of the last line of the /Config/routes.php file to a require_once because of some "Class already defined Exceptions" thrown in the test-environment.
Wrong routes.php:
require_once CAKE . 'Config' . DS . 'routes.php';
For the application itself that made no difference, since the routes are only needed to be initialized once per request. But in a test-environment, the routes are reinitialized several times, which was not possible anymore with the require_once include.
This is how the line is supposed to look like, which it does by default:
Correct routes.php:
require CAKE . 'Config' . DS . 'routes.php';

CakePHP reading Cookie with multiple dots

I am using CakePHP to develop a website and currently struggling with cookie.
The problem is that when I write cookie with multiple dots,like,
$this->Cookie->write("Figure.1.id",$figureId);
$this->Cookie->write("Figure.1.name",$figureName);`
and then read, cakePHP doesn't return nested array but it returns,
array(
'1.id' => '82',
'1.name' => '1'
)
I expected something like
array(
(int) 1 => array(
'id'=>'82',
'name'=>'1'
)
)
Actually I didn't see the result for the first time when I read after I write them. But from second time, result was like that. Do you know what is going on?
I'm afraid it doesn't look as if multiple dots are supported. If you look at the read() method of the CookieComponent (http://api.cakephp.org/2.4/source-class-CookieComponent.html#256-289), you see this:
277: if (strpos($key, '.') !== false) {
278: $names = explode('.', $key, 2);
279: $key = $names[0];
280: }
and that explode() method is being told to explode the name of your cookie into a maximum of two parts around the dot.
You might be best serializing the data you want to store before saving and then deserializing after reading as shown here: http://abakalidis.blogspot.co.uk/2011/11/cakephp-storing-multi-dimentional.html

Doctrine findBy with OR condition

Is it possible to use OR statement in Doctrine findBy() method?
I know that given array is interpreted as case1 AND case2...
Like this
$this->repos['notif']->findBy(array('status' => 1, 'status' => 2, 'status' => 3);
Stands for
SELECT * FROM `notif` WHERE status=1 AND status=2 AND status=3;
Now I need something to stand for:
SELECT * FROM `notif` WHERE status=1 OR status=2 OR status=3;
Is there a way to get all cases?
You can write:
$this->repos['notif']->findBy(array('status' => array(1, 2, 3)));
and that should work too.
I know that this is old question. Anyways, it's possible to use Criteria for the complex queries (in Doctrine 2 at least):
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria
->orWhere($criteria->expr()->contains('domains', 'a'))
->orWhere($criteria->expr()->contains('domains', 'b'));
$groups = $em
->getRepository('Group')
->matching($criteria);
As far as I know this is not a supported feature by Doctrine to use IN() queries with findby. You could do two things:
Implement a findByStatus(array $statusTypes) method in your (custom) 'notif' repository class. If you like this approach I can give you a example.
Convert your findBy to the following:
$qb = $this->repos['notif']->createQueryBuilder('n');
$data = $qb->where($qb->expr()->in('status', array(1,2,3)))->getQuery()->getResult();
That should work either :)
If you are using MongoDB and need more complex queries, like "less than" linked together with OR, but cannot use a query builder, this also works with this syntax:
->findBy(array(
'$or' => array(
array('foo' => array('$lt' => 1234)),
array('$and' => array(
array('bar' => 45678),
array('baz' => array('$lt' => 89013))
))
)
));
Or as a solution for your question:
->findBy(array(
'$or' => array(
array('status' => 1),
array('status' => 2),
array('status' => 3),
)
));

Symfony2, Doctrine 2: getResult Object

$posts = $em->find('Application\BlogBundle\Entity\Post',1);
print_r ($posts);
Why I got it?
Barii\BlogBundle\Entity\Post Object ( [id:Barii\BlogBundle\Entity\Post:private] => 1 [title:Application\BlogBundle\Entity\Post:private] => something [body:Application\BlogBundle\Entity\Post:private] => content )
instead of a simple array like this:
array ( [id] => 1,
[title] => "something",
[body] => "content" )
I use it with Symfony 2.
You have a couple options here. As far as I know, you can't find results as arrays from entity repositories by default. Instead, you can do one of two things:
First, you could implement a toArray() method on your entity object (perhaps through a mapped superclass) that simply returns an array of properties.
Second, you could use Doctrine Query Language to pull the information that you need using the getArrayResult() method, perhaps something like this:
$query = $em->createQuery('SELECT p FROM Application\BlogBundle\Entity\Post p WHERE p.id=:pid');
$query->setParameter('tid', $postId);
$result = $query->getArrayResult(); // shortcut for $query->getResult(Query::HYDRATE_ARRAY);
More in-depth documentation on DQL can be found here.