Let's say I have an entity A with columns ID, foo, and bar which are either strings, integers or DateTime objects. This entity has all of the standard getters like getId(), getFoo(), and getBar().
In my controller, I have an object that is of another entity called B. The relationship between B and A is one to many. The getAllA() function finds all A associated with B which will return a Doctrine ArrayCollection. So with the object in the controller, I invoke
$paginator = $this->get('knp_paginator');
$paginatedObject = $paginator->paginate(
$object->getAllA(),
$this->get('request')->query->get('page', 1),
3
Now pagination works fine, but how do I sort? In the table header row I have
{{ knp_pagination_sortable(paginatedObject, 'ID', '???????????????') }}
but what goes in for the question marks?
You could use a DQL query like
'SELECT o FROM AcmeBundle:Object o'
and then the third parameter would be 'o.id'
source
Related
I have two multi-word models, let's call them FunkyModel and AnotherModel.
Will creating a pivot table named another_model_funky_model work?
The docs and examples I've come across all use single word model names like this: model A - User, model B - Address, and pivot table will then be address_user.
If you dive into the source code of the BelongsToMany relation function, you'll find that if you haven't provided a $table, the code will execute the function joiningTable. This uses the current model and the passed related class, snake cases the names and then puts them in alphabetical order of each other.
Simply said, no matter if you have a single word or a couple, the result will always be the 2 classes snaked, in alphabetical order. Note that the alphabetical order is applied by the default php sort.
Examples:
Department + Occupation > department_occupation
AwesomeModel + LessInterestingModel > awesome_model_less_interesting_model
Role + UserPermission > role_user_permission
You can even try and see what the auto-generated name is by simply calling the following:
(new Model)->joiningTable(OtherModel::class, (new OtherModel));
Yes it would work, you can also name it whatever you want, you just need to declare the table name in the relation (same goes for the foreign keys)
class FunkyModel
{
public function anotherModels()
{
return $this->belongsToMany(AnotherModel::class, 'pivot_table_name', 'funky_model_id', 'another_model_id');
}
I have used some accessors for Model attributes.
And as my knowledge about Accessor in Laravel, it can use to create a virtual attribute based on another attribute value or modify the return value of the existing attribute.
So I create an Accessor with the public method getStatusAttribute to convert the status from integer to string value. For example, my Model has an attribute named is 'status'. In DB, this column is stored with integers like 0,1,2,...
In this method, the return value is a string based on the current status attribute value.
public function getStatusAttribute(int $value): string
{
$statuses = [
1 => 'New',
2 => 'Pending',
3 => 'Canceled'
];
return $statuses[$value];
}
Everything work fined when I retrieve attribute value from the model object entity.
But when I want to retrieve an Eloquent Collection with a specific 'status' attribute value, the $value parameter in the 'where' method expects a string value that is returned from the accessor method, not is an integer value which stored in a database. So the $value parameter would be 'New' or 'Pending' or 'Canceled' instead of 1,2,3.
I want to retrieve a collection that contains an Eloquent Model Object so that I won't use an Illuminate\Support\Facades\DB.
I know I still can retrieve the exact collection with the $value parameter as a string, but I was just wondering if we have another way to skip the accessor in the query of Eloquent Collection?
Please see an example below for more detail about what I expect.
For example, some records in the database look like the below, and the model was named 'DemoModel' :
id
status
1
1
2
3
3
1
4
3
5
2
public function getCanceledEntities($entityId)
{
$canceledEntities = DemoModel::all()->where('status', '=', 3);
if($canceledEntities->isNotEmpty()) {
return $canceledEntities;
}
}
Without an accessor, this query will return a collection containing two entities with id [ 2, 4 ].
But with an accessor (as defined in the model), it can't find a matched entity because the WHERE clause expects that the 3rd parameter is 'Canceled' instead of 3.
My alternative method is to use a string 'Canceled' in the 'where' clause. However, I still want to use the value stored in a database for the query, and I think maybe the framework has another way to write an Eloquent Collection query without invoking an accessor.
Any suggestions are always welcome.
This eloquent collection provides this result:
$id = Model::where('s_id', $s_id)->pluck('l_id');
print_r($id)
Illuminate\Support\Collection Object
(
[items:protected] => Array
(
[0] => 31242682774
)
)
How do I return only the "31242682774" value as a string and not a collection?
EDIT ANSWER:
All I had to do is:
$id = Model::where('s_id', $s_id)->pluck('l_id')->first();
Any better options?
If you only need a single value, not multiple values, pluck isn't what you want. There is a method called value on Query Builder that returns a single value:
Model::where('s_id', $s_id)->value('l_id');
Laravel 6.x Docs - Query Builder - Retrieving Results - Retrieving A Single Row / Column From A Table value
It compares to when it the process you wanna do it. On the query execution or after. The most common approach would probably be.
$id = Model::where('s_id', $s_id)->first()->l_id;
This will execute after, meaning the query builder will fetch all columns in the row. In general in Laravel you don't that often work with strings and or other abstractions than your model. Model::where('s_id', $s_id)->first() will return your model and select the l_id property on it.
The approach you chosen is the database way, you only select the l_id and return it as a collection and select the first item from there. This is thou a very performance efficient way of doing it since the database does all the work and is very quick at it.
$id = Model::where('s_id', $s_id)->pluck('l_id')->first();
The reason why it is a collection, it is mainly made for selecting multiple id's, so if you query returned multiple rows multiple ids would be returned. Here you can see an example of pluck in conditional queries, where it is most often used.
$teamIds = Team::where('type', 'admin')->pluck('id');
$adminUsers = User::where('team_id', $teamIds)->get();
Your solution is perfect for what you need, just trying to bring clarity on why and a example of how it is often used.
I have a table that has a one-to-many relationship with another table.
Call them tables parent and child
child has a field called field1
I am trying to get an array of all field1 values.
In the parent Model, I have this function that gets me all children of parent
public function children()
{
return $this->hasMany(Child::class);
}
Now, in the parent model, I also want to get all field1 values.
I can get all the children like so:
$children = $this->children->all();
But I just can't figure out how to then index into this to get all the field1 values.
Maybe it is better to just use $this->children in which case it is a Collection and then use some sort of Collection method to extract field1?
I tried
$this->children->only(['field1'])
but that returned nothing, even though field1 certain exists.
Ideas?
Thanks!
You can use pluck method of collecion to get an array of field1 values:
$parent->child->pluck('field1');
Or better, you can use pluck method of query builder (see section Retrieving A List Of Column Values), being even more efficient, with same result:
$parent->child()->pluck('field1');
map() is the function you are looking.
$children = $this->children->all()->map(function($children) {
return $children->field1;
});
A shorter version using Higher Order Message.
$children = $this->children->all()->map->field1;
I am new to laravel and confused about some query methods.
find($id) is useful and returns a nice array, but sometimes I need to select by other fields rather than id.
The Laravel document said I could use where('field', '=', 'value') and return a bunch of data, which is fine.
What I can't understand is why I need to add ->first() every time, even if I am pretty sure there is only one single row matches the query.
It goes like this:
$query->where(..)->orderBy(..)->limit(..) etc.
// you can chain the methods as you like, and finally you need one of:
->get($columns); // returns Eloquent Collection of Models or array of stdObjects
->first($columns); // returns single row (Eloquent Model or stdClass)
->find($id); // returns single row (Eloquent Model or stdClass)
->find($ids); // returns Eloquent Collection
// those are examples, there are many more like firstOrFail, findMany etc, check the api
$columns is an array of fields to retrieve, default array('*')
$id is a single primary key value
$ids is an array of PKs, this works in find method only for Eloquent Builder
// or aggregate functions:
->count()
->avg()
->aggregate()
// just examples here too
So the method depends on what you want to retrieve (array/collection or single object)
Also the return objects depend on the builder you are using (Eloquent Builder or Query Builder):
User::get(); // Eloquent Colleciton
DB::table('users')->get(); // array of stdObjects
even if I am pretty sure there is only one single row matches the query.
Well Laravel cant read your mind - so you need to tell it what you want to do.
You can do either
User::where('field', '=', 'value')->get()
Which will return all objects that match that search. Sometimes it might be one, but sometimes it might be 2 or 3...
If you are sure there is only one (or you only want the first) you can do
User::where('field', '=', 'value')->first()
get() returns an array of objects (multiple rows)
while
first() returns a single object (a row)
You can of course use get() when you know it will return only one row, but you need to keep that in mind when addressing the result:
using get()
$rez = \DB::table('table')->where('sec_id','=','5')->get();
//will return one row in an array with one item, but will be addressed as:
$myfieldvalue = $rez[0]->fieldname;
using first()
$rez = \DB::table('table')->where('sec_id','=','5')->first();
// will also return one row but without the array, so
$myfieldvalue = $rez->fieldname;
So it depends on how you want to access the result of the query: as an object or as an array, and also depends on what "you know" the query will return.
first() is the equivalent of LIMIT 1 at the end of your SELECT statement. Even if your query would return multiple rows, if you use first() it will only return the first row