I have this Accessor bellow which returns one string result (example: 'Ready' or 'Ongoing' ...):
public function getMinimumStatusAttribute()
{
$statusIds = [];
$tasks = $this->tasks()->get();
foreach ($tasks as $task) {
array_push($statusIds, $task->task_status_id);
}
return taskStatus::orderBy('order', 'asc')
->where('operational_status', '=', true)
->whereIn('id', $statusIds)->value('name');
}
I have TeamleaderDeal model :
return TeamleaderDeal::all();
which returns:
[
{
"id": 4,
"teamleader_id": "8b03da5a-af1f-051d-ad6d-b6199c7f7c35",
"created_at": "2019-09-09 11:41:46",
"updated_at": "2019-09-14 20:57:03",
"title": "Brand identity #2",
"reference": "12",
"lead_company_id": "adeddc13-6962-0a19-ac72-6713d1cf1455",
"teamleader_company_id": 1,
"dealphase_id": "199a34fc-de5c-038d-a655-c61fa4d97d17",
"estimated_closing_date": null,
"po_number": "az215487",
"teamleader_deal_phase_id": 6,
"dealPhase": "Refused",
"tasksCount": 5,
"companyLanguage": "nl",
-------------------------
"minimumStatus": "ready", ||||||accessor results
-------------------------
"invoiced": 1,
(...)
I would like to filter TeamleaderDeal results by MinimumStatus to show for example only results where MinimumStatus equal to 'Ready' ?
Thanks
You may use
public function getMinimumStatusAttribute($minimumStatus = NULL) {
if($minimumStatus === 'Ready') {
// do the magic here
$statusIds = [];
$tasks = $this->tasks()->get();
foreach ($tasks as $task) {
array_push($statusIds, $task->task_status_id);
}
return taskStatus::orderBy('order', 'asc')
->where('operational_status', '=', true)
->whereIn('id', $statusIds)->value('name');
}
// else return default value
return $this->attributes['minimum_status'];
}
Edit
Regarding your updates you may use reject method provider by Laravel Collection
E.g
$teamleaderDeals = TeamleaderDeal::all();
return $teamleaderDeals->reject(function ($teamleaderDeal) {
return $teamleaderDeal->minimumStatus !== 'Ready';
});
I think you need this simple where clause:
return taskStatus::orderBy('order', 'asc')
->where('operational_status', '=', true)
->where('name', 'Ready')
->whereIn('id', $statusIds)->value('name');
What are accessors?
Accessors create a dummy attribute on the object which you can access as if it were a database column. So if your database has user table and it has FirstName and LastName column and you need to get full name then it will be like.
Syntax of accessors:
get{Attribute}Attribute
Example :
public function getFullNameAttribute(){ return $this->FirstName. " ".$this->LastName;}
After that you can get full user name with below accessors.
{{ $user->full_name }}
After that you can get full user name with below accessors.
{{ $user->full_name }}
What is Mutator ?
Mutator is use to set value of attribute, a mutator transforms an eloquent attribute value when it is set.
How to define a mutator,
set{Attribute}Attribute
Above method on your model where {Attribute} is the "studly" cased name of the column you wish to access.
Example :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Register extends Model
{
/**
* Set the user's first name.
*
* #param string $value
* #return void
*/
public function setNameAttribute($value)
{
$this->attributes['name'] = strtolower($value);
}
}
Now you can use this in your controller like.
use App\Models\Register;
$register= Register::find(1);
$register->name = 'Websolutionstuff';
Related
I have been trying to get all authors from collections of books.
$books = Books::all();
foreach($books as $book){ $book->author ...
This code will work, but i want to get all author without using loop
$allAuthorsThruBooks = Books::someQueryMaybe();
$allAuthorsThruBooks will show list of author.
Thanks!
Assuming all your Model is inside Models directory App\Models
Books Model
use App\Models\Author;
...
Class Books extends Model
{
public function author()
{
return $this->belongsTo(Author::class, 'author_id');
}
}
Query
$books = Books::with(['author'])->get();
// with condition
$books = Books::with(['author' => function($query)
$query->where(...);
])->get();
Example Result
[
id: 1,
name: 'Book One',
author: [
id: 1,
name: 'Maddog'
]
],
[...]
Method 01
Try pluck
$authorList = collect($books)->pluck('author')->unique();
// use ->toArray() if you want to convert into array
Method 02
Create helper
namespace App\Helpers;
use Illuminate\Support\Arr;
class ArrHelper
{
public static function onlyValues($array = [], $keys = [])
{
return array_filter(
array_values(
Arr::only($array, $keys)
)
);
}
}
In controller
$authorList = collect(ArrHelper::onlyValues($books, ['author']));
I define the relation in Company table (where I added the plural):
protected $table = 'companies';
public function country() {
return $this->belongsTo(Country::class, "country_id")->withDefault(['country' => 'unknown']);
}
I also did the same in the Country model.
When I use the following code in the controller show function it works:
public function show (Company $company) {
$company->country = $company->country()->pluck('country');
But if I use the same code in the index function in a loop, I get an error "Call to undefined method stdClass::country()":
public function index (Company $company) {
if (request('tag')) {
$companies = Tag::where('name',request('tag'))->firstOrFail()->companies;
$companies->page_title = "Businesses matching tag '".request('tag')."'";
} else {
$companies = DB::table('companies')
->where([['is_active', '=', '1']])
->orderBy('company')
->get();
}
foreach($companies as $key => $thisCompany) {
...
$thisCompany->country = $company->country()->pluck('country');
}
I guess it is due to the fact that $company is created in the loop and not passed through the function like in show(Company $company)... but I could not find how to solve this issue... so help will be appreciated.
I have added the model in the argument of the function and change the name of the $company variable in the loop by $thisCompany to avoid confusion with the $company model.
No error but the field $country->country does not contain the name of the country but "Illuminate\Support\Collection {#443 …1}"
Why is it so complicated? Please help...
Paul, sorry, I think I didn't explain myself well in the comments.
What I meant by "What about if you change DB::table('companies') by Company?", is to stop using DB Query Builder to use the Eloquent Company model.
Specifically in this segment of code:
$companies = DB::table('companies')
->where([['is_active', '=', '1']])
->orderBy('company')
->get();
So, it could be:
$companies = Company::where([['is_active', '=', '1']])
->orderBy('company')
->get();
The explanation is that in the first way (with DB Query Builder), the query will return a collection of generic objects (the PHP stdClass object) that do not know anything about the Company and its relationships.
On the other hand, if you use the Eloquent model Company, it will return a collection of Company objects, which do know about relationships, and specifically the relationship that you have defined as country.
Then, when you loop over the collection, you will be able to access the country relation of each Company object:
foreach($companies as $key => $company) {
//...
$company->country = $company->country()->pluck('country');
}
Finally, your code could looks like:
public function index () {
if (request('tag')) {
$companies = Tag::where('name',request('tag'))->firstOrFail()->companies;
$companies->page_title = "Businesses matching tag '".request('tag')."'";
} else {
$companies = Company::where([['is_active', '=', '1']])
->orderBy('company')
->get();
}
foreach($companies as $key => $company) {
//...
$company->country = $company->country()->pluck('country');
}
//...
}
enter image description hereI am trying to implement a many to many relationship search with 2 models.
i get input from multiple checkbox values and want to search for items that match A or B when there is an input of data.
I read this url and wrote the same logic.
https://laracasts.com/discuss/channels/laravel/many-to-many-relationship-with-2-pivot-table-data-search
public function search(Request $request)
{
$languages = $request->lang;
$fields = $request->field;
$agencies = Agency::with('languages')->with('specialized_fields')
->orWhereHas('languages', function($query) use ($languages) {
$query->whereIn('language_id', $languages);
})
->orWhereHas('specialized_fields', function($query) use ($fields) {
$query->whereIn('specialized_field_id', $fields);
})
->get();
dd($agencies);
}
i expected to achieve A or B search but instead I got this error.
Argument 1 passed to Illuminate\Database\Query\Builder::cleanBindings() must be of the type array, null given, called in /var/www/jtf/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php on line 907
it seems that it causes this error if either A or B is null, but why??? Does the OrWhereHas method work only when theres an input??
/added info/
my error message
my agency model
class Agency extends Model {
protected $guarded = [
'id'
];
public function languages(){
return $this->belongsToMany('App\Language');
}
public function specialized_fields(){
return $this->belongsToMany('App\SpecializedField');
}
public function region(){
return $this->hasOne('App\Region');
} }
I believe it's because either $languages or $fields is null.
Since ->whereIn() is expecting an array, but you're passing null.
You just need to make sure you're passing an array.
$languages = array_filter((array) $request->lang); // cast to array & remove null value
$fields = array_filter((array) $request->field);
$agencies = Agency::with('languages', 'specialized_fields')
->orWhereHas('languages', function($query) use ($languages) {
$query->whereIn('language_id', $languages);
})
->orWhereHas('specialized_fields', function($query) use ($fields) {
$query->whereIn('specialized_field_id', $fields);
})
->get();
I'm speculating that you started your where query chain with an orWhereHas() which may have caused the problem, try starting with whereHas() instead.
public function search(Request $request){
$languages = $request->lang;
$fields = $request->field;
$agencies = Agency::with('languages', 'specialized_fields') // you can get away by just using one with(), not needed but its cleaner this way
->whereHas('languages', function($query) use ($languages) { // previously orwherehas
$query->whereIn('language_id', $languages);
}) ->orWhereHas('specialized_fields', function($query) use ($fields) {
$query->whereIn('specialized_field_id', $fields);
})
->get();
dd($agencies);
}
I want this object only if it has all the necessary relationships.
At the moment my code:
StudentController
$student = Student::with('inscriptions','inscriptions.classroom')
->find($request->user()->id);
Student
public function inscriptions()
{
return $this->hasMany('App\InscribedStudent');
}
InscribedStudent - Note: "Registration Open"
public function classroom()
{
return $this->hasOne('App\Classroom', 'id')->where('registration_open', true);
}
Json Return When haven't registration opened
{
"inscriptions": [
{
"id": 1,
"student_id": 1,
"classroom_id": 1,
"deleted_at": null,
"created_at": "2019-07-04 23:34:48",
"updated_at": "2019-07-04 23:34:48",
"classroom": null
}
]
}
I want to do something like that, because I don't need the object InscribedStudent if I haven't a classroom.
public function inscriptions()
{
return $this->hasMany('App\InscribedStudent')
->hasOne('App\Classroom', 'id')
->where('registration_open', true);
}
You can use has() or whereHas() to check that the classroom exists.
https://laravel.com/docs/5.8/eloquent-relationships#querying-relationship-existence
// this will only get students that have a classroom through inscriptions
$students = Student::has('incriptions.classroom')
->with('inscriptions.classroom')
->get();
// this will get students, but only fetch inscriptions if there is a classroom
$students = Student::with(['inscriptions' => function($inscriptionQuery) {
$inscriptionQuery->has('classroom')->with('classroom');
}])
->get();
You can also make a custom scope on the Student model if you want to use that instead.
// this will only get students that have a classroom through inscriptions
public function scopeHasClassroom($query)
{
$query->has('inscriptions.classroom')
->with('inscriptions.classroom');
}
// this will get students, but only fetch inscriptions if there is a classroom
public function scopeHasClassroom($query)
{
$query->with(['inscriptions' => function($inscriptionQuery) {
$inscriptionQuery->has('classroom')->with('classroom');
}]);
}
Then you can call the custom scope like this:
$students = Student::hasClassroom()->get();
https://laravel.com/docs/5.8/eloquent#query-scopes
I'm kinda stuck with this here and don't know how to move forward with this one.
I have two Models: user and child and they are in a Relationship.
( Keep in mind that this only illustrate the problem )
class Child extends Model{
protected $primaryKey = 'id_child';
public $appends = ['is_alive'];
public function user(){
return $this->belongsTo('Models\User','id_user');
}
public function getIsAliveAttribute(){
if (!is_null($this->lifetime_updated_at))
return (Carbon::parse($this->lifetime_updated_at)->addMinute($this->lifetime) >= Carbon::now());
else
return false;
}
}
class User extends Model{
protected $primaryKey = 'id_user';
public $appends = ['is_alive'];
public function childs(){
return $this->hasMany('Models\Child','id_user');
}
public function getIsAliveAttribute(){
if (!is_null($this->lifetime_updated_at))
return (Carbon::parse($this->lifetime_updated_at)->addMinute($this->lifetime) >= Carbon::now());
else
return false;
}
}
Now I want to use Eager Loading in the Controller to retrieve my Childs data from User.
But my User Model Object comes from an MiddleWare in my Application. So I only have the User Model Object to use and I don't want to Query the User again using "with()".
$user = User::where('name','DoctorWho')->first();
return user->childs()->find(3);
What this operation returns:
{
"id_child": 3,
"name": "JayZ",
"last_name": "Etc",
"lifetime": 1,
"lifetime_updated_at": null,
"created_at": "2017-05-29 21:40:02",
"updated_at": "2017-05-29 21:40:02",
"active": 1
}
What I needed ( With Attribute Appended)
{
"id_child": 3,
"name": "JayZ",
"last_name": "Etc",
"lifetime": 1,
"lifetime_updated_at": null,
"created_at": "2017-05-29 21:40:02",
"updated_at": "2017-05-29 21:40:02",
"active": 1,
"is_alive": true
}
Is even possible to retrieve Child Data with Appended Attributes using Eager Loading ?
Notes: This user object come from an Middleware, I must use the User Model Object to get its child's with the appended attribute.
Thanks in Advance,
LosLobos
The thing is I was doing something wrong that is not related to Eloquent acessing the model like that does come with the appended attributes!
What you're doing here is not eager loading. Your childs relationship is wrong. Should be return $this->hasMany('Models\Child', 'id_user'); based on the model and the other relationship defined.
Here are some ways you can access the child information. These by default should respect the $appends property and load the field.
$childId = 3;
$user = User::with('childs')
->where('name', 'DoctorWho')
->first();
return $user->childs()->where('id_child', $childId)->first();
// Or
$user = User::with(['childs' => function ($query) use ($childId) {
$query->where('id_child', $childId);
}])
->where('name', 'DoctorWho')
->first();
return $user->childs->first();
// Or
$child = Child::whereHas('user', function ($query) {
$query->where('name', 'DoctorWho');
})
->find(3);
return $child;
Edit :
If you already have the user model then you can do this.
$child = Child::where('id_user', $user->id_user)
->where('id_child', 3)
->first();
return $child;