Yii2 Converting model objects to array with ArrayHelper::toArray() - php

I am working in YII2 Framework on the following query
SELECT T.id, T.name, T.status, IFNULL(T.image,'no-image.png') as DP
FROM TABLE_NAME T;
here is my code
$modelTeam = Teams::find()
->select(
['T.id', 'T.name', 'T.status', 'IFNULL(T.image,"no-image.png") as DP']
)
->from('{{%teams}} T')
->all();
Edit:
The result set does not include DP column at all why is that so, and how can I do that.
Edit 2:
While telling that the results do not include the DP column I missed a piece of important information that I was using the ArrayHelper::toArray() to convert the model object to an array and then iterate over it
$results=ArrayHelper::toArray($modelTeam);

The actual problem is not where I was thinking it is, the query is alright, I used ArrayHelper::toArray($modelTeam) method to convert the model object to an array to further iterate over the array and display all the records, and that is where the problem lies.
I needed to use the second parameter $properties for the ArrayHelper::toArray(). The second argument converts properties mapping per class, as it has problems displaying the custom declared public properties of a model and the DP is declared public inside the Teams model as it is an alias in the ActiveRecrod query.
$modelTeam = Teams::find()->
select(['TM.id', 'TM.name', 'TM.status'])
->addSelect([new \yii\db\Expression('IFNULL(TM.image,\'no-image.png\') AS DP')])
->from('{{%teams}} TM')->all();
$results = ArrayHelper::toArray($modelTeam, [
'common\models\Teams' => [
'id',
'name',
'status',
'DP',
],
]);

$modelTeam = Teams::find()
->select(['T.id', 'T.name', 'T.status'])
->addSelect([new Expression('IFNULL(T.image,"no-image.png") as DP')])
->from('{{%teams}} T')
->all();
$arrTeam = $modelTeam->asArray()->all();

To use IFNULL in a select with Yii2 you must create a new expression.
$modelTeam = Teams::find()
->select(['T.id', 'T.name', 'T.status'])
->addSelect([new Expression('IFNULL(T.image,"no-image.png") as DP')])
->from('{{%teams}} T')
->all()

Related

Need help for my sql query to make use of AS operator [duplicate]

Lets say we are using Laravel's query builder:
$users = DB::table('really_long_table_name')
->select('really_long_table_name.id')
->get();
I'm looking for an equivalent to this SQL:
really_long_table_name AS short_name
This would be especially helpful when I have to type a lot of selects and wheres (or typically I include the alias in the column alias of the select as well, and it gets used in the result array). Without any table aliases there is a lot more typing for me and everything becomes a lot less readable. Can't find the answer in the laravel docs, any ideas?
Laravel supports aliases on tables and columns with AS. Try
$users = DB::table('really_long_table_name AS t')
->select('t.id AS uid')
->get();
Let's see it in action with an awesome tinker tool
$ php artisan tinker
[1] > Schema::create('really_long_table_name', function($table) {$table->increments('id');});
// NULL
[2] > DB::table('really_long_table_name')->insert(['id' => null]);
// true
[3] > DB::table('really_long_table_name AS t')->select('t.id AS uid')->get();
// array(
// 0 => object(stdClass)(
// 'uid' => '1'
// )
// )
To use aliases on eloquent models modify your code like this:
Item
::from( 'items as items_alias' )
->join( 'attachments as att', DB::raw( 'att.item_id' ), '=', DB::raw( 'items_alias.id' ) )
->select( DB::raw( 'items_alias.*' ) )
->get();
This will automatically add table prefix to table names and returns an instance of Items model. not a bare query result.
Adding DB::raw prevents laravel from adding table prefixes to aliases.
Here is how one can do it. I will give an example with joining so that it becomes super clear to someone.
$products = DB::table('products AS pr')
->leftJoin('product_families AS pf', 'pf.id', '=', 'pr.product_family_id')
->select('pr.id as id', 'pf.name as product_family_name', 'pf.id as product_family_id')
->orderBy('pr.id', 'desc')
->get();
Hope this helps.
To use in Eloquent.
Add on top of your model
protected $table = 'table_name as alias'
//table_name should be exact as in your database
..then use in your query like
ModelName::query()->select(alias.id, alias.name)
You can use less code, writing this:
$users = DB::table('really_long_table_name')
->get(array('really_long_table_name.field_very_long_name as short_name'));
And of course if you want to select more fields, just write a "," and add more:
$users = DB::table('really_long_table_name')
->get(array('really_long_table_name.field_very_long_name as short_name', 'really_long_table_name.another_field as other', 'and_another'));
This is very practical when you use a joins complex query
I have tried all these options and none works for me. Then I had found something in the Laravel documentation that really works.
You could try this:
DB::table('table_one as t1')
->select(
't1.field_id as id','t2.field_on_t2 as field'
)->join('table_two as t2', function ($join) {
$join->on('t1.field_id ', '=', 't2.field_id');
})->get()
Also note that you can pass an alias as the second parameter of the table method when using the DB facade:
$users = DB::table('really_long_table_name', 'short_name')
->select('short_name.id')
->get();
Not sure if this feature came with a specific version of Laravel or if it has always been baked in.
Same as AMIB answer, for soft delete error "Unknown column 'table_alias.deleted_at'",
just add ->withTrashed() then handle it yourself like ->whereRaw('items_alias.deleted_at IS NULL')
In the latest version of Laravel 9, you can use alias name for column as:
$events = Booking::whereBetween('sessionDateTime', [$today, $nextMonth])->get(['bookings.sessionDateTime as start']); // start is an alias here

My whereJsonContains not working (Laravel 5.8)

I have problem with my laravel query.
Now I use query like this:
$courses = Course::whereJsonContains('schedule->day', 1)->get();
It doesn't work.
I'm using postgreSql 9.6 and my database and raw query look like this
http://sqlfiddle.com/#!17/88fd2/1/0
I want to select class where have schedule in day = 1
If you define the column as schedule->day, MySQL assumes that this is an array of integers. In your case it's an array of objects, so you have to target the parent array and add the property name you are looking for in the second argument.
Like so:
$courses = Course::whereJsonContains('schedule', ['day' => 1])->get();
I solved with
$courses = Course::whereJsonContains('schedule', [['day' => '1']])->get();
I solved with
$products=ProductShop::active()
->whereJsonContains('tag', [['value' => "tampa"]])->get();
If you're querying the value уоu don't need to use whereJsonContains, simply use a regular where query such as:
$courses = Course::where('schedule->day', 1)->get();`
If you want to check if day exists in Json, use whereJsonLength such as:
$courses = Course::whereJsonLength('schedule->day', '>', 0)->get();

Eloquent order relationship results

I have a simple eloquent query and want to include another table with my results, however, the order of relationship results is incorrect.
Is it possible to order the results without using an SQLRAW statement
$groups = AttributeGroup::with('attribute')->where('page_id', $page->id)->get();
What I would like -
$groups = AttributeGroup::with('attribute')->orderBy('iteration', 'DESC')->where('page_id', $page->id)->get();
I get the error of Unknown column because this column is part of relationship table.
This will order each attribute relation of every attribute group result:
$groups = AttributeGroup::with(['attribute' => function ($query) {
$query->orderBy('iteration', 'DESC');
}])->where('page_id', $page->id)->get();
Is this what you want to achieve?
You can use closures to change the query when using with and has.
$groups = AttributeGroup::with(['attribute' => function($query){
$query->orderBy('iteration');
})->where('page_id', $page->id)->get();
Details are available on https://laravel.com/docs/5.6/eloquent-relationships#constraining-eager-loads

Laravel 5.1 select field in with function

Can I select value from relationships with function "with" ?
So make something like this:
$test = User::where('id',1)->with(['user_detail' => function($query){
$query->select("detail_1");
}])->get();
Yes I know that I can put select in relation "user_detail" but can I select in with function?
You can select within with as you made the example given below:
$test = User::where('id',1)->with(['user_detail' => function($query){
$query->select("detail_1");
}])->get();
But it won't not work (as you commented in other answer) because you've only selected a single property but the foreign key is not available in your select statement. So, make sure that, you also select the related foreign key as well and then it'll work.
In your case, I believe that, you've to also select the user_id in your select for example:
$test = User::where('id',1)->with(['user_detail' => function($query){
$query->select(
'user_id', // This is required if this key is the foreign key
'detail_1'
);
}])->get();
So, without the foreign key that makes the relation, Eloquent won't be able to load the related models and that's why you get null in your result as you mentioned in other comment.
Yes, you can use select() inside with(). Just pass an array of columns:
$query->select(['detail_1', 'detail_2']);
Alternatively, you can create another relation and add select() to it:
public function userDatails()
{
return $this->hasMany('App\UserDetail')->select(['detail_1', 'detail_2']);
}
$result = Staff::where('live_status',2)
->with('position')->with('department')->with('gender')
->with(['partner' => function($query){
$query->where('alive',0);
}]);

How to alias a table in Laravel Eloquent queries (or using Query Builder)?

Lets say we are using Laravel's query builder:
$users = DB::table('really_long_table_name')
->select('really_long_table_name.id')
->get();
I'm looking for an equivalent to this SQL:
really_long_table_name AS short_name
This would be especially helpful when I have to type a lot of selects and wheres (or typically I include the alias in the column alias of the select as well, and it gets used in the result array). Without any table aliases there is a lot more typing for me and everything becomes a lot less readable. Can't find the answer in the laravel docs, any ideas?
Laravel supports aliases on tables and columns with AS. Try
$users = DB::table('really_long_table_name AS t')
->select('t.id AS uid')
->get();
Let's see it in action with an awesome tinker tool
$ php artisan tinker
[1] > Schema::create('really_long_table_name', function($table) {$table->increments('id');});
// NULL
[2] > DB::table('really_long_table_name')->insert(['id' => null]);
// true
[3] > DB::table('really_long_table_name AS t')->select('t.id AS uid')->get();
// array(
// 0 => object(stdClass)(
// 'uid' => '1'
// )
// )
To use aliases on eloquent models modify your code like this:
Item
::from( 'items as items_alias' )
->join( 'attachments as att', DB::raw( 'att.item_id' ), '=', DB::raw( 'items_alias.id' ) )
->select( DB::raw( 'items_alias.*' ) )
->get();
This will automatically add table prefix to table names and returns an instance of Items model. not a bare query result.
Adding DB::raw prevents laravel from adding table prefixes to aliases.
Here is how one can do it. I will give an example with joining so that it becomes super clear to someone.
$products = DB::table('products AS pr')
->leftJoin('product_families AS pf', 'pf.id', '=', 'pr.product_family_id')
->select('pr.id as id', 'pf.name as product_family_name', 'pf.id as product_family_id')
->orderBy('pr.id', 'desc')
->get();
Hope this helps.
To use in Eloquent.
Add on top of your model
protected $table = 'table_name as alias'
//table_name should be exact as in your database
..then use in your query like
ModelName::query()->select(alias.id, alias.name)
You can use less code, writing this:
$users = DB::table('really_long_table_name')
->get(array('really_long_table_name.field_very_long_name as short_name'));
And of course if you want to select more fields, just write a "," and add more:
$users = DB::table('really_long_table_name')
->get(array('really_long_table_name.field_very_long_name as short_name', 'really_long_table_name.another_field as other', 'and_another'));
This is very practical when you use a joins complex query
I have tried all these options and none works for me. Then I had found something in the Laravel documentation that really works.
You could try this:
DB::table('table_one as t1')
->select(
't1.field_id as id','t2.field_on_t2 as field'
)->join('table_two as t2', function ($join) {
$join->on('t1.field_id ', '=', 't2.field_id');
})->get()
Also note that you can pass an alias as the second parameter of the table method when using the DB facade:
$users = DB::table('really_long_table_name', 'short_name')
->select('short_name.id')
->get();
Not sure if this feature came with a specific version of Laravel or if it has always been baked in.
Same as AMIB answer, for soft delete error "Unknown column 'table_alias.deleted_at'",
just add ->withTrashed() then handle it yourself like ->whereRaw('items_alias.deleted_at IS NULL')
In the latest version of Laravel 9, you can use alias name for column as:
$events = Booking::whereBetween('sessionDateTime', [$today, $nextMonth])->get(['bookings.sessionDateTime as start']); // start is an alias here

Categories