Cakephp: find in a controller using "like" inside an array of possible values - sql

The main idea of this post is that I need to combine search inside an array via "like" without doing a fetch.
In the following code I extract the zones (part of postal code) depending on session ID:
$sess_id = $this->Session->read('Auth.User');
$this->loadModel('Zone', 2);
$MyZones = $this->Zone->find('list', array('recursive' => -1, 'conditions' => array('Zone.user_id' => $sess_id['id']), 'fields' => array('Zone.zone')));
$this->set('MyZones', $MyZones);
print_r($MyZones);
//output : $MyZone = Array ( [1] => AB [2] => AL [3] => B1 )
Now that I have my array I want to look for persons who live in this zone (example his postalcode can be AB526PQ so he lives in the administrator zone)
$this->loadModel('Person', 2);
$num_persons = $this->Person->find('count', array('recursive' => -1, 'conditions' => array('Person.pc LIKE' => '%' . $MyZones)));
$this->set('num_persons', $num_persons);
I got the following error :
Notice (8): Array to string conversion [APP\Controller\ZonesController.php]
This is the generated sql query:
SELECT COUNT(*) AS `count` FROM `tn`.`personnes` AS `Personne` WHERE `Personne`.`pc` LIKE '%Array'

You will have to break your condition from
$conditions = array('Person.pc LIKE' => '%' . $MyZones);
to
foreach($MyZones as $MyZone) {
$conditions[] = array('Person.pc LIKE' => '%' . $MyZone);
}

Related

Converting SQL query to CakePHP

I have this SQL query that I need to convert to CakePHP. I used this website [http://dogmatic69.com/sql-to-cakephp-find-converter][1] that converts the code but I doesn't work in the way that I want. There is no results.
I think it is because it creates an empty array
here is the SQL code :
SELECT shops.phone1 FROM galleries , albums , shops
WHERE galleries.album_id = albums.id and albums.shop_id = shops.id and galleries.id = 210
and this is the result the website gives me :
$options = array(
'fields' => array(
'shops.phone1',
),
'joins' => array(
array(
),
),
'conditions' => array(
'Gallery.album_id = albums.id',
'albums.shop_id = shops.id',
'Gallery.id' => '210',
),
);
$data = $this->find('all', $options);
but the code doesn't work.
Any Ideas what could be wrong ?
Thanks
There are many ways to achieve this.
If you have defined your associations correctly then you can do this:
$data = $this->Shops->find('all')
->contain(['Galleries','Albums'])
->fields(['Shops.phone1'])
->where(['Galleries.id' => 210]);
Otherwise you can use custom join to generate your query:
$data = $this->Shops->find('all')
->join([
'albums' => [
'table' => 'albums',
'type' => 'INNER', // define your join type here
'conditions' => 'albums.shop_id = Shops.id',
],
'galleries' => [
'table' => 'galleries',
'type' => 'INNER', // define your join type here
'conditions' => 'galleries.album_id=albums.id',
]
])
->select(['Shops.phone1'])
->where(['galleries.id' => 210]);
Further Reading: Cakephp -> Query Builder -> Adding Joins

ProcessMaker get data from SqlServer returned error

I am going to bind a dropdown from Sql Server database in ProcessMaker DynaForm. I set up the connection and write the query. My query return data which some of them are in Persian language, so the dropdown failed to bind and Chrome Inspector shows the error:
Unexpected token ;
Whenever I changed my query in which the returned data is not in Perisan language, every thing works fine!
Even when I write a mock query such as: Select 1, N'وحید', whitout referencing any table, every thing works fine too!
How can I confugre processmaker to show the Persian language data in dropdown too?
UPDATE
I found the php class which executes the query and get the returned data. Here is the result which is returned:
Array ( [0] => 1 [1] => ��� ����� )
Array ( [0] => 2 [1] => ��� �Ә��� )
Array ( [0] => 3 [1] => ��� ������� )
Array ( [0] => 4 [1] => ������ )
Array ( [0] => 5 [1] => ��� ͘�� )
I think there is some problem with connection encoding, but I do not know how to resolve it!
Here is my connection to sql server's details:
MSSQLStatement Object ( [conn:protected] => MSSQLConnection Object ( [database:MSSQLConnection:private] => MyDB [transactionOpcount:protected] => 0 [dblink:protected] => Resource id #18 [dsn:protected] => Array ( [database] => MyDB [encoding] => utf8 [hostspec] => MyInstanceName [password] => MyPassword [phptype] => mssql [port] => [protocol] => [socket] => [username] => MyUserName ) [flags:protected] => 0 [lastQuery] => select Id, Title From MyTable ) [resultSet:protected] => [updateCount:protected] => [warnings:protected] => Array ( ) [resultClass:protected] => [stmt:protected] => [limit:protected] => 0 [offset:protected] => 0 )
Are you adding a semicolon at the end of the query?
If you checkout the ProcessMaker documentation, they indicate that when using SQL server, semicolon should not be added:

how to get result for api connecting to whoapi?

As according to the mention documentation at whoapi.com i have gone through as mention according to instruction and tried implementing the api but the variable doesn't pass from one page to other.For example i have one page which have input type and submit button then when i click submit button it should redirect to who api url and display result
http://api.whoapi.com/?domain=whoapi.com&apikey=demokey&r=blacklist
whoapi.com = name of url,demokey = key assigned by who api & blacklist = name of service of who api
guide me through the connecting protocol.
Not sure I understand the question. Using the API should be straight simple as any REST request is.
PHP example:
$domain = "whoapi.com";
$r = "blacklist";
$apikey = "demokey";
$request = "http://api.whoapi.com/?domain=$domain&r=$r&apikey=$apikey";
$output = json_decode(file_get_contents($request), true);
Resulting array with print_r($output) looks like this:
[status] => 0
[ip] => 88.198.98.181
[blacklisted] => 0
[blacklists] => Array
(
[0] => Array
(
[tracker] => invaluement.com
[blacklisted] => 0
)
[1] => Array
(
[tracker] => surbl.org
[blacklisted] => 0
)
[2] => Array
(
[tracker] => barracudacentral.org
[blacklisted] => 0
)
[3] => Array
(
[tracker] => sorbs.net
[blacklisted] => 0
)
[4] => Array
(
[tracker] => spamhaus.org
[blacklisted] => 0
)
)
Hope this helps.

PDO: Passing extra parameters to a prepared statment than needed

Can you send more parameters than needed to a prepared statement using PDO with no undesired side effects?
That mights seem like a strange question but I ask because I have 4 queries in a row which all use similar and different parameters. The relevant parts of the queries:
1st (select, different table to others):
WHERE threadID = :tid
2nd (select):
WHERE user_ID = :u_ID AND thread_ID = :tid
3rd (update if 2nd was successful):
SET time = :current_time WHERE user_ID = :u_ID AND thread_ID = :tid
4th (insert if 2nd was unsuccessful):
VALUES (:u_ID, :tid, :current_time)
Can I declare one array with the three parameters at the beginning and use it for all 4 queries?
To sort out any confusion, the queries would be executed seperately. It is the parameters variable being reused and so that would mean some queries would receive parameters they don't need. So something like:
$parameters = array(':tid' => $tid, ':u_ID' => $u_ID, ':current_time' => $time);
$1st = $db->prepare($query1);
$1st->execute($parameters);
$2nd = $db->prepare($query2);
$2nd->execute($parameters);
$3rd = $db->prepare($query3);
$3rd->execute($parameters);
$4th = $db->prepare($query4);
$4th->execute($parameters);
If I can, should I? Will this slow down or cause security flaws to my database or scripts?
If I can make this question a bit clearer, please ask.
Thank you!
Perhaps the documentation has been updated since this question was first asked, but now it is quite clearly stated "No"
You cannot bind more values than specified; if more keys exist in input_parameters than in the SQL specified in the PDO::prepare(), then the statement will fail and an error is emitted.
These answers should be useful in filtering out the extra parameters.
I know this is already answered and it's only asking about whether you can send extra params, but I thought people might arrive at this question, and want to know how to get around this limitation. Here's the solution I use:
$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
$1st = $db->prepare($query1);
$1st->execute(array_intersect_key($parameters, array_flip(array('tid'))));
$2nd = $db->prepare($query2);
$2nd->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid'))));
$3rd = $db->prepare($query3);
$3rd->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid', 'current_time'))));
$4th = $db->prepare($query4);
$4th->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid', 'current_time'))));
That array_interset_key and array_flip maneuver could be extracted to its own function, like:
function filter_fields($params,$field_names) {
return array_intersect_key($params, array_flip($field_names))
}
I just haven't got around to it yet.
The function flips your array of key names, so you have an array with no values, but the right keys. Then intersect filters the first array so you only have the keys that are in both arrays (in this case, only the ones in your array_flipped array). But you get the values for the original array (not the empties). So you make one array of parameters, but specify which params are actually sent to PDO.
So, with the function, you'd do:
$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
$1st = $db->prepare($query1);
$1st->execute(filter_fields($parameters, array('tid')));
$2nd = $db->prepare($query2);
$2nd->execute(filter_fields($parameters, array('u_ID', 'tid')));
$3rd = $db->prepare($query3);
$3rd->execute(filter_fields($parameters, array('u_ID', 'tid', 'current_time')));
$4th = $db->prepare($query4);
$4th->execute(filter_fields($parameters, array('u_ID', 'tid', 'current_time')));
If you have PHP 5.4, you can use the square bracket array syntax, to make it even cooler:
$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
$1st = $db->prepare($query1);
$1st->execute(filter_fields($parameters, ['tid']));
$2nd = $db->prepare($query2);
$2nd->execute(filter_fields($parameters, ['u_ID', 'tid']));
$3rd = $db->prepare($query3);
$3rd->execute(filter_fields($parameters, ['u_ID', 'tid', 'current_time']));
$4th = $db->prepare($query4);
$4th->execute(filter_fields($parameters, ['u_ID', 'tid', 'current_time']));
I got a chance to test my question, and the answer is you cannot send more parameters than the query uses. You get the following error:
PDOException Object
(
[message:protected] => SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
[string:Exception:private] =>
[code:protected] => HY093
[file:protected] => C:\Destination\to\file.php
[line:protected] => line number
[trace:Exception:private] => Array
(
[0] => Array
(
[file] => C:\Destination\to\file.php
[line] => line number
[function] => execute
[class] => PDOStatement
[type] => ->
[args] => Array
(
[0] => Array
(
[:u_ID] => 1
[:tid] => 1
[:current_time] => 1353524522
)
)
)
[1] => Array
(
[file] => C:\Destination\to\file.php
[line] => line number
[function] => function name
[class] => class name
[type] => ->
[args] => Array
(
[0] => SELECT
column
FROM
table
WHERE
user_ID = :u_ID AND
thread_ID = :tid
[1] => Array
(
[:u_ID] => 1
[:tid] => 1
[:current_time] => 1353524522
)
)
)
)
[previous:Exception:private] =>
[errorInfo] => Array
(
[0] => HY093
[1] => 0
)
)
I don't know a huge amount about PDO, hence my question, but I think that because :current_time is sent but not used and the error message is "Invalid parameter number: parameter was not defined" you cannot send extra parameters which are not used.
Additionally the error code HY093 is generated. Now I can't seem to find any documentation explaining PDO codes anywhere, however I came across the following two links specifically about HY093:
What is PDO Error HY093
SQLSTATE[HY093]
It seems HY093 is generated when you incorrectly bind parameters. This must be happening here because I am binding too many parameters.
executing different type of multiple queries with one execute leads to problems. you can run multiple selects or multiple updates with one execute. For this case to create different prepared statements objects and pass the the parameters accordingly.
// for WHERE threadID = :tid
$st1 = $db->prepare($sql);
$st1->bindParam(':tid', $tid);
$st1->execute();
or
$st1->execute(array(':tid'=>$tid);
// for WHERE user_ID = :u_ID AND thread_ID = :tid
$st2 = $db->prepare($sql);
$st2->bindParam(':u_ID', $u_ID);
$st2->bindParam(':tid', $tid);
$st2->execute();
or
$st2->execute(array(':tid'=>$tid, ':u_ID' => $u_ID);
// for SET time = :current_time WHERE user_ID = :u_ID AND thread_ID = :tid
$st3 = $db->prepare($sql);
$st3->bindParam(':u_ID', $u_ID);
$st3->bindParam(':tid', $tid);
$st3->bindParam(':current_time', $current_time);
$st3->execute();
or
$st3->execute(array(':tid'=>$tid, ':u_ID' => $u_ID, ':current_time' => $current_time);
// for VALUES (:u_ID, :tid, :current_time)
$st4 = $db->prepare($sql);
$st4->bindParam(':u_ID', $u_ID);
$st4->bindParam(':tid', $tid);
$st4->bindParam(':current_time', $current_time);
$st4->execute();
or
$st4->execute(array(':tid'=>$tid, ':u_ID' => $u_ID, ':current_time' => $current_time);

converting sql query into cakephp format

Hi
i need the following sql query into cakephp find() format. the query it self is working fine but i need to change it.
$this->Part->query(
"SELECT `parts`.`id`,`parts`.`part_name`
FROM `parts`
LEFT JOIN (
SELECT `op` . *
FROM `order_parts` AS `op`
WHERE `op`.`order_id` =".$this->Session->read('orderid')."
) AS `vT`
ON ( `parts`.`id` = `vT`.`part_id` )
WHERE `vT`.`part_id` IS NULL"
);
thanks
If your relationship are Order HABTM Part and you have a table orders_parts with columns: id, order_id,part_id you should be able to do something like this:
First, get the ids of the parts which are in the order:
//each Part has one OrdersPart per order
$this->Part->bindModel(array('hasOne' => array('OrdersParts')));
$parts = $this->Part->find('list', array(
'fields' => array('Part.name'),
'conditions' => array(
'OrdersParts.order_id' => $this->Session->read('orderid'),
),
'recursive' => 2
));
Now get the parts which are not in the order:
$this->Part->find('all', array(
'conditions' => array(
"NOT" => array('Part.id' => array_keys($parts))
),
));