Zend_Db fetchAll() to return values as keys, not as key => value - zend-db

Is there a way to change the default functionality in Zend_Db fetchall() method, so that it doesn't return this:
[0] => 100000055944231
[1] => 100000089064543
[2] => 100000145893011
[3] => 100000160760965
but this:
[100000055944231]
[100000089064543]
[100000145893011]
[100000160760965]

Although your question is actually flawed (noted by BartekR), I suppose you're trying to receive a simple array, instead of a multidimensional one.
You could do:
$results = $this->db->fetchAll($select);
$values = array_map(function($row) { return $row['column']; }, $results);
This will turn:
array(
array('column' => 'test'),
array('column' => 'test2'),
array('column' => 'test3'),
);
into
array(
'test',
'test2',
'test3'
);
(note; my example only works in PHP5.3+, if you're working with PHP5.2, you can define the function and use it by its name with array_map (e.g. array_map('methodName', $results))

I'm looking for a similar solution, I'm trying to load a field returned by the fetchAll($select) as the array key.. Without looping through the entire resultset.
So:
$results = $this->db->fetchAll($select, <FIELDNAME_TO_MAKE_KEY_OF_RESULTS_ARRAY>);
results[<my fieldname>]->dbfield2;

Further to Pieter's, I'd add the case where the rows are themselves arrays, and not just scalars; it's possible to nest the results, to as many fields as the query contains.
e.g. Here with two levels of nesting, respectively on field1 and field2.
$complex_results = array_map(function($row) { return array($row['field1'] => array($row['field2'] => $row)); }, $results);
As always, each row contains all fields, but $complex_results is indexed by field1, then field2 only.

Related

Laravel multiple where clauses in query from given array

I hope the title describes my problem good as enough.
I tried to make a geosearch-function in laravel. The queries as its own are correct. Now I try to get all articles from my table, whose match with the gotten zipcode of a former query. All functions I use you can found here: Laravel 5 add results from query in a foreach to array). But now I want to perform one query, within multiple or dynamic where clauses (with or).
The print_r($zipcodes) of my former query (get all zipcodes in a range from a zipcode $zipcodes = $this->getZipcodes($zipCoordinateId, $distance);) outputs:
Array
(
[0] => stdClass Object
(
[zc_zip] => 13579
[distance] => 0
)
[1] => stdClass Object
(
[zc_zip] => 12345
[distance] => 2.228867736739
)
[2] => stdClass Object
(
[zc_zip] => 98765
[distance] => 3.7191570094844
)
)
So how should my query in laravel should look, when I want to perform following?
SELECT *
FROM articles
WHERE zipcode = '13579'
OR zipcode = '98765'
OR zipcode = '12345';
Thank you in advance,
quantatheist
UPDATE
With the solution from balintant this is working fine. Here is my code:
// grabs all zipcodes matching the distance
$zipcodes = $this->getZipcodes($zipCoordinateId, $distance);
foreach ($zipcodes AS $key=>$val)
{
$zipcodes[$key] = (array) $val;
}
$codes = array_column($zipcodes, 'zc_zip');
$articles = Article::whereIn('zipcode', $codes)->get();
return view('pages.intern.articles.index', compact('articles'));
You can use both the whereIn and orWhere scopes. The first one better fits to your current example. Also, you can use array_column to get all the real zip codes from the array above.
$query->whereIn('zip', [12,34,999])->get();
// > array
Update:
When you want to use array_column to get the specific subvalues of the array (like zc_zip) you must first transform it's childs to an array. If it's a model you must transform it easily with toArray().
$zip_objects = [
(object) [ 'zc_zip' => 13579, 'distance' => 0 ],
(object) [ 'zc_zip' => 12345, 'distance' => 2.228867736739 ],
(object) [ 'zc_zip' => 98765, 'distance' => 3.7191570094844 ],
];
foreach ( $zip_objects AS $key=>$val )
{
$zip_objects[$key] = (array) $val;
}
$zip_codes = array_column($zip_objects, 'zc_zip');
var_dump($zip_codes);
// > array(3) {
// > [0]=>
// > int(13579)
// > [1]=>
// > int(12345)
// > [2]=>
// > int(98765)
// > }

Problems returning result of CDbCriteria based query

I have a query as follows
$criteria1 = new CDbCriteria();
$criteria1->condition = 'id = 1';
$modelA=Table1::model()->find($criteria1);
I can pass it to a view and return the title and entry
$this->widget('bootstrap.widgets.TbBox', array(
title' => $modelA['title'],
'content' => $modelA['entry'] ));
Now I'd like to return a range of entries
$criteria2 = new CDbCriteria();
$criteria2->condition = 'id > 7';
$modelB=Table1::model()->findAll($criteria2);
(btw : I'm following a form as laid out here). I was expecting to be able to read the resulting array of values out as below, but ['title'] is now being seen as a undefined index (obviously I'm expecting to read this out in a loop but you get the point)
$this->widget('bootstrap.widgets.TbBox', array(
'title' => $modelB['title'][0],
'content' => $modelB['entry'][0]));
Where am I going wrong?
Thanks
No, the indexes should be specified in the different order: the number of a specific element first, then the name of the property. Additionally, it's better (=cleaner) to name the result of findAll so it'll show you (and any other reader) that it's a collection, not a single model:
$models = Table1::model()->findAll($criteria2);
// ...
$this->widget('bootstrap.widgets.TbBox', array(
'title' => $models[0]['title']
//...
));
But even that's not necessary if you use foreach (and you probably will):
foreach ($models as $model):
// ...
$this->widget('some.name', array(
'title' => $model['title']
);
endforeach;

How do I apply a CDataColumn filter to my CGridView so it displays only rows with a null-value?

I have a model with a boolean value, generated from a table like this:
CREATE TABLE receivable (
...
is_paid INTEGER DEFAULT NULL,
...
)
You should only take notice of the possible NULL value.
I have a gii-generated Receivable.php-model and a simple CGridView, like this:
$dataProvider = $model->search();
$dataProvider->pagination = ['pageSize'=>20];
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'filter'=>$model,
'columns'=>array(
'id',
[
'name'=>'is_paid',
'type'=>'raw',
'value'=>'($data->is_paid==1)?"PAID":"";',
'filter'=>['1'=>'PAID', '0'=>'0']
],
'someothercolumn',
['class'=>'CButtonColumn']
),
);
It should make sense so far? It does work fine I must say, with just one tiny problem - I want to allow filtering on null values as well!
'filter'=>['1'=>'PAID', '0'=>'0', null=>'null'] // This shows all records.
'filter'=>['1'=>'PAID', '0'=>'0', ''=>'null'] // This also shows all records.
'filter'=>['1'=>'PAID', '<>1'=>'null or zero'] // This shows 0-records only.
Well, now I'm at a loss. Is there any way I can use the CDataColumn.filter to allow the user to filter on null values? (Only display rows where 'is_paid'==null)
Edit: Values can be 1,0 or NULL, but the filter can only be applied for 1 or 0 (or show everything). How can I let the user display rows with null-values only?
Any help is much appreciated!
this is one way you can do it
1.'filter' => array('0' => Yii::t('app', 'No'), '1' => Yii::t('app', 'Yes')),
or something like this
2.is_paid:boolean
or something like this
3.'filter' => CHtml::listData(UserRegistry::model()->findAll(), 'id_user_registry', 'firstname' ),
In the above example i have the values in a db table
or something like this
4.'filter' => Lookup::items('option'),
and for the above example in the model you would have something like this
4. public static function items($type, $code)
{
if(!isset(self::$_items[$type]))
self::loadItems($type);
return isset(self::$_items[$type][$code]) ? self::$_items[$type][$code] : false;
}
private static function loadItems($type)
{
self::$_items[$type]=array();
$models=self::model()->findAll(array(
'condition'=>'type=:type',
'params'=>array(':type'=>$type),
//'order'=>'position',
));
foreach($models as $model)
self::$_items[$type][$model->code]=$model->name;
}

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

SugarCRM - Add leads with auto-incremented ID

I use the SOAP API to add new leads to SugarCRM. Additionally, I use a plugin to assign an auto-incremented lead ID whenever a new lead is created (http://www.sugarforge.org/projects/autoincrement/).
Now, the plugin works fine, if I create a new lead via frontend. But, if I use the SOAP API, the function from the module, which assigns the auto-increment ID to the lead, does not trigger.
I create the lead via
$module = 'Leads';
$params = array(
'session' => $session,
'module_name' => $module,
'name_value_list' => array(
array('name' => 'id', 'value' => ''),
//array('name' => 'int_lead_id_c', 'value' => ''),
array('name' => 'first_name', 'value' => $_POST["first_name"]),
array('name' => 'last_name', 'value' => $_POST["last_name"]),
array('name' => 'phone_home', 'value' => $_POST["phone"]),
array('name' => 'email1', 'value' => $_POST["email"]),
array('name' => 'assigned_user_id', 'value' => '1'),
)
);
//Create the Lead record
$lead_result = $soapclient->call('set_entry', $params);
The function in the module is this one:
class SugarFieldAutoincrement extends SugarFieldBase {
/**
* Override the SugarFieldBase::save() function to implement the logic to get the next autoincrement value
* and format the saved value based on the attributes defined for the field.
*
* #param SugarBean bean - the bean performing the save
* #param array params - an array of paramester relevant to the save, most likely will be $_REQUEST
* #param string field - the name of the field
*/
public function save(&$bean, $params, $field, $properties, $prefix = '') {
}
}
How can I make sure, that this function is also triggered, when adding leads via SOAP API?
Thanks a lot for your help! :-)
David
You would need to set the field type to 'autoincrement' and the dbType to 'int' in the vardef record for the field.
If I'm not mistaken, the Database has a UUID() trigger on insert for most tables, so you should be able to completely remove the id field.
If you want to trigger the function before saving, you can use beforeSave logic hook.