Is it possible to craft a wildcard WHERE query with Doctrine, like so:
->where('this_field = ?', ANYTHING);
I'd be using this to build a search query dynamically out of unknown user-selected parameters and therefore would need to have the condition in place but capable of accepting the value "anything".
To add, I can get this to work:
$field = 'this_field = ?';
$value = 5;
...
->where($field, $value);
... but it's still doesn't allow me to use "anything" as value or to eliminate the entire query condition. The following fails:
$field = NULL;
$value = NULL;
...
->where($field, $value);
Thanks
If you build the query dynamically you can also check wther $value has a value or not and then add the where part if necessary. E.g.
$q; // Your query object.
if(isset($value)) { // or empty() or maybe just if($value) depending on your needs.
$q->where('this_field = ?', $value);
}
This is easier to understand and easier to debug imo.
[Answer to own question]
After playing around with this, found a solution that works, posting here for others.
Using ->whereIn allows Doctrine to ignore a query condition completely:
$empty = array();
...
->andWhereIn('this_field', $empty)
The above condition doesn't get included in the resulting SQL at all.
Related
http://example.com/api/transfer/transfers/code/456/code/234
When using $this->get('code') on a url like above I expect the REST library to return an array or a list of the codes.
Instead it returns the last one.
Is there a way to return both values in a list, or is there another recommandation for formating the URL.
Thank you
I know it has been long since you posted the question. However it could help other people looking for the same thing.
Assuming that transfer is your controller and transfers is the function, another way to format your url could be:
http://example.com/api/transfer/transfers?code[]=456&code[]=234
This was you perform $this->get('code') you'll get an array back.
If you are creating the url via code then you may use http_build_query(). It handles the necessary escaping. It means it will replace [ for %5B and ] for %5D, in this case.
The code would be like:
$codes = array(456, 234);
$query = http_build_query(array('code' => $data));
$url = 'http://example.com/api/transfer/transfers?' . $query;
Can any one suggest me how to write SQL query in .tpl file?
I tried to write db_query("select * from table_name "); But it is not working.
Please give me a solution to write sql query in tpl file
.tpl files are for the template layout and should not have much more logic than if a region has content. For anything requiring more logic I'd recommend either adding an applicable hook in your template.php or look into creating your own module.
What is the goal you are trying to achieve it may be solvable in another way instead of using a custom query. Likely you can create a view for your page?
Otherwise, try testing your query first through your database - if you have phpmyadmin or similar set up to see if it is actually returning a result.
And see https://api.drupal.org/api/drupal/includes!database!database.inc/function/db_query/7 for more information on how to use that particular function.
I have tried below code and getting the records
$result = db_query("SELECT * from node");
$records = $result->fetchAll();
print_r($records);
Can you check the tpl file is correct or not, OR can you share the code.
Better to write a function in your module and return the data from the query to the tpl file.
// function inside your module
function your_custom_function(){
$result = db_query("SELECT * from node");
$records = $result->fetchAll();
retun $records;
}
Then you can call this function from tpl file
// calling the function from tpl
$data = your_custom_function();
foreach($data as $value){
// do your template logic here
}
CakePHP's Model::afterFind() callback looks like:
afterFind(array $results, boolean $primary = false)
According to the documentation:
The $primary parameter indicates whether or not the current model was the model that the query originated on or whether or not this model was queried as an association. If a model is queried as an association the format of $results can differ.
They can differ, but experimentation shows that they don't always differ. As far as I can tell, the $primary parameter isn't actually all that useful. If it's set to false you may or may not get a flattened data structure, so you may or may not wind up with the dreaded "cannot use string offset as an array" error message.
Although I haven't tried it yet, my thought based on the documentation was to ignore the $primary flag altogether and just check the data:
public function afterFind($results, $primary = false) {
if (array_key_exists(0, $results) {
// operate on $results[0]['User']['fieldname']
} else {
// operate on $results['fieldname']
}
return $results;
}
This is hackish and I don't like it, but it seems likely to be more useful than $primary.
Explicitly stated, my questions are:
What is the $primary flag actually useful for?
Am I correct that it is not useful for determining the structure of the $results array, or have I missed something there?
Indeed the $primary parameter seems to only be useful in warning you of cases where the format of $results is unpredictable. It is not useful in determining the format of $results.
More information here: https://groups.google.com/forum/?fromgroups=#!topic/cake-php/Mqufi67UoFo
The solution offered there is to check !isset($results[$this->primaryKey]) to see what format $results is. This is also a bit of a hack, but arguably better than checking for a key '0'.
The solution I ultimately came up with is to do something like this:
public function afterFind($results, $useless) {
// check for the primaryKey field
if(!isset($results[$this->primaryKey])) {
// standard format, use the array directly
$resultsArray =& $results;
} else {
// stupid format, create a dummy array
$resultsArray = array(array());
// and push a reference to the single value into our array
$resultsArray[0][$this->alias] =& $results;
}
// iterate through $resultsArray
foreach($resultsArray as &$result) {
// operate on $result[$this->alias]['fieldname']
// one piece of code for both cases. yay!
}
// return $results in whichever format it came in
// as but with the values modified by reference
return parent::afterFind($results, $useless);
}
This reduces code duplication because you don't have to write your field alteration logic twice (once for an array and once for non-array).
You may be able to avoid the references stuff altogether by just returning $resultsArray at the end of the method, but I wasn't sure what issues that might cause if CakePHP (or some other parent class) expects $results in the way it was passed in. Plus this way doesn't have the overhead of copying the $results array.
If you can't always rely on primaryKey being in the fields list AND you know the key you are looking for, you can get away with something a bit more simple. Here is an example:
/**
* Decrypt password
*
* #see Model::afterFind()
*/
public function afterFind($results, $primary = false) {
if (!empty($results['password'])) {
$results['password'] = Security::rijndael($results['password'], Configure::read('encrypt.key'), 'decrypt');
return $results;
}
foreach ($results as &$r) {
if (!empty($r[$this->alias]['password'])) {
$r[$this->alias]['password'] = Security::rijndael($r[$this->alias]['password'], Configure::read('encrypt.key'), 'decrypt');
}
}
return $results;
}
I ran into this issue. The accepted answer works good. However, I had to make a minor adjustment. If you're looking to modify a field for example construct a fully qualified file name from logo, it's better to create a new field, as "return parent::afterFind($results, $useless);" will do it twice if the model find is called from some other model.
foreach($resultsArray as &$result) {
// operate on $result[$this->alias]['fieldname']
// one piece of code for both cases. yay!
// Added logoFull instead of modifying logo
if(isset($result[$this->alias]['logo'])){
$result[$this->alias]['logoFull'] = Configure::read('urlImg') . 'logos' . DIRECTORY_SEPARATOR .
'carrier' . DIRECTORY_SEPARATOR . $result[$this->alias]['logo'];
}
}
Answers in the book...
The $primary parameter indicates whether or not the current model was
the model that the query originated on or whether or not this model
was queried as an association. If a model is queried as an association
the format of $results can differ;
Code expecting $primary to be true will probably get a "Cannot use
string offset as an array" fatal error from PHP if a recursive find is
used.
Thus it could be useful in certain situations for logic processing and may could be used to have a knock on effect into your $results
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
->entityCondition('bundle', 'exclusion_lists');
$entity_type = 'node';
$result = $query->execute();
if (!empty($result[$entity_type])) {
$entities = entity_load($entity_type, array_keys($result[$entity_type]));
}
var_dump($entities->field_first_name);
The concept: essentially I take a CSV file, Upload it, Read the contents to an array, get all the first and last names from the exclusion_lists content type, and then scrub it. I can't seem to get anything out of the $entities variable. I'm sure it's just sleep deprivation, etc that's getting to me, but I can't seem to figure this out.
Instead you var_dump($entities) variable to see the structure of the array. Then probably you need to use field_get_items to get the value of the particular field.
I'm using symfony 1.3 with Propel 1.4. I need to use a prepared query that will be used inside a loop changing the values of bound parameters.
Is it possible to do this with Propel 1.4? I want to retrieve results as objects so don't want to use raw SQL if I can help it.
Propel does not seem to support this out of the box. Take one of the examples, the Book class. BookPeer::doSelect() calls BookPeer::doSelectStmt() and passes the result to BookPeer::populateObjects(). BookPeer::doSelectStmt() calls BasePeer::doSelect(), which always calls BasePeer::createSelectSql() to create the SQL statement, prepares it, and passes it to BasePeer::populateStmtValues() to actually bind the values.
You can take code from these methods to get something like this (without exception or transaction handling):
$criteria = new Criteria();
$criteria->addThis();
$criteria->addThat();
$con = Propel::getConnection($criteria->getDbName(), Propel::CONNECTION_READ);
$params = array();
$sql = BasePeer::createSelectSql($criteria, $params);
$stmt = $con->prepare($sql);
// $stmt is a prepared PDOStatement
// $params is an array of the form: [{'table': 'tableName', 'column': 'columnName', 'value': 'paramValue'}, ...]
// You can keep this format and use BasePeer::populateStmtValues(), or you can call $stmt->bindParam() yourself
// Now in the loop, we set the params ourself
foreach ($loop as $loopData) {
// Bind the params, using your preferred method
// ...
// Pass the prepared and bound statement to populateObjects()
$books = BookPeer::populateObjects($stmt);
// Do something with the found objects
// ...
}