Not equal condition with findAll() - yii2

I am trying to pull record from a table using the following code
$userId = Yii::$app->user->id;
$lists = PromoLists::findAll(['user_id' => $userId, 'list_type' => 'custom']);
which outputs a query like below
select * from promo_lists where user_id ='$userId' and list_type='custom'
But i am unable to find any thing in the documentation that would help me achieve it with the following condition.
select * from promo_lists where user_id ='$userId' and list_type='custom' and status!='deleted'
as the status is an ENUM field and there are 4 different status
'active','pending','rejected','deleted'
currently i used the following approach
PromoLists::findAll(['user_id' => $userId, 'list_type' => 'custom', 'status'=>['active','pending','rejected']]);
which outputsthe following query
select * from promo_lists where user_id ='$userId' and list_type='custom' and status in ('active','pending','rejected')
which somehow achieves the same thing but this query would need to be edited every time when there is a new status type added to the table column status.
i know i can do this by using PromoLists::find()->where()->andWhere()->all()
but how to check with != / <> operator using findAll().

Simply like this:
PromoLists::find()->where(['and',
[
'user_id' => $userId,
'list_type' => 'custom',
],
['<>', 'status', 'deleted'],
])->all();

Using operator format in condition
http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html#operator-format
PromoLists::find()
->andWhere([
'user_id' => $userId,
'list_type' => 'custom',
['!=', 'status', 'deleted']
])
->all();

Related

Codeigniter: Know AI ID of query

When a user create an item, on my controller i need to send 2 SQL Query.
The first is easy to do:
$data = array(
'author' => $this->input->post('author'),
'name' => $this->input->post('name'),
);
$this->item_model->insertItem($data);
But on my second query, i need to recover, to find the ID of the query showing just before.
For example:
$data = array(
'user_id' => $_SESSION['user_id'],
'item_id' => ????,
);
$this->item_model->insertItem($data);
Thanks
For fetching the last inserted ID of variable $item_id in the same transaction of your controller, you can get the ID of record in the same session as follows:
$item_id = $this->db->insert_id();

Cakephp 3.5 InnerJoin

I have following situation.
i have a table "drivers_events" in this there are stored the drivers which are booked for an event.
Now I would like to do following
SELECT
Driver.id,
Driver.name
FROM
drivers AS Driver
INNER JOIN
drivers_events AS Listing
ON Driver.id = Listing.driver_id
WHERE
Listing.event_id = 83
ORDER BY
Driver.name ASC;
If I run it as a SQL query in phpmyadmin, it works perfectly and I get the correct id and name from the table "drivers".
When I do this in my controller like this
$drivers = $this->Jobs->query("
SELECT
Driver.id,
Driver.name
FROM
drivers AS Driver
INNER JOIN
drivers_events AS Event
ON Driver.id = Event.driver_id
WHERE
Event.event_id = $activeevent
ORDER BY
Driver.name ASC
");
then i get the complete array of jobs which created in the past.
What did i do wrong ?
It would be great if someone could help me.
Thanks in advance
I tried a lot more. I have come to the conclusion that I can read out the drivers who are assigned to an event.
in the controller it looks like this
$drivers = $this->Jobs->drivers_events->find('list',
[
'conditions' =>
[
'drivers_events.event_id' => $this->request->session()->read('Event.active')
],
'keyField' => 'driver_id',
'valueField' => 'driver_id'
]
);
In the model
$this->belongsTo('drivers_events', [
'foreignKey' => 'event_id',
]);
So now I get the right drivers for a driving job within an event.
But how do I get the name of the driver from the "Drivers" table instead the ID ?
Thx for help
Event key word is reserved for SQL.
Please do not use it for table alias.
Or use such this method.
drivers_events AS `Event`
Hope to be useful.
$result = $this->Jobs->find()
->enableAutoFields(true)
->enableHydration(false)
->select([
'id' => 'Driver.id',
'Title' => "Driver.name"
])
->join([
'Events' => [
'table' => 'drivers_events',
'type' => 'INNER',
'conditions' => [
'Jobs.event_id = Events.id',
],
]
])
->join([
'Driver' => [
'table' => 'drivers',
'type' => 'INNER',
'conditions' => [
'Events.driver_id = Driver.id',
],
]
])
->where([
'Events.id' => $activeevent
])
->group('Driver.id')
->toArray();
Ref: Cakephp 3 Adding Joins
Select Drivers.id, drivers.accountname
FROM TABLE__
Join table__
Join table__
And (Brand) Totaljobs.com
Having Count <4
group By Driver.id, Drivers.Accountname
Order by (Drivers.accountname)

Possible to mix where() clause

I have the following code (it's shortened otherwise it would be too long to show):
Feedback::find()
->where(['feedback.fg_id' => $this->id])
->orWhere(['feedback.fg_id' => $this->id, 'feedback.closed_time' => NULL, '<' => ['feedback.survey_end_date', new Expression('NOW()')]])
->all();
This code do not work, because of the last statement in orWhere()
My question is now: How can I combine the syntax inside orWhere? It's because I need all the statements inside the or block.
The ambivalent sql code should be:
SELECT * FROM feedback WHERE
(feedback.fg_id = 1) OR (feedback.fg_id = 1 AND feedback.closed_time IS NULL AND feedback.survey_end_date < NOW())
Yes you can combine you condition as ...
Feedback::find()
->where(['feedback.fg_id' => $this->id])
->orWhere(['AND',
['feedback.fg_id' => $this->id],
['feedback.closed_time' => NULL],
['<' , 'feedback.survey_end_date', new Expression('NOW()')]
]);

How to use AND and OR in MySQL query?

I want to get those records whose date_last_copied field is empty or less than the current date. I tried this, but it did not give me the desired result:
$tasks = $this->Control->query("
SELECT *
FROM
`controls`
WHERE
`owner_id` = ".$user_id."
AND `control_frequency_id` = ".CONTROL_FREQUENCY_DAILY."
OR `date_last_copied` = ''
OR `date_last_copied` < ". strtotime(Date('Y-m-d'))."
");
Current query looks something like this, I think. That is, find the records with the correct owner_id and frequency_id, where the date_last_copied is null or less than a certain date. Is that logic correct?
SELECT *
FROM controls
WHERE owner_id = ::owner_id::
AND control_frequency_id = ::frequency_id::
AND (
date_last_copied IS NULL
OR date_last_copied < ::date::
)
But we should really be using the CakePHP query builder, rather than running raw SQL. This article gives some details. If I were to take a stab at a solution, we'd want something like the following. But we ideally want someone from the CakePHP community to chime in here. EDIT: Note that this seems to be for CakePHP 3.0, only.
// Build the query
$query = TableRegistry::get('controls')
->find()
->where([
'owner_id' => $ownerId,
'control_frequency_id' => $frequencyId,
'OR' => [
['date_last_copied IS' => null],
['date_last_copied <' => $date]
]
]);
// To make sure the query is what we wanted
debug($query);
// To get all the results of the query
foreach ($query as $control) {
. . .
}
I'm suggesting this, rather than the raw SQL string you have above, because:
We can now leverage the ORM model of CakePHP.
We don't have to worry about SQL injection, which you're currently vulnerable to.
EDIT: OK, this is a guess at the syntax applicable for CakePHP 2.0... YMMV
$controls = $this->controls->find('all', [
'conditions' => [
'owner_id' => $ownerId,
'control_frequency_id' => $frequencyId,
'OR' => [
['date_last_copied IS' => null],
['date_last_copied <' => $date]
]
]
];
Otherwise, we just use the raw query as a prepared statement:
$result = $this->getDataSource()->fetchAll("
SELECT *
FROM controls
WHERE owner_id = ?
AND control_frequency_id = ?
AND (
date_last_copied IS NULL
OR date_last_copied < ?
)",
[$ownerId, $frequencyId, $date]
);
Not sure about your whole logic but your final query statement should be something like:
SELECT * FROM `controls` WHERE (`owner_id` = <some owner_id>)
AND (`control_frequency_id` = <some id value>)
AND (`date_last_copied` = '' OR
`date_last_copied` IS NULL OR
`date_last_copied` < CURDATE() )
Use parentheses carefully to match your logic.
Always specify the version of cakePHP you are using for your App.
This query should work fine in CakePHP 3.0 for SQL AND and OR.
$query = ModelName>find()
->where(['colunm' => 'condition'])
->orWhere(['colunm' => 'otherCondition'])
->andWhere([
'colunm' => 'anotherContion',
'view_count >' => 10
])
->orWhere(['colunm' => 'moreConditions']);

CakePHP model associations - Random order on retrieve of associated model for HABTM

I am retrieving data:
$mydata = $this->ProductList->find('all', array('order' => 'rand()', 'conditions' => array('name' => 'we love')));
I have set up a HABTM relationship to the Product model. As you can see, I am fetching all products in the 'we love'-list. Now, I want those Products I am retrieving to be randomised. But they are not, instead the MySQL is randomised on the ProductList model as you can see in the SQL. Why is that? How can I get the random fetch on the Products instead?
Resulting MySQL query:
SELECT `ProductList`.`id`, `ProductList`.`name` FROM `database`.`product_lists` AS `ProductList` WHERE `name` = 'we love' ORDER BY rand() ASC
SELECT `Product`.`id`, `Product`.`category_id`, `Product`.`name`, `Product`.`price`, `Product`.`description`, `ProductListsProduct`.`product_list_id`, `ProductListsProduct`.`product_id` FROM `database`.`products` AS `Product` JOIN `database`.`product_lists_products` AS `ProductListsProduct` ON (`ProductListsProduct`.`product_list_id` = 3 AND `ProductListsProduct`.`product_id` = `Product`.`id`)
EDIT:
There are so many different ways to approach this; to get a random product from a user's product list. You could do it with PHP - just find all of the products and then use rand() to pick on from the returned array. You could set a Model query condition. The list goes on...
I would probably create an alias to the Product model in ProductList called RandomProduct. You could set the query for the retrieved product when you set the relationship:
public $hasMany = array(
'RandomProduct' => array(
'className' => 'Product',
'foreignKey' => 'product_list_id',
'order' => 'Rand()',
'limit' => '1',
'dependent' => true
)
);
You can then use the containable behavior so that this model is only retrieved when you need it. (You wouldn't need to do this if recursive finds are greater than -1, but I usually do that as best practice so that my models only query for the data that they need.) The following would return any ProductList called 'we love' and a "random" product associated with that list.
$mydata = $this->ProductList->find(
'all',
array(
'conditions' => array(
'name' => 'we love'
)
),
'contain' => array(
'RandomProduct'
)
);