Execute params with doctrine using named parameters - php

I'm encountering a strange problem with doctrine and named parameters.
Here is a query which actually works perfectly with this set of parameters (dynamic in my code):
$params = array( ':id_editeur' => 1,
':nom_editeur' => 'Test');
public function updateById($params)
{
Doctrine_Query::create()
->update('Editeur e')
->set('e.nom_editeur', ':nom_editeur')
->where('e.id_editeur = :id_editeur')
->execute($params);
}
Now i have another function
public function findAll($params)
{
$query = Doctrine_Query::create()
->from('Editeur e')
->orderBy(':orderby')
->limit(':limit')
->offset(':offset');
return $query->execute($params);
}
With these parameters:
$params = array( ':orderby' => ('e.id_editeur ASC'),
':limit' => (10),
':offset' => (20));
And even if it's the same mechanism i get the following error
Invalid parameter number: number of
bound variables does not match number
of tokens
Any idea of the reason? By the way, it works if I fill the orderby, limit and offset directly in the function in the classical way.

The params var cannot contain ":" character...
Try replacing:
$params = array( ':id_editeur' => 1,
':nom_editeur' => 'Test');
to:
$params = array( 'id_editeur' => 1,
'nom_editeur' => 'Test');

Try remove the parenthesis in params array.
$params = array( ':orderby' => 'e.id_editeur ASC',
':limit' => '10',
':offset' => '20');

Related

CakePHP 3: How to use custom pagination?

I don't succeed in using the pagination with a custom query. I follow exactly what's in the doc, but it doesn't work. The point is to paginate a list of records, having the flag 'valid' to 'Y' or 'N'.
In the controller:
if (!isset($this->request->query['valid']) || $this->request->query['valid'] == '')
$allFilters['valid'] = 'N';
else
$allFilters['valid'] = 'Y';
$this->paginate = ['finder' => ['curnames' => $allFilters]];
$data = $this->paginate($this->Names)->toArray();
In the model:
public $paginate = ['finder' => 'curnames', 'limit' => 25, 'order' => ['Names.id' => 'asc']];
public function findCurnames(Query $query, array $options) {
$query->where([
'valid' => $option['valid']
]);
return $query;
}
When I execute the code, I get a Cake\Network\Exception\NotFoundException exception. What I am missing?
Update: The version is 3.3. The error is triggered when this is executed:
$data = $this->paginate($this->Names)->toArray();
Update : In the controller, I've change the line
$this->paginate = ['finder' => ['curnames' => $allFilters]];
to
$paginate = ['finder' => ['curnames' => $allFilters]];
and the error doesn't pop up anymore. But the condition filtering on the 'valid'='Y' or 'N' is not taken into account. So it still doesn't work.
I got the answer. The error comes from a typo. Correct code should be
'valid' => $options['valid']
Options with a 's'.
Now it works.
Isn't it easier to do something like this (without any custom finder method):
if ($this->request->getQuery('valid', '') == '')
$valid = 'N';
else
$valid = 'Y';
$this->paginate = [
'limit' => 25,
'order' => ['Names.id' => 'asc']
];
$query = $this->Names->find('all')
->where([
'valid' => $valid
]);
$data = $this->paginate($query)->toArray();

Two variables set to null inside ( ) of function

In my model I have this
function pieChart($conditions = null) {
//Get Data for PieChart
$this->RecordDrug->virtualFields['sum'] ='COUNT(*)';
$records = array();
$records=$this->RecordDrug->find('list',
array(
'conditions' => $conditions,
'fields' => array( 'Drug.drug', 'sum'),
'order' => array('sum' => 'desc'),
'contain' => array( 'Drug', 'Record' ),
'group' => 'Drug.Drug'
));
return $records;
}
Which basically means that when this function is called by it's self, there are no conditions set. So inside my controller, I am able to define a condition, if i'd like. I want to do the exact same thing except with
'limit' => $limit,
and I assume I need to set
$limit = null
Inside the parenthesis of the function. I've tried & and , and $limit,$conditions = null
but neither of these options worked. I am not too experience with OOP but I assume there is a way to do this?
EDIT:
Updated code, Still not working. The first varialbe that comes inside the functions parenthesis is the one that works, the second one just act's like it's not there
Model:
function pieChart($limit = null, $conditions = null) {
//Get Data for PieChart
$this->RecordDrug->virtualFields['sum'] ='COUNT(*)';
$records = array();
$records=$this->RecordDrug->find('list',
array(
'conditions' => $conditions,
'fields' => array( 'Drug.drug', 'sum','Record.unit'),
'order' => array('sum' => 'desc'),
'limit' => $limit,
'contain' => array( 'Drug', 'Record' ),
'group' => 'Drug.Drug'
));
debug($records);
return $records;
}
Controller:
$conditions = array('Record.user_id' => $this->Session->read('Auth.User.id'));
$pieChart = $this->Record->pieChart($conditions);
$this->set('output',$pieChart);
Even after this conditions variable, it does not only load the users data. If I were to remove '$limit = null' it will work as intended.
This way:
function pieChartTwo($limit = null, $conditions = null) {
...
}

ZF2: How to pass parameters to forward plugin which I can then get in the method I forward them to?

I have an Action method in Foo Controller which requires parameters:
public function fooAction($one, $two) {
$a = one;
$b = $two;
}
And I need to forward to that method from the other method of some Boo Controller. And one of those parameters has to be by reference parameter. The only example that the manual has is this:
$result = $this->forward()->dispatch('Boo\Controller\Boo', array('action' => 'boo'));
No any additional parameters. But they write:
$params is an optional array of parameters with which to see a
RouteMatch object for purposes of this specific request.
So, I tried:
$result = $this->forward()->dispatch('Boo\Controller\Boo', array(
'action' => 'boo',
'one' => &$one,
'two' => $two,
));
But it doesn't work.
Is there any way to pass additional parameters to forward controller?
UPD:
These do not work too:
$result = $this->forward()->dispatch('Boo\Controller\Boo', array(
'action' => 'boo',
'params' => array(
'one' => &$one,
'two' => $two,
)));
$result = $this->forward()->dispatch('Boo\Controller\Boo', array(
'action' => 'boo',
'options' => array(
'one' => &$one,
'two' => $two,
)));
UPD 2:
I still can't get the functionality I want (to pass parameters with the forward plugin) but I found other solutions. Before calling the forward plugin I set the variables to the Request object and after the forward I get them from the Request in my boo Action of my Boo\Controller\BooController:
// in Foo::fooAction
$this->getRequest()->one = &$one;
$this->getRequest()->two = $two;
$result = $this->forward()->dispatch('Boo\Controller\Boo', array('action' => 'boo'));
// in Boo::booAction
$a = $this->getRequest()->one;
$b = $this->getRequest()->two;
Stupid solution, it will not work with Ajax requests. Still interested how to pass parameters with the forward plugin. OR MAYBE how to get them in the booAction. Because there in no anything in the Request if I pass them with the forward.
UPD 3 and Final:
I finally found where they've decided to hide parameters I pass with the forward plugin. They put them in the RouteMatch object.
- Tryyyy to guess where we've hidden your params... Oh yeeah, they are in the RouteMatch, of course they are there, didn't you think smth else?
And NO ANY info in the forward plugin section of the manual!
To get params, I have to do this in my BooController::booAction:
$param = $this->getEvent()->getRouteMatch()->getParam('nameOfParam');
Why not to use the params plugin?
This works for me:
public function indexAction() {
$object = new SomeObject();
return $this->forward()->dispatch('Application\Controller\Index', [
'action' => 'show',
'myObject' => $object,
]);
}
public function showAction() {
$object = $this->params('myObject');
var_dump($object);
return [];
}
You can create a container class and use it in both controllers
in module.conf
public function getServiceConfig()
{
return array(
'invokables' => array(
'my_handy_container' => 'path\container_class_name',
)
);
}
Create a getter in both controllers:
public function getMyHandyContainer()
{
if (!$this->myHandyContainer) {
$this->myHandyContainer = $this->getServiceLocator()->get('my_handy_container');
}
return $this->myHandyContainer;
}
And call it using:
$myContainer = $this->getMyHandyContainer()->myHandyContainer;
$myContainer->foo = 5; // set something
ZF2 way to pass vars using forward
In the passing method do:
return $this->forward()->dispatch('controller_name', [
'action' => 'whatever',
'varname' => $value,
'varname2' => $value2
]);
In the invoked controller method, do:
$param2 = $this->params()->fromRoute('varname2',false);
Thought I would add another option that works for me.
You can simply pass the params straight through the forward function and use the routeMatch function to access them at the other end.
return $this->forward()
->dispatch('Module\Controller\Foo', array(
'action' => 'bas',
'id' => 6)
);
Passes to Foo Controller, basAction in this method you can then use the following code to access the id param
$myParam = (int) $this->getEvent()->getRouteMatch()->getParam('id');
Not sure if this meets your requirements - but works for me.
Thanks for the question, helped me a lot. Found an easy way for getting all params passed to forward()->dispatch(...). In the controller's action method:
$params = $this->params()->fromRoute();
returns array $data as passed as $data into forward()->dispatch($controllerName, $data).
Here in the official ZF2 documentation is written exactly how it works:
$params is an optional array of parameters with which to seed a RouteMatch object for purposes of this specific request. Meaning the parameters will be matched by their key to the routing identifiers in the config (otherwise non-matching keys are ignored).
So pass like this:
$params = array(
'foo' => 'foo',
'bar' => 'bar'
);
$this->forward()->dispatch('My\Controller', $params)
And then you can get your route match params in your My\Controller like normally:
$foo = $this->params()->fromRoute('foo');
$bar = $this->params()->fromRoute('bar');
For people struggling with accessing parameters within their controller here a nice overview from this CheatSheet.
$this->params()->fromPost('foo'); //POST
$this->params()->fromQuery('foo'); //GET
$this->params()->fromRoute('foo'); //RouteMatch
$this->params()->fromHeader('foo');//Header
$this->params()->fromFiles('foo'); //Uploaded file

CakePHP paginate and order by

It feels like I've tried everything so I now come to you.
I am trying to order my data but it isn't going so well, kinda new to Cake.
This is my code:
$this->set('threads', $this->paginate('Thread', array(
'Thread.hidden' => 0,
'Thread.forum_category_id' => $id,
'order' => array(
'Thread.created' => 'desc'
)
)));
It generates an SQL error and this is the last and interesting part:
AND `Thread`.`forum_category_id` = 12 AND order = ('desc') ORDER BY `Thread`.`created` ASC LIMIT 25
How can I fix this? The field created obviously exists in the database. :/
You need to pass in the conditions key when using multiple filters (i.e. order, limit...). If you just specify conditions, you can pass it as second parameter directly.
This should do it:
$this->set('threads', $this->paginate('Thread', array(
'conditions' => array(
'Thread.hidden' => 0,
'Thread.forum_category_id' => $id
),
'order' => array(
'Thread.created' => 'desc'
)
)));
or perhaps a little clearer:
$this->paginate['order'] = array('Thread.created' => 'desc');
$this->paginate['conditions'] = array('Thread.hidden' => 0, ...);
$this->paginate['limit'] = 10;
$this->set('threads', $this->paginate());
if you get an error, add public $paginate; to the top of your controller.
Try
$this->set('threads', $this->paginate('Thread', array(
'Thread.hidden' => 0,
'Thread.forum_category_id' => $id
),
array(
'Thread.created' => 'desc'
)
));
I'm not a Cake master, just a guess.
EDIT. Yes, thats right. Cake manual excerpt:
Control which fields used for ordering
...
$this->paginate('Post', array(), array('title', 'slug'));
So order is the third argument.
try
$all_threads = $this->Threads->find('all',
array(
'order' => 'Threads.created'
)
);
$saida = $this->paginate($all_threads,[
'conditions' => ['Threads.hidden' => 0]
]);
There are a few things to take note of in paginate with order. For Cake 3.x, you need :
1) Ensure you have included the fields in 'sortWhitelist'
$this->paginate = [
'sortWhitelist' => [
'hidden', 'forum_category_id',
],
];
2) for 'order', if you put it under $this->paginate, you will not be able to sort that field in the view. So it is better to put the 'order' in the query (sadly this wasn't stated in the docs)
$query = $this->Thread->find()
->where( ['Thread.hidden' => 0, 'Thread.forum_category_id' => $id, ] )
->order( ['Thread.created' => 'desc'] );
$this->set('threads', $this->paginate($query)

something's wrong with my cakePHP save method

i have a method inside a model, to do a simple save (insert to database), first it finds any users which meet certain conditions, and then insert certain info to another table to each of those found users, here's the code:
function save_emails(){
App::import('Model', 'User');
App::import('Model', 'EmailSave');
$this->EmailSave = new EmailSave();
$this->User = new User();
$users = $this->User->find("all", array(
'conditions' => array(
'OR' => array(
array('User.user_type_id' => '4'),
array('User.user_type_id' => '1')
)
),
'fields' => array(
'username',
'email'
),
'recursive' => -1
));
foreach($users as $user){
//pr($user);
$to = $user['User']['email'];
$subject = $email_template['subject'];
$template = //calling a templating method;
$save_send['EmailSave']['created'] = date("Y-m-d H:i:s", time());
$save_send['EmailSave']['modified'] = date("Y-m-d H:i:s", time());
$save_send['EmailSave']['send_to'] = $to;
$save_send['EmailSave']['subject'] = $subject;
$save_send['EmailSave']['message'] = $template;
//pr($save_send);
$this->EmailSave->save($save_send);
//echo $to."<br />".$subject."<br />".$template."<br />".$cron_id."<br />";
}
}
this is pretty much straight forward, i mean i am not using any complicated methods, now when i run the find method towards user :
$users = $this->User->find("all", array(
'conditions' => array(
'OR' => array(
array('User.user_type_id' => '4'),
array('User.user_type_id' => '1')
)
),
'fields' => array(
'username',
'email'
),
'recursive' => -1
));
it returns 2 results, and when i try to print the result using cake's pr method, it would print the right results, but...if i apply the save method, it would only insert one of the result, how is that possible? i have traced the codes line by line and it went through just find, the problem is when i save them to the database, it fails to save all 2 results, please help.
http://book.cakephp.org/view/1031/Saving-Your-Data
Creating or updating is controlled by the model's id field. If $Model->id is set, the record with this primary key is updated. Otherwise a new record is created.
When calling save() in a loop, don't forget to call create().

Categories