Explanation for the use of $condition and $param in findByAttributes in Yii
In most case, this is how I use findByAttributes
Person::model()->findByAttributes(array('first_name'=>$firstName,'last_name'=>$lastName));
Copy from this thread http://www.yiiframework.com/forum/index.php/topic/21178-findbyattributes-example/
Explain what you want to do and where is your errors.
Try to read documentation http://www.yiiframework.com/doc/api/1.1/CActiveRecord#findByAttributes-detail
When you do a find in Yii's CActiveRecord using the attributes of the model, you would most likely find by some equality.
Person::model()->findByAttributes(array(
'first_name' => $firstName,
'last_name' => $lastName,
));
In English, this translates to "Find me a person whose last name is $lastname and whose first name is $firstname". But this is a bad example. Consider the following.
Person::model()->findByAttributes(array(
'age' => 18,
));
This is a better example which translates, in English, to "Fetch me all eighteen year olds" (that is, "where age = 18). This can be re-written with conditions like so
Person::model()->findByAttributes(array(
'condition' => 'age = :age',
'params' => array(
':age' => 18,
),
));
So far, there may seem to be little benefits. But such expressions make us able to use more boolean operators. For example...
Person::model()->findByAttributes(array(
'condition' => 'age < :age',
'params' => array(
':age' => 18,
),
));
...can now help us find all those below a certain age.
The query can grow as complex as you wish with $conditions and $params, but with your normal method, you may only use assignment queries.
Related
I want to find posts which have a specific post meta key/value or posts which are in a specific category. Here is the query. I want to combine the tax_query and the meta_query with OR, but AFAICS there's no way to do this.
$args = [
'post_type' => 'my-event',
'post_status' => 'publish',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
'cat' => 'home',
'tax_query' => [
[
'taxonomy' => 'event-cat',
'terms' => [
'open',
],
'field' => 'slug',
'operator' => 'IN',
'include_children' => true,
],
],
'meta_query' => [
[
'key' => 'event_author',
'value' => [1,7,11,15],
'compare' => 'IN',
],
],
];
$loop = new WP_Query($args);
Result should be:
All posts (events) which are in the category 'open' (no matter who the author is) AND all posts which are from one of the specified authors (no matter in which category the event is).
On SO I found a few similar questions and I think I have to create a SQL query to find a solution but I don't know how to do it. Hope that someone can help me here.
Thanks and best regards.
In order to make custom,unconventional and a bit complicated queries like this, you have to learn some basic SQL Syntax. Trust me, SQL basics are not so hard to learn, and they are really worth it if you consider how many projects in many different programming languages need some SQL knowledge.
WordPress gives you the option to make custom queries with wpdb::get_results() function. In case you already know how to use SQL syntax, try exploring the wordpress database a little, and you will find what table columns you need to extract to get the result you want.
I would like to use an IN clause in findFirst but it doesn't seem to work?
Expected code, or something similar:
$item = Item::findFirst([
'conditions' => 'categories IN :cats: AND released < :now:',
'order' => 'id ASC',
'bind' => [
'cats' => $this->categories,
'released' => time()
],
]);
I tried using bindTypes but there's no such "list" or "array" type (also, that would get a lot more verbose than expected)...
I know I can do it through the query builder, but I was looking to keep it a bit more idiomatic:
$item = Item::query()
->inWhere('categories', $this->categories)
->andWhere('released < :now:', ['now' => time()])
->orderBy('id ASC')
->limit(1)
->execute()
->getFirst();
You can bind the array and IN clause like this:
$result = ModelName::findFirst([
'conditions' => 'id in ({cats:array})',
'bind' => array('cats' => [3, 5, 8])
]);
Note that the above example will get the first record with id 3. However if you use find() you will get the items with 3, 5 and 8.
More examples in the docs (at the bottom of this section).
I have this silverstripe query that does not work ( it outputs all messages and not the ones with the date range )
What would be the best way to tackle this query?
Im fairly new to silverstripe and havent been able to find information on how to print the raw query.
return = Message::get()
->filter(array(
'IsPublished' => true,
'StartPublication:LessThanOrEqual' => date('Y-m-d'),
'Priority' => array('High', 'Normal')
))
->where("\"StopPublication\" >= ".date('Y-m-d')." OR \"StopPublication\" IS NULL")
->sort('StartPublication', 'DESC')->limit($this->getLimit());
The correct answer is to not use where() - this is a trap method that a lot of learners fall into (presumably due to the name). It's intended basically only for very complex things that the ORM just can't handle.
You're calling filter at least, which is the correct thing. But what you want instead of where() is filterAny():
Message::get()
->filter([
'IsPublished' => true,
'StartPublication:LessThanOrEqual' => 'now',
'Priority' => ['High', 'Normal']
])
->filterAny([
'StopPublication:GreaterThanOrEqual' => 'now',
'StopPublication' => null
])
->sort('StartPublication', 'DESC')
->limit($this->getLimit());
As the other answer already specifies, do not use an = on the return (or put a $ in front of return to make it a variable), and to return the query itself use $datalist->sql() http://api.silverstripe.org/3.1/class-DataList.html#_sql
But - seeing the docs on SQLQuery is wrong, because you're not using SQLQuery. You're using the ORM, so this doc page is far more relevant: http://docs.silverstripe.org/en/3.1/developer_guides/model/data_model_and_orm/#filterany
For starts return = Message::get() its just return Message::get()
I assume that you have set php error reporting so that it outputs errors and SS is also in development mode so it won't hide error outputs.
The answer to your question is to to do either:
to output it to the output html:
Debug::dump(Message::get()
->filter(array(
'IsPublished' => true,
'StartPublication:LessThanOrEqual' => date('Y-m-d'),
'Priority' => array('High', 'Normal')
))
->where("\"StopPublication\" >= ".date('Y-m-d')." OR \"StopPublication\" IS NULL")
->sort('StartPublication', 'DESC')->limit($this->getLimit())->sql());
or output it to the project roots log file
Debug::log(Message::get()
->filter(array(
'IsPublished' => true,
'StartPublication:LessThanOrEqual' => date('Y-m-d'),
'Priority' => array('High', 'Normal')
))
->where("\"StopPublication\" >= ".date('Y-m-d')." OR \"StopPublication\" IS NULL")
->sort('StartPublication', 'DESC')->limit($this->getLimit())->sql());
See http://docs.silverstripe.org/en/developer_guides/model/sql_query/
My title will look like naive but I have to say I read/searched/tested everything possible, but my find() method don't implement the JOIN to related tables in the SQL query. I used it several times in other projects without problems but here...
Here my 2 models (nothing special but the manual definition of the related model) :
class Pflanzen extends AppModel {
public $useTable = 'pflanzen';
public $hasAndBelongsToMany = array(
'Herbar' => array(
'order'=>'Herbar.order ASC',
'joinTable' => 'herbar_pflanzen',
'foreignKey' => 'pflanzen_id',
'associationForeignKey' => 'herbar_id')
);
}
class Herbar extends AppModel {
public $useTable = 'herbar';
public $hasAndBelongsToMany = array(
'Pflanzen' => array('joinTable' => 'herbar_pflanzen',
'foreignKey' => 'herbar_id',
'associationForeignKey' => 'pflanzen_id')
)
}
Here my query in the "Herbar" controller (can't be more normal...) :
$pflanzen = $this->Herbar->Pflanzen->find('all',array(
'fields'=>array('Herbar.name','Pflanzen.linkplatter'),
'conditions' => array('Pflanzen.linkplatter' => true),
'order' => 'Herbar.name',
'limit' => 10,
'recursive'=>2)
);
$this->set('pflanzen',$pflanzen);
and the resulting error in the view :
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Herbar.name' in 'field list'
SQL Query: SELECT `Herbar`.`name`, `Pflanzen`.`linkplatter`, `Pflanzen`.`id` FROM `burgerbib`.`platter_pflanzen` AS `Pflanzen` WHERE `Pflanzen`.`linkplatter` = '1' ORDER BY `Herbar`.`name` ASC LIMIT 10
You can see that their is no JOIN in the SQL. Why ?? What do I wrong ?
I would really appreciate your help as I'm searching for hours and do no more see any solutions and didn't find nothing using google. Thanks in advance !!
HABTM doesn't make joined queries, it makes a query for all base records and more queries as needed for each relationship to fill the array. Your condition assumes a join, hence the error.
You can force a join using the 'joins' parameter. http://book.cakephp.org/1.2/en/view/872/Joining-tables
In the End, the better way of doing this is using the containable behaviour. Force Join is only useful when the containable behavior don't respond to the need :
http://book.cakephp.org/2.0/fr/core-libraries/behaviors/containable.html#using-containable
I have the following example code:
$dataProvider = new CActiveDataProvider('firstTable',
array('criteria' => array(
'select' => 't.firstfield,secondTable.secondfield',
'join' => 'join secondTable on secondTable.id=t.secondTable_id',
),
'pagination' => array(
'pageSize' => 10,
),
));
$results=$dataProvider->getData();
After running the code above, firstField (from the model table - firstTable) is available in the object, but secondField (from the joined table - secondTable) is not.
Can anyone provide assistance on what is wrong with the code or why the "select" option is not picking up the secondField?
it would be better if you use CDbCriteria, that has a better solution to join table with the help of relations. I can show the example with CDbCriteria.
$criteria = new CDbCriteria;
$criteria->select = 'firstfield';
$criteria->with = array('secondTable_relation'=>array('select'=>'secondfield'));
$dataProvider = new CActiveDataProvider('firstTable',
array('criteria' => $criteria,
'pagination' => array(
'pageSize' => 10,
),
));
$results=$dataProvider->getData();
secondTable_relation is a relation name with secondTable.
Can anyone provide assistance on what is wrong with the code or why the "select" option is not picking up the secondField?
Answer:
That is happening because you have not selected the field which relates the two tables, i.e the foreign key in firstTable : secondTable_id. So if you do:
'select' => 't.firstfield,t.secondTable_id,secondTable.secondfield',
you will be able to access the secondField of secondTable:
$singleresultrow->secondTableRelationName['secondField'];// a single result row can be obtained by foreach iteration over $results
However there will still be another query (Lazy Loading) when you access the secondField. And the initial(before lazy) object returned will not have the secondTable object filled.
The problem i think lies in the fact that by default yii accesses the related fields by lazy loading, and for that to happen the related foreign_key should be present in the model you are trying to make a dataprovider of, here it is firstTable, and the foreign_key secondTable_id.