Yii CListView Search with Subqueries - php

I am using a CListView to display my data on a page. I have a textbox for searching keywords in the query.
In my query where I build my CActiveDataProvider I have some subqueries. For Example:
$criteria = new CDbCriteria;
$criteria->select = array('
Lessons.id,
Lessons.name,
(SELECT
COALESCE(CONCAT(u.first_name, " ", u.last_name), last_name, first_name)
FROM
users AS u
WHERE
u.user_token = Lessons.instructor_id
) as instructor_name
');
My model for the above query does have a class variable called $instructor_name.
When I enter data into the textbox I then run this piece of code to join another table for searching.
if ( !empty($query) ) {
$criteria->with = array('packages');
$criteria->compare( 'packages.contents', $query, true);
$criteria->together = true;
}
The results when running a search query do not return the instructor_name data from the subquery.
Any ideas on what is happening here to prevent my subquery data from loading? Thank you in advance.

To do this in a more CActiveRecord way (and get the results your looking for), try the following:
1 - Add instructor relation to Lesson model that references the User table (so now you will be able to do $lesson->instructor)
'instructor'=>array(self::BELONGS_TO, 'User', 'instructor_id'),
2 - Add a column/expression into the select clause in your Lesson::search() method that represents the concatenated instructor_name - something like:
$criteria->select = array('
Lessons.id,
Lessons.name,
COALESCE(CONCAT(instructor.first_name, " ", instructor.last_name), last_name, first_name) AS instructor_name
...etc
3 - Add instructor to the "with" part of the search criteria so that the instructor info is joined into the query
$criteria->with = array('packages', 'instructor');

Related

Laravel query builder add complex query result

I have three models with the following hierarchy :
User
id
....some other properties
Journey
id
user_id
budget
....some other properties
Confirmation
id
journey_id
user_id
....some other properties
I have a HasMany from User to Journey, a HasMany from Journey to Confirmation.
I want to get the sum for a column of the journeys table by going through the confirmations table but I cannot create an intermediate HasManyThrough relation between User and Journey by using Confirmation.
I have tried to do
public function journeysMade(): HasManyThrough
{
return $this->hasManyThrough(Journey::class, Confirmation::class);
}
// And after,
User::with(...)->withSum('journeysMade','budget')
But it was not possible because the relations are not adapted.
With hindsight, the sql query I want to translate would look like
select coalesce(sum(journeys.budget), 0) as income
from journeys
inner join confirmations c on journeys.id = c.journey_id
where c.user_id = ? and c.status = 'finalized';
How can I implement this query considering how I will use my query builder :
$driversQueryBuilder = User::with(['profile', 'addresses']); // Here
$pageSize = $request->input('pageSize', self::DEFAULT_PAGE_SIZE);
$pageNumber = $request->input('pageNumber', self::DEFAULT_PAGE_NUMBER);
$driversPaginator = (new UserFilterService($driversQueryBuilder))
->withStatus(Profile::STATUS_DRIVER)
->withCountry($request->input('country'))
->withSex($request->input('sex'))
->withActive($request->has('active') ? $request->boolean('active') : null)
->get()
->paginate(perPage: $pageSize, page: $pageNumber);
return response()->json(['data' => $driversPaginator]);
The reason why I want to get a builder is because UserFilterService expects a Illuminate\Database\Eloquent\Builder.
Do you have any idea about how I can solve this problem ?
Not 100% sure what exactly you want to sum, but I think you need the following query
$user->whereHas('journeys', function($query) {
$query->whereHas('confirmations', function($subQuery) {
$subQuery->sum('budget);
}
});
If you the above query isn't summing the budget you need, you just add another layer of abstraction with whereHas methods to get exactly what you need. Hope this helps!
EDIT:
$user->whereHas('confirmations', function($q) {
$q->withSum('journeys', 'budget')->journeys_sum_budget;
}

Laravel Many to many without using id column

I have 3 tables. Players, player_skills and Skills.
Players
- bb1_player_id
Skills
- bb1_skill_id
Player_skills
- bb1_player_id
- bb1_skill_id
I have created the Player Model with this method.
public function skills()
{
return $this->belongsToMany('App\Skills', 'player_skills', 'bb1_player_id', 'bb1_skill_id');
}
That outputs this Query:
"select `skills`.*, `player_skills`.`bb1_player_id` as `pivot_bb1_player_id`, `player_skills`.`bb1_skill_id` as `pivot_bb1_skill_id` from `skills` inner join `player_skills` on `skills`.`id` = `player_skills`.`bb1_skill_id` where `player_skills`.`bb1_player_id` = ?"
The query works, but I am hoping to get a query that does not every use the id field of the tables and only uses the fields I am specifying. It uses both the id of the skill and player.id at the '?' of the query. Is there a way around this? Or do I need to rework my tables to conform?
I have also tried adding more options like below to no avail.
public function skills()
{
return $this->belongsToMany('App\Skills', 'player_skills','bb1_player_id','bb1_skill_id','bb1_player_id','bb1_skill_id');
}

How to tell Paris/ORM which table to use for the Model?

I've just added some Joins to my application which uses Idiorm/Paris, I'm finding that when I search via Model::factory() the object returned is getting the ID from the joined object, not the 'parent' object.
How can I tell Paris which table alias should form the model?
I'm doing this in a search context, so I don't think that I can use has_many() but I'd be happy to be wrong!
Sample code:
// Find a booking with a join
$query = Model::factory('Booking');
$query->where('booking.id', '2282');
$query->join(
'customer',
array('booking.id', '=', 'customer.booking_id'),
'customer'
);
$bookingWithJoin = $query->find_one();
// Find the same booking, without a join
$query = Model::factory('Booking');
$query->where('id', '2282');
$bookingWithoutJoin = $query->find_one();
// The booking with a join gets the ID of the customer it's joined with
echo $bookingWithJoin->id .' != '. $bookingWithoutJoin->id;
I discovered the answer was $query->select('booking.*');
Does the equivelant of
SELECT booking.* FROM bookings JOIN customer on booking.customer_id = customer.id
So the returned results won't have customer.* fields included.

Yii CActiveDataProvider data is not loading from joined tables

My code :
$criteria = new CDbCriteria();
// $criteria->select = array("id");
$criteria->with = array('userProfiles'=>array(
'select'=>'firstname'
));
$criteria->together = true;
$criteria->condition = "firstname like '%$q%' "
. "and (user_id not in (select id2 from friends where id1=$user_id) "
. "and user_id not in (select id1 from friends where id2=$user_id))";
$dataProvider = new CActiveDataProvider("Users", array(
'criteria' => $criteria
));
return $dataProvider;
Notes:
1- userProfiles relation is defined in User module
Issue:
It is loading data only from User table not also from the user_profiles table despite of providing select atribute 'select'=>'firstname'
I want data from both user and userProfile table.
Relation self::HAS_ONE can't be executed together with main query, try use join
$criteria->select = "*, user_profiles.firstname firstname";
$criteria->join = 'user_profiles ON user_profiles.user_id = users.id';
Something like this, but you should create firstname field in User AR to retrieve it.
Or change relation to HAS_MANY and check first entity of array.
together: whether the table associated with this relationship should be forced to join together with the primary table and other tables. This option is only meaningful for HAS_MANY and MANY_MANY relations.
Because you can't write query that will give you only one record for each joining record
SELECT * FROM main
INNER JOIN slave ON (slave.main_id = main.id limit 1) // will not work);

Doing Join query using CDBCriteria

I am trying to do a Join query using CDBCriteria in Yii framework. The issue is the join query works successfully but it does not display the columns from other tables.
I am doing in the following way
$criteria = new CDbCriteria;
$criteria->order = 't.id desc';
$criteria->select = '*';
$criteria->join = ' INNER JOIN table2 INNER JOIN table3 INNER JOIN table4';
When i run this, I can see only the mail table1 columns displayed. Other columns are not shown.
In my model class, I have the relation has
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'user' => array(self::BELONGS_TO, 'DmPhoneUser', 'user_id'),
'command' => array(self::BELONGS_TO, 'DmOtaCommand', 'command_id'),
'partner' => array(self::BELONGS_TO, 'DmPartner', 'partner_id'),
);
}
********************************************************
public function actionGetHistory($start, $per_page)
{
$partner_id = '10';
$criteria = new CDbCriteria;
$criteria->order = 't.history_id desc';
$criteria->select = 't.*, table2.*';
$criteria->join = ' INNER JOIN table2 ON t.command_id = table2.command_id';
$result = Table_1_class::model()->with('command')->findAll();
$history_data = CJSON::encode($result);
echo $history_data;
}
here command_id is common in table1 and table2.
This is how I am using the criteria code.
As I said, Yii's Active Record implementation will only use columns which are defined in the table itself or the tables you are linking to through with, not arbitrary columns you return in the resultset.
Solution 1: Define a relation to table2, add that relation to with, and get rid of join. Then you'll probably need to convert each returned object to an array - CJSON::encode will not handle a model with relations well.
Solution 2: Use Yii::app()->db->createCommand("SQL query")->queryAll(); instead of Active Record. This will produce an array of arrays, which CJSON::encode will have no problem with.

Categories