unable to define relationship in laravel 5.7 - php

I have two table as sbj_topics and difficulty_level_sbj_topic so, I want to define relationship b\w them to fetch records, so to make relationship I have done this,
SbjTopic.php:
public function difficulty_level_sbj_topic() {
return $this->hasMany('App\DiffiLvlSbjTopic');
}
And in DiffiLvlSbjTopic.php:
protected $table = 'difficulty_level_sbj_topic';
public function sbj_topics() {
return $this->belongsTo('App\SbjTopic');
}
After that I returned the data to a view as:
$easy = DiffiLvlSbjTopic::where(['subject_id' => $id, 'difficulty_level_id' => 2])->get();
return view('diffi_lvls.show', compact('easy'));
Then in the view I done this:
#foreach($easy as $easy)
{{ $easy->sbj_topics }}
#endforeach
but the page is blank, and when I do this {{ $easy->sbj_topics->sbj_topic_name }} trying to get property of undefined! comes.
The main purpose of creating relationship is to display Subject Topic Name because I have foreign key as sbj_topic_id in difficulty_level_sbj_topic table so if anyone has any other idea to do this without relationship that will be awesome.

Break this down:
SbjTopic - has many difflevels
a difflevel belongs to aSbjTopic
With this understanding, I can see you are getting the difflevels (DiffiLvlSbjTopic). This is actually what you are passing to your blade.
So first off: complete your relationship by specify the foreign keys. i.e:
In the SbjTopics model:
public function difficulty_level_sbj_topic() {
return $this->hasMany('App\DiffiLvlSbjTopic', 'subject_id');
}
with this, you know that in the 'difficulty_level_sbj_topic' you must have the column subject_id.
Now define the reverse relationship in your DiffiLvlSbjTopic model:
public function sbj_topics() {
return $this->belongsTo('App\SbjTopic', 'subject_id');
}
With all these in place in your controller or route all you need to do is fetch the DiffiLvlSbjTopic model properties. For instance:
public function index () {
$easy = DiffiLvlSbjTopic::all();
return view('diffi_lvls.show', compact('easy'));
}
Finally in your view:
#foreach($easy as $difflevel)
<div>{{ $difflevel->sbj_topics->name }} </div>
#endforeach
That's it.

Your both variables should not be $easy it can be something like $easy as $easySingle. And add a loop inside like
#foreach($easy as $easySingle)
foreach ($easySingle->sbj_topics as $topic) {
$topic->property;
}
#endforeach

Related

undefined variable when trying to fetch data from database laravel

Hi I'm having trouble getting data from database after adding a new function inside my controller. Can anyone explain to me this error and what should I do?
Background information: I have 3 different type of tables, personal_infos, user_infos and user_info1s table where personal_infos hasMany user_infos and user_info1s. I am using user_id as a foreign key to link together with personal_infos table
I'm using this video as a reference and want to do something like his end result (see 17.17 of video), but I get this error:
Error: Undefined variable: data
What I want to do:
Route.php
Route::get('/home/{id}', 'HomeController#getData')->name('home');
HomeController
public function getData($id) {
$data['data'] = DB::table('personal_infos')->get()->sortByDesc('upload_time');
if (count($data) > 0) {
return view('home',$data)
->with('test', personal_info::find($id)); // --> after adding this got error
} else {
return view('home');
}
}
Home.blade.php
<table class="table table-bordered">
<tr>
<th><strong><big>Name: </big></strong></th>
</tr>
<td>
<tr>
#foreach($data as $value)
<tr>
<th>{{HTML::link_to_route('home',$value->Name, array($value->id)) }}</th>
</tr>
#endforeach
</tr>
</tr>
</table>
Code that I have now after some changes:
HomeController:
public function getData($id = null){
$data['data'] = DB::table('personal_infos')->orderBy('created_at', 'desc')->get();
return view('home')
->with('personalInfos', $personalInfos)
->with('test', personal_info::find($id));
}
}
home.blade.php
<ul>
#foreach ($personalInfos as $info)
<li>{{ HTML::link_to_route('home', $info->Name, [ $info->id ]) }}</li>
#endforeach
</ul>
Route
Route::get('/home/{id?}', 'HomeController#getData')->name('home');
personal_info model: (don't know if needed but just in case)
class personal_info extends Eloquent
{
protected $fillable = array('Email', 'Name', 'Mobile_No');
protected $table = 'personal_infos';
protected $primaryKey = 'id';
public function user_infos() {
return $this->hasMany('App\user_info','user_id');
}
public function user_info1s() {
return $this->hasMany('App\user_info1','user_id');
}
}
user_info1 and user_info (they are similar so I will just put 1 of them)
class user_info1 extends Eloquent
{
protected $fillable = array('hobby','sport','user_id');
public function personal_infos() {
return $this->belongsTo('App\personal_info', 'user_id', 'id');
}
}
I can tell you're learning Laravel. There are several issues with the code posted in your question. Let's walk through each of these to see if we can improve your understanding.
First, let's take a look at the controller method signature:
public function getData($id)
This method expects an $id parameter defined in the corresponding route. However, if we take a look at the route:
Route::get('/home/(:any)', 'HomeController#getData')->name('home');
...it doesn't properly declare that the URL contains a parameter (the video you're watching is about a very old version of Laravel). As described in the docs, we'll need to change the route signature to include a parameter for $id:
Route::get('/home/{id}', 'HomeController#getData')->name('home');
Next, let's see how the controller method fetches its data:
$data['data'] = DB::table('personal_infos')->get()->sortByDesc('upload_time');
This query fetches all records from personal_infos into a Collection, and then sorts them by upload_time. This is fine, but database engines can usually sort data faster than our PHP application, so we can instruct the DB to sort our data for us:
$data['data'] = DB::table('personal_infos')->orderBy('upload_time', 'desc')->get();
Notice how we changed the call to sortByDesc() on the collection to orderBy() for the database query. Now, the database sorts the results for us, so the collection doesn't need to.
Finally, let's try to fix the error you experience when passing the data to the view. Here's how your controller method currently does it:
if (count($data) > 0) {
return view('home', $data)
->with('test', personal_info::find($id)); // --> after adding this got error
} else {
return view('home');
}
There are a couple problems with the code above:
count($data) will always be greater than zero, because we're setting $data['data'] every time we call the method, so the else block will never execute. This is probably fine because...
...when count($data) equals zero, the controller doesn't pass the view any data, so $data in the view will be undefined.
The view in question uses #foreach to loop through each of the results, so we can simplify the code in the controller method because foreach won't iterate over an empty collection:
$personalInfos = DB::table('personal_infos')->orderBy('upload_time', 'desc')->get();
return view('home')
->with('personalInfos', $personalInfos)
->with('test', personal_info::find($id));
The view will receive two variables from the method above: $personalInfos and $test. I took the liberty of renaming $data['data'] into a more meaningful variable. This becomes very important as the project grows. Here's how we can use the data in the view:
<ul>
#foreach ($personalInfos as $info)
<li>{{ HTML::link_to_route('home', $info->Name, [ $info->id ]) }}</li>
#endforeach
</ul>
The template above outputs an unordered list as shown in the image in the question. The original table contains several row/column nesting errors and will not display the information like the question describes. As we can see, this template loops through each result in $personalInfos. If $personalInfos is empty, the list will not display any items.
If we want our controller method to handle the route with or without an ID, we'll need to tell Laravel that the ID is optional. For the route, a question mark (?) after the parameter makes it optional:
Route::get('/home/{id?}', 'HomeController#getData')->name('home');
Then, we can set a default value for the controller method that handles the route. In this case, we'll use null:
public function getData($id = null)
Of course, after we update this, we'll need to change the method to handle a null $id argument, which we use to fetch a personal_info for the view's $test variable. The question doesn't explain how the view uses $test, so I'll leave this as an exercise to the reader :)
Follow are two ways to pass multiple variables to view:
//Passing variable to view using with Method
return view('home')->with(['test'=>personal_info::find($id),'data'=>$data['data']]);
//Passing variable to view using Associative Array
return view('home', ['test'=>personal_info::find($id),'data'=>$data['data']]);

Laravel get record from database in blade view

I would like to known how to get data from database in blade like from User table:
{{ Auth::user()->name }}
I have table user_settings
I would like to get record from this table by logged user id like this:
{{ UserSettings::user()->my_field }}
How can I do that?
Try this on your blade view
{{ \App\UserSettings::where('user_id',Auth::user()->id)->first()->my_field }}
In default, model file is inside App folder.
Such direct access to database table is not preferred though, you can return this as a variable from controller function like,
$field = \App\UserSettings::where('user_id',Auth::user()->id)->first()->my_field;
return view('view_name',comapact('field'));
and use in blade like
{{$field}}
Another good way is posted by Orkhan in another answer using eloquent relationship.
Hope you understand.
You need to retrieve the UserSettings associated to the authenticated user:
UserSettings::where('user_id', Auth::id())->first()->my_field
You can defined a method named current() to return that for you.
class UserSettings extends Model
{
public static function current()
{
return UserSettings::where('user_id', Auth::id())->first()
}
}
Then use:
UserSettings::current()
On the other had it would better to use one-to-one relationship on user model:
class User extends Model
{
public function settings()
{
return $this->hasOne('App\UserSettings');
}
}
Then use:
Auth::user()->settings->my_field

Twig showing keys also instead of only values

I am using Laravel 5.3 along with Twig templating engine (Not Blade). I am trying to generate a list of drop-down list in the form. Instead of showing just the values. It is showing the keys as well.
For example:
{"display_name":"Admin"}
In my view the code is
{{ form_select('roles', roles, input_get('role'), {id:'user_type',class:'form-control'}) }}
In the controller
public function create()
{
$roles = Role::all('display_name');
return view('users.user-add')->with(['roles' => $roles]);
}
What am I missing?
I would suggest you to create a helper for this so that there is no requirement for you to pass roles from every controller to every view. Create a helper function like this :
if(!function_exists('getRoles'))
{
function getRoles()
{
$roles = Role::get();
foreach ($roles as $role)
{
$results[$role->id] = $role->name;
}
return $results;
}
}
and now in your template do :
{{ form_select('roles', getRoles(), input_get('role'), {id:'user_type',class:'form-control'}) }}
I hope I understood your question as intended and this helps you achieve what you are looking for.

Laravel get relationship or all objects

I'm using Laravel 5.2. In my application, if a user is an admin, he can see all groups. Otherwise, he can only see his groups.
Model
public function groups() {
if ($this->isAdmin()) {
return \App\Group::get();
}
return $this->belongsToMany('App\Group');
}
View
#foreach($user->groups as $group)
{{ $group->name }}
#endforeach
Result
The code above works if the user is not an admin, but I get this error if the user is an admin
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
I tried this instead: $user->groups() as $group, it works when the user is an admin, but show nothing when it's not an admin.
Question
I know when I call a relation as a property ($user->groups), it returns a collection of objects. Instead, if I call it as a function ($user->groups()), I get a QueryBuilder instance.
What can I do to use the same syntax as in my view ?
Note: I cannot add all groups in the database to the admin, as admins must have no group.
The way is not using directly relationship for this but using extra method to handle this.
First in your model create simple relationship:
public function groups()
{
return $this->belongsToMany('App\Group');
}
and then create extra method:
public function availableGroups()
{
if ($this->isAdmin()) {
return \App\Group::get();
}
return $this->groups;
}
Now in view you can use:
#foreach($user->availableGroups() as $group)
{{ $group->name }}
#endforeach

Query foreign key data from Blade template

I have two models: MenuCategory and MenuItem, I want to display MenuItem data on my blade page along with its MenuCategory. I know its possible to do this by adding it to the return data in my controller however I would like to do it leveraging Eloquent instead, however I receive errors.
Here are my codes:
MenuCategory model
public function items()
{
return $this->hasMany('App\MenuItem');
}
MenuItem model
public function category()
{
return $this->belongsTo('App\MenuCategory');
}
Controller
public function show($id)
{
$item = MenuItem::findOrFail($id);
return view('menu.admin.single', compact('item'));
}
Blade Page
{{ $item->category->name }}
UPDATE:
Table menu_item
id
name
menu_category_id
Table menu_category
id
name
When using all the above I get the following error:
Trying to get property of non-object
This error is due to the naming convention of Eloquent.
Provide the optional foreign key variable in your relationship method to make it work, ie.
$this->belongsTo('App\MenuCategory', 'menu_category_id');
Probably every Item doesn't contain a related category but to make sure you may try something like this, it'll try to retrieve the name only if there is a related category is available:
{{ $item->category ? $item->category->name : 'No Name or empty string' }}
Alternatively you may try something like this:
$item = MenuItem::has('category') // check if there is a related category
->with('category') // if yes then load it with that category
->findOrFail($id);
You used a different foreign key than Laravel expect so explicitly mention it like:
public function category()
{
return $this->belongsTo('App\MenuCategory', 'menu_category_id', 'id');
}

Categories