call model relation function in controller laravel - php

In my Model I have the function
App\Akte.php
public function lvs() {
return $this->hasMany('App\lvs', 'lv_id');
}
In my Controller I call
public function index()
{
$aktes = \App\Akte::all();
return view('admin.akte.index', ['aktes' => $aktes]);
}
And i´d like to extend my collection $aktes with the lvs table. Can somebody explain how to do this?
So my result should be a collection in which every single element of "Akte" has its Many collections of lvs in it..

If you also want the relationship loaded, just use:
$aktes = \App\Akte::with('lvs')->get();

See that. May be usefull for your needs.
https://laravel.com/docs/5.7/eloquent-relationships
public function index()
{
$aktes = \App\Akte::->all()->where('lvl', 2);
return view('admin.akte.index', ['aktes' => $aktes]);
}
somthing like this ...

Related

how can I use multiple methods in a route?

I would like to understand how to associate more methods to my route. For example:
Route::get('/dashboard', 'DController#showX')->middleware('auth');
Besides showX() I have another function called showY() that I would like to associate with the route, but if I rewrite it twice it doesn't go, how can I solve the problem?
Controller:
public function showY(){
$name=Auth::user()->name;
return view('dashboard',['name'=>$name]);
}
public function showX(){
$y= Y::all();
}
There is no way to do it from the route like that. How would you handle two return values?
Judging by the controller methods, maybe you want to use the value of showX in showY?
The way I see to handle this would be to have one method in the route:
Route::get('/dashboard', 'DController#show')->middleware('auth');
and have it fire both of your other methods:
public function show() {
// decide what to return
$xValue = $this->showX();
return $this->showY($xValue);
}
protected function showY($y){
$name=Auth::user()->name;
return view('dashboard',['name' => $name, 'y' => $y]);
}
protected function showX(){
$y= Y::all();
}

Laravel getAttribute not appended to the model

I have added a accessor to my User.php model getArticlesCountAttribute
protected $appends = ['articles_count'];
public function getArticlesCountAttribute()
{
return (int) $this->articles()->count();
}
but when i access it from my laravel blade views articles count database query runs every-time i use the accessor in my view
For example: if i have Auth::user()->articles_count 3 times in my blade view it will run articles count query 3 times.
Shouldn't it be appended at the start and query should only run once no matter how many times i reference it in my views?
I think you should not cache or store it. It is still a model and a model should not have this kind of implementations.
You should restructure your view and pass the result of the count from the controller to the view.
public function myAction()
{
return view('myview', [
'articleCount' => Auth::user()->articles_count
]);
}
And in the view have than once the result in the variable $articleCount.
Try this one code
protected $hidden = ['articles_count'];
public function getArticlesCountAttribute()
{
return (int) $this->articles()->count();
}
You just have to access the attribute, not the method:
protected $appends = ['articles_count'];
public function getArticlesCountAttribute()
{
return (int) $this->articles->count();
}
This way if articles is not loaded it will be the first time :)
You could cache it, for example:
protected $articlesCounted;
public function getArticlesCountAttribute()
{
if (is_null($this->articlesCounted)) {
return $this->articlesCounted = $this->articles()->count();
}
return $this->articlesCounted;
}

Relationship method must return an object in laravel eloquent

I am trying to find a row with condition and that is...
A user has many profile pictures but there is one picture that is is_main
So this is what I wrote
public function profile_picture()
{
return $this->hasMany('App\User_profile_picture');
}
public function active_picture()
{
return $this->profile_picture()->find($this->is_main);
}
Now when I access it through
$picture = Auth::user()->active_picture;
It says
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
What is that I have to do to make it work?
Your code should be
public function profile_picture()
{
return $this->hasMany('App\User_profile_picture');
}
You are missing the return statement
If you want to use a Model method as a property, it has to return a relationship. Otherwise you need to call it as a method with the () operator. Like explained here.
So the solution to your question would be:
$picture = Auth::user()->active_picture();
edit: TIL you can also set a custom eloquent accessor:
public function getActivePictureAttribute()
{
return $this->profile_picture()->find($this->is_main);
}
$picture = Auth::user()->active_picture;
Yeah, you have to write the get...Attribute in camelCase, and can then use the attribute in snake_case/kebab-case or camelCase. (See the eloquent $snakeAttributes boolean variable.)
I think you can try this:
public function profile_picture()
{
return $this->hasMany('App\User_profile_picture');
}
public function active_picture()
{
return $this->profile_picture()->find($this->is_main);
}
Hope this work for you !!!
You must use class:
public function profile_picture()
{
return $this->hasMany(App\User_profile_picture::class);
}

Laravel: One Controller for multiple Models

I'm currently rebuilding my vanilla-PHP-App with Laravel and I have the following problem.
I have multiple database-tables, that represent word categories (noun, verb, adverb, ...). For each table I created a separate Model, a route::resource and a separate resource-Controller. For example:
NomenController.php
public function show($id)
{
$vocab = Nomen::find($id);
return view('glossarium.vocab_update', compact('vocab'));
}
and
VerbController.php
public function show($id)
{
$vocab = Verb::find($id);
return view('glossarium.vocab_update', compact('vocab'));
}
...which are essentially the same except the Model class.
I don't want to create a separate Controller for each model, that does exactly the same. What would be the most simple and elegant way to solve this?
Should I just create a VocabController.php and add a parameter for the Model-name like:
Route::resource('/vocab/{category}', 'VocabController');
and then add a constructor method in this controller like
public function __construct ($category) {
if ($category == 'nomen') {
$this->vocab = App\Nomen;
}
else if ($category == 'verb') {
$this->vocab = App\Verb;
}
}
I wonder if there is a simpler method to do that. Can I somehow do this with Route Model Binding?
Thanks in advance
Simply create a trait like this in App\Traits, (you can name it anything... Don't go with mine though... I feel its pretty lame... :P)
namespace App\Traits;
trait CommonControllerFunctions {
public function show($id) {
$modelObject = $this->model;
$model = $modelObject::find($id);
return view('glossarium.vocab_update', compact('model'));
}
}
and in your NomenController and VerbController, do this:
use App\Traits\CommonControllerFunctions;
class NomenController {
use CommonControllerFunctions;
protected $model = Nomen::class;
}
and
use App\Traits\CommonControllerFunctions;
class VerbController {
use CommonControllerFunctions;
protected $model = Verb::class;
}
Note: Please note that this example is just a work-around for your particular situation only... Everyone practices code differently, so this method might not be approved by all...
I think the simpliest way it to create only one controller, eg VocabController with methods nomen, verb and whatever you want.
Routes:
Route::get('/vocab/nomen/{nomen}', 'VocabController#item');
Route::get('/vocab/verb/{verb}', 'VocabController#item');
And the model binding:
Route::model('nomen', 'App\Nomen');
Route::model('verb', 'App\Varb');
Then your method shoud look like that:
public function item($item)
{
return view('glossarium.vocab_update', $item);
}
Keep in mind, that $item is already fetched model from the database.

Laravel: Pass Parameter to Relationship Function?

Is it possible to pass, somehow, a parameter to a relationship function?
I have currently the following:
public function achievements()
{
return $this->belongsToMany('Achievable', 'user_achievements')->withPivot('value', 'unlocked_at')->orderBy('pivot_unlocked_at', 'desc');
}
The problem is that, in some cases, it does not fetch the unlocked_at column and it returns an error.
I have tried to do something like:
public function achievements($orderBy = true)
{
$result = $this->belongsToMany (...)
if($orderBy) return $result->orderBy(...)
return $result;
}
And call it as:
$member->achievements(false)->(...)
But this does not work. Is there a way to pass parameters into that function or any way to check if the pivot_unlocked_at is being used?
Well what I've did was just adding new attribute to my model and then add the my condition to that attirbute,simply did this.
Class Foo extends Eloquent {
protected $strSlug;
public function Relations(){
return $this->belongsTo('Relation','relation_id')->whereSlug($this->strSlug);
}
}
Class FooController extends BaseController {
private $objFoo;
public function __construct(Foo $foo){
$this->objFoo = $foo
}
public function getPage($strSlug){
$this->objFoo->strSlug = $strSlug;
$arrData = Foo::with('Relations')->get();
//some other stuff,page render,etc....
}
}
You can simply create a scope and then when necessary add it to a builder instance.
Example:
User.php
public function achievements()
{
return $this->hasMany(Achievement::class);
}
Achievement.php
public function scopeOrdered(Builder $builder)
{
return $builder->orderBy(conditions);
}
then when using:
//returns unordered collection
$user->achievements()->get();
//returns ordered collection
$user->achievements()->ordered()->get();
You can read more about scopes at Eloquent documentation.
You can do more simple, and secure:
When you call the relation function with the parentesis Laravel will return just the query, you will need to add the get() or first() to retrieve the results
public function achievements($orderBy = true)
{
if($orderBy)
$this->belongsToMany(...)->orderBy(...)->get();
else
return $this->belongsToMany(...)->get();
}
And then you can call it like:
$member->achievements(false);
Works for the latest version of Laravel.
Had to solve this another was as on Laravel 5.3 none of the other solutions worked for me. Here goes:
Instantiate a model:
$foo = new Foo();
Set the new attribute
$foo->setAttribute('orderBy',true);
Then use the setModel method when querying the data
Foo::setModel($foo)->where(...)
This will all you to access the attribute from the relations method
public function achievements()
{
if($this->orderBy)
$this->belongsToMany(...)->orderBy(...)->get();
else
return $this->belongsToMany(...)->get();
}

Categories