This is my view
'promoter_id' => [
'type' => Form::INPUT_DROPDOWN_LIST,
'options' => ['prompt' => '--'.Yii::t ( 'app', 'Ventor Type' ).'--',],
'items' => ArrayHelper::map (
User::find ()->orderBy ( 'username')->where(['user_type_id' => [13]])->asArray ()->all (),
'id',
'username'
)
]
What i did?
show the users filtered by user_type_id = 13.
user_type_id=13 means the users are promoters.
What i want?
I want to show the users like below sql query using ArrayHelper::map.
SELECT u.username
FROM tbl_user u,tbl_user_type t
where u.user_type_id = t.id and t.type='promoter';
Since you are using mysql you can simply use an innerJoin:
User::find()
->select(['user.id', 'user.username'])
->innerJoin('user_type', 'user_type.id = user.id')
->where(['user_type.type' => 'promoter'])
->orderBy('username')
->asArray()
->all(),
If you have a relation between user and user_type you can use joinWith instead, which handles the join type and the join condition for you:
User::find()
->select(['user.id', 'user.username'])
->joinWith('userType', true)
->where(['userType.type' => 'promoter'])
->orderBy('username')
->asArray ()
->all (),
Related
Background:
Mediawiki's PHP framework provides functions for creating SQL statements to be executed against the application. Creating a simple SELECT FROM WHERE statement is easy and well documented, but I'm trying to create a JOIN statement and I don't understand the documentation. The examples are fragmented and disjointed.
Current attempt:
The SQL I'm trying to recreate is as follows. Using phpmyadmin I've tested this code and it returns the results I need:
SELECT user.user_id, user.user_name, user.user_real_name, user.user_email
FROM user
LEFT JOIN ipblocks ON user.user_id = ipblocks.ipb_user
WHERE ipblocks.ipb_id IS NULL
Translating this into Mediawiki's framework looks something like this, but this code doesn't work. The function documentation is here.
$result = $this->dbr->select(
array( $this->dbr->tableName( 'user' )),
array( 'user_name', 'user_id', 'user_email' ),
array( 'ipb_id' => 'NULL'),
__METHOD__,
array( 'GROUP_BY' => 'user_id DSC' ),
array( 'ipblocks' => array( 'LEFT JOIN', 'user_id=ipb_user' ) )
);
The SQL generated by this code can be checked by calling selectSQLText() instead. This function returns the generated SQL rather than executing it. The calling convention is the same. THis results in the following SQL:
SELECT user_name,user_id,user_email
FROM `user`
WHERE ipb_id = 'NULL'
I can see why the function has returned this, but I don't understand why the last two parameters have been ignored. The GROUP_BY and JOIN parts have been ignored. Why is this and how do I correct the code?
Thanks.
I'm not an user of Mediawiki, I've just glossed over the function documentation. As for grouping, I believe you should use GROUP BY array key, not GROUP_BY. As for joins, I think you must include ipblocks table in $table parameter in order to use it in $join_conds.
So, try this:
$result = $this->dbr->select(
array( 'user', 'ipblocks' ),
array( 'user_name', 'user_id', 'user_email' ),
array( 'ipb_id' => null),
__METHOD__,
array( 'GROUP BY' => 'user_id DSC' ),
array( 'ipblocks' => array( 'LEFT JOIN', 'user_id=ipb_user' ) )
);
I'm rebuilding a vanilla PHP/MySQL application using CakePHP 3.5.13.
One of the queries in the original application needs to build a JOIN condition on the same table and does so by using separate table aliases. The query is as follows - and gives the correct results that we expect:
SELECT DISTINCT(s.id) FROM substances s
JOIN display_substances AS dsUses
ON (s.id = dsUses.substance_id AND dsUses.display_id = 128 AND (dsUses.value LIKE '%dye%') )
JOIN display_substances AS displays
ON (s.id = displays.substance_id AND displays.display_id NOT IN (1,2,3,4,6,128) AND (displays.value LIKE '%bpr%'))
The reason this is needed is because the query is doing a search for 2 separate items of user input - within the same table (display_substances) but against different display_substances .display_id fields. In terms of the query above it means:
Search for "%dye%" where display_id = 128
Search for "%bpr%" where display_id is not 1,2,3,4,6 or 128
In Cake I have written it like this in a Controller that handles the search functionality:
$query = $Substances->find()->select(['id' => 'Substances.id'])->distinct();
// Search for "dye"
$query = $query->matching('DisplaySubstances', function ($q) use ($uses_summary) {
return $q->where([
'DisplaySubstances.value LIKE' => '%dye%', // "dye" is dynamic and comes from $uses_summary
'DisplaySubstances.display_id' => 128
]);
});
// Search for "bpr"
$query = $query->matching('DisplaySubstances', function ($q) use ($regulatory_information) {
return $q->where([
'DisplaySubstances.value LIKE' => '%bpr%', // "bpr" is dynamic and comes from $regulatory_information
'DisplaySubstances.display_id NOT IN' => [1,2,3,4,6,128]
]);
});
This produces the wrong SQL, because when I debug $query->sql(); it gives a different JOIN condition:
INNER JOIN display_substances DisplaySubstances ON
(
DisplaySubstances.value like "%dye%" AND DisplaySubstances.display_id = 128
AND DisplaySubstances.value like "%bpr%"
AND DisplaySubstances.display_id not in (1,2,3,4,6,128)
AND Substances.id = (DisplaySubstances.substance_id)
)
I'm not sure how to rewrite this query such that it will treat each of the two search inputs as a JOIN condition, as per the original query.
The main thing I've noticed is that the original query has separate aliases for the same table (AS dsUses and AS displays). I'm not sure if this is relevant?
I'm trying to use the ORM as opposed to writing the SQL manually so would prefer to know how to use it to do this.
It's not yet possible to specify custom aliases for matching() calls, currently multiple matching() calls on the same association will merge the conditions as can be seen in your generated SQL snippet.
For now you'd have to either create additional associations (ie additionally to your DisplaySubstances association in your SubstancesTable class) with different aliases:
$this->hasMany('DsUses', [
'className' => 'DisplaySubstances'
]);
$this->hasMany('Displays', [
'className' => 'DisplaySubstances'
]);
on which you can then match:
$query->matching('DsUses', function ($q) use ($regulatory_information) {
return $q->where([
'DsUses.value LIKE' => '%dye%',
'DsUses.display_id' => 128
]);
});
$query->matching('Displays', function ($q) use ($regulatory_information) {
return $q->where([
'Displays.value LIKE' => '%bpr%',
'Displays.display_id NOT IN' => [1, 2, 3, 4, 6, 128]
]);
});
or build the joins manually, for example using innerJoin():
$query->innerJoin(
[
'DsUses' => 'display_substances'
],
[
'Substances.id' => new \Cake\Database\Expression\IdentifierExpression('DsUses.substance_id'),
'DsUses.display_id' => 128,
'DsUses.value LIKE' => '%dye%'
],
[
'DsUses.display_id' => 'integer',
'DsUses.value' => 'string'
]
);
$query->innerJoin(
[
'Displays' => 'display_substances'
],
[
'Substances.id' => new \Cake\Database\Expression\IdentifierExpression('Displays.substance_id'),
'Displays.display_id NOT IN' => [1, 2, 3, 4, 6, 128],
'Displays.value LIKE' => '%bpr%'
],
[
'Displays.display_id' => 'integer',
'Displays.value' => 'string'
]
);
See also
cakephp/cakephp#9499 : Improve association data fetching
Cookbook > Database Access & ORM > Query Builder > Adding Joins
I have a drupal 6 installation with a bunch of webforms i need my users to complete.
My aim to to show a list of webforms in a table with submission dates and a col stating Complete or Not Complete.
This is where im at... I thought it was working until i submitted the forms as a test user and the table changed for everyone as NULL is no longer found once the form has been submitted by anyone.
I pretty much want to search and list all forms with SSOW in the title that exist and show if the current logged in user has completed them or not. I tried to achive this with views before i went down this route, but no luck there either
thanks in advance for anyone who might take a look
$sql = "SELECT node.nid AS 'page', node.title AS 'webform',
IFNULL(FROM_UNIXTIME(webform_submissions.submitted), '') AS 'subdate',
IF(webform_submissions.submitted IS NULL, 'NOT COMPLETED', 'COMPLETED')
AS 'status'
FROM node
LEFT OUTER JOIN webform_submissions ON node.nid = webform_submissions.nid
LEFT OUTER JOIN users ON webform_submissions.uid = users.uid
WHERE node.title LIKE '%SIGNOFF%' AND node.type LIKE 'webform' AND
(webform_submissions.uid IS NULL OR webform_submissions.uid LIKE
'$user->uid')";
$res = db_query($sql);
$table_rows = array();
while ($row = db_fetch_object($res)) {
$table_rows[] = array(
'data' => array(
// Column 1
'Webform' => array('data' => l($row->webform, 'node/' . $row->page), 'class' => 'col-title', ),
// Column 2
'Date Submitted' => array('data' => $row->subdate, 'class' => 'col-submitted',),
// Column 3
'STATUS' => array('data' => $row->status, 'class' => 'col-status',),
// Row attributes
'id' => 'articles-row-' . $row->nid, 'class' => 'articles-row');
}
// Format and print out the table.
return theme('table', $table_header, $table_rows, array('id' =>
'table-articles', 'class' => 'articles' ));
I have two tables: users and posts. I'm trying to select any users that have at least one post.
I'm guessing this require either a join or a subselect. Is there something in CakePHP that makes this simple?
Use counter caching, see http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#belongsto
counterCache: If set to true the associated Model will automatically
increase or decrease the “[singular_model_name]_count” field in the
foreign table whenever you do a save() or delete(). If it’s a string
then it’s the field name to use. The value in the counter field
represents the number of related rows. You can also specify multiple
counter caches by using an array where the key is field name and value
is the conditions. E.g.:
array(
'recipes_count' => true,
'recipes_published' => array('Recipe.published' => 1) ) counterScope: Optional conditions array to use for updating counter
cache field.
No additional query needed in this case. It will automatically in- and decrease the count in the users table if you add/delete posts.
Example:
public $belongsTo = array(
'User' => array(
'foreignKey' => 'user_id',
'counterCache' => true,
'counterScope' => array(
'published' => 1)));
This should select all users that made 1 post or more
SELECT * FROM `users` as u
INNER JOIN `posts` as p ON p.user_id = u.id
In cake you should be able to do something like this:
$this->User->find('all', array('joins' =>
array(
'table' => 'posts',
'alias' => 'p',
'type' => 'inner',
'conditions' => array(
'User.id = p.user_id'
)
)
);
[EDIT]
Maybe you could add
'group' => 'User.id'
or
'fields' => 'DISTINCT User.id, ...'
To remove duplicates entries
I have two tables in cakePHP.
competencies
------------
id
name
competenceRatings
-----------------
id
competence_id
user_id
rating
I need a way to write the following query in the cake way:
SELECT * FROM competencies WHERE id NOT IN (SELECT competence_id FROM competence_ratings WHERE employee_id = $userId)
Someone please help me!!
What i did before going to this subquery method:
I tried competencies->hasMany->competenceRatings, competenceRatings->belongsTo->competencies relations.
$competencies = $this->Competence->CompetenceRating->find('all',array('CompetenceRating.user_id' => $userId,'CompetenceRating.competence_id !=' => 'Competence.id'));
I want to be able to get the names of competencies for which a user have NOT made any ratings into competenceRatings table. i.e., I need list of names from competencies table for which there are no entries in comptenceRatings table(for given user_id).
EDIT
I tried table join also:
$options['joins'] = array(
array(
'table' => 'competence_ratings',
'alias' => 'CompetenceRating',
'type' => 'LEFT OUTER',
'conditions' => array(
'Competence.id = CompetenceRating.competence_id'
)
)
);
$options['conditions'] = array( 'CompetenceRating.employee_id' => $employee['Employee']['id'] );
$competencies = $this->Competence->find('all',$options);
you would probably have to use a subquery():
$subqueryOptions = array('fields' => array('competence_id'), 'conditions' => array('employee_id'=>$user_id));
$subquery = $this->Competence->CompetenceRating->subquery('all', $subqueryOptions);
$res = $this->Competence->CompetenceRating->find('all', array(
'conditions' => array('id NOT IN '. $subquery)
));
the source for subquery is here:
https://github.com/dereuromark/tools/blob/2.0/Lib/MyModel.php#L405
you need to put this in your AppModel.php
BUT I think the subquery is not necessary. You can probably make a single and easy query out of it:
$this->Competence->CompetenceRating->find('all', array(
'group' => 'competence_id',
'conditions' => array('NOT' => 'employee_id'=>$user_id)),
'contain' => array('Competence')
));
dont forget to include Competence via "contain" if you have recursive set to -1.