Laravel multilevel menu doesn't work - php

I have created multilevel menu by this example (first reply):
How to create a database-driven multi-level navigation menu using Laravel
I'm always getting empty array. Here's my database structure (database's name is also "structure")
structure_id and parent_id are relevant.
Here's my code:
App/navigation.php
<?php
namespace App;
use DB;
use Illuminate\Database\Eloquent\Model;
class Navigation extends Model {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'structure';
public function parent() {
return $this->hasOne('structure', 'structure_id', 'parent_id');
}
public function children() {
return $this->hasMany('structure', 'parent_id', 'structure_id');
}
public static function tree() {
return static::with(implode('.', array_fill(0, 4, 'children')))->where('parent_id', '=', NULL)->get();
}
}
and the Controller:
app/http/controllers/structurecontroller.php
<?php
namespace App\Http\Controllers\Superuser;
use App\Http\Controllers\Controller;
use App\Navigation;
use App\Structure as Model;
class StructureController extends Controller
{
/**
* Allow only for logged in
* DashboardController constructor.
*/
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
//$model = new Model();
//$items = $model->getStructure();
$items = Navigation::tree();
var_dump($items);exit;
return view('superuser.structure', ['items' => $items]);
}
}
I'm pretty sure, I have some data in database. So, what's the problem there? I'm getting always empty array from database. Thank for help

It's probably your database structure--you're declaring parent_id as NOT NULL, with a default of 0. In your tree function you then do this:
...->where('parent_id', '=', NULL)->get();
I'm going to guess that the "0" is not resolving to NULL like you intended.

// Do not forget to add import: App\structure
public function parent() {
return $this->hasOne('App\structure', 'structure_id', 'parent_id');
}

Related

Slug problems show with laravel

I have model:
class Header extends Model
{
use HasFactory;
public function getRouteKeyName()
{
return 'slug';
}
}
my controller:
public function show($id)
{
$headers = DB::table('headers')->find($id);
$blocks = DB::table('blocks')->where('header_id', $id)->get();
return view('test', compact('headers', 'blocks'));
}
my route:
Route::get('/{id}', [MainController::class, 'show'])->name('show');
but I can't show slug, I see localhost:8000/id
error: Attempt to read property "id" on null
You are using getRouteKeyName which is useful for Route-Key binding. But your route is not set up that way.
It also does not help you with the find() method in the Model.
Also, you are not using your model in your DB call. Any methods or properties defined in your model will therefore not be used.
And you should set up relationships to get related data.
Respecting your current route, you should do something like this:
class Header extends Model
{
use HasFactory;
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'slug';
// ^-- this is what you use to tell Model what column to use for find()
// only use this if you do route-model binding
public function getRouteKeyName()
{
return 'slug';
}
// relationship to find all blocks that belong to this header_id
public function blocks()
{
return $this->hasMany(\App\Model\Blocks::class);
}
}
Then for the DB Call:
public function show($id)
{
$header = Headers::find($id);
$blocks = $header->blocks ?? [];
return view('test', compact('header', 'blocks'));
}

Laravel models to implement one to many and many to many in single query

i have this table structure, project has one to many relation with rewards , rewards and shipping has many to many relation with pivot table reward_ship.
projects rewards shipping reward_ship
--------- -------- -------- ------------
id id id id
title amount location reward_id
amount project_id name ship_id
i am trying to extract one particular project details with all other associate tables data(rewards and shipping data using reward_ship table) in one query.
These is how i am trying
Projects Model
class Rewards extends Model {
public function projs(){
return $this->hasMany('App\Rewards');
}
public function rewds(){
return $this->belongsToMany('App\Shipping')
->withPivot('reward_ship', 'ship_id', 'reward_id');
}
public function shiplc(){
return $this->belongsToMany('App\Rewards')
->withPivot('reward_ship', 'ship_id', 'reward_id');
}
}
class Rewards extends Model {
public function proj() {
return $this->belongsTo('App\Projects');
}
}
Controller api class
Route::get('projects/{id}', function($id) {
$p = Projects::find($id);
$getd = Rewards::with('proj')
->where('rewards.project_id', '=', $p->id)
->get();
});
it doesn't work.
i search and tried many related model base query in larvel.
i know my implementation are wrong. Please suggest me to work out.
You can use Laravel 5.5 new feature API Resources.
It helps you to format the output of objects such as models or collections, to display attributes and also relationships.
So, you could do something like this in your ItemResource:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class Project extends Resource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request
* #return array
*/
public function toArray($request)
{
return [
'project_id' => $this->project_id,
'title' => $this->title,
'amount' => $this->amount,
// To access relationship attributes:
'rewards' => $this->rewards->load('shippings'),
];
}
}
Then in your controller, you just need to create a new Resource instance and pass the item object that you want to return:
use App\Http\Resources\Project as ProjectResource;
// some code
/**
* Show a single formatted resource.
*
* #param Project $project
* #return ProjectResource
*/
public function show($project)
{
return new ProjectResource($project);
}
// the rest of your code
The output should be the expected.
You have to fix the relationships that you have :
Projects Model :
public function rewards(){
return $this->hasMany('App\Rewards');
}
Rewards Model :
public function projects() {
return $this->belongsTo('App\Projects');
}
public function shippings(){
return $this->belongsToMany('App\Shipping','reward_ship', 'reward_id', 'ship_id');
}
Shipping model:
public function rewards(){
return $this->belongsToMany('App\Rewards','reward_ship', 'ship_id', 'reward_id');
}
After that you can call the relationships in the controller to eager load the wanted elements like this :
$project = Projects::with('rewards.shippings')
->where('id', $project_id)
->get();
And in the view you can loop over the rewards then get the shippings like this :
#foreach ($project->rewards as $reward)
<p>This is a reword {{ $reward->amount }}</p>
#foreach ($reward->shippings as $shipping)
<p>This is a shipping {{ $shipping->name }}</p>
#endforeach
#endforeach
class Project extends Model
{
public function rewds()
{
return $this->hasMany('App\Rewards');
}
public function shiplc()
{
return $this->hasManyThrough('App\Shipping', 'App\Rewards');
}
}
class Rewards extends Model
{
public function shiplc()
{
return $this->belongsToMany('App\Shipping');
}
public function projs()
{
return $this->belongsTo('App\Project');
}
}
class Shipping extends Model
{
public function shiplc()
{
return $this->belongsToMany('App\Shipping');
}
}
Route::get('projects/{id}', function($id) {
$p = Projects::with(['rewds', 'shiplc'])->find($id);
});
Project.php
class Project extends Model {
public function rewards() {
return this->hasMany(Reward::class, 'project_id', 'id');
}
}
Reward.php
class Reward extends Shipping {
public function shipping(){
return $this->belongsToMany(Shipping::class, 'reward_ship', 'reward_id', 'ship_id');
}
public function project(){
return $this->belongsTo(Project::class);
}
}
You can retrieve it like this:
$projectDetails = Project::where('id', $projectId)
->with(['rewards', 'rewards.shipping'])->get();

Class "MenuModel" not Found

I get this error when i try to run my Laravel
Class 'Menumodel' not found
in HasRelationships.php (line 487)
Here is my data structure
And this is MainComposer.php
<?php
namespace App\Http\ViewComposers;
use Illuminate\View\View;
use App\Menumodel as menu;
class MainComposer
{
public $items = [];
public function __construct()
{
$this->items = menu::tree();
}
public function compose(View $view)
{
$view->with('items', end($this->items));
}
}
MenuModel
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Menumodel extends Model
{
//
public $table = 'Menu';
protected $fillable = ['MenuParent','MenuName','MenuPath','MenuIcon','MenuOrder','RouteName'];
public function parent() {
return $this->hasOne('Menumodel', 'MenuCode', 'MenuParent');
}
public function children() {
return $this->hasMany('Menumodel', 'MenuParent', 'MenuCode');
}
public static function tree() {
return static::with(implode('.', array_fill(0, 4, 'children')))->where('MenuParent', '=', NULL)->get();
}
}
I aldredy try this use \App\Menumodel as menu; but still no different. How can i fix it ?
Your relationships are incorrect. You need to provide the full class namespace.
return $this->hasOne(Menumodel::class, '...', '...');
return $this->hasMany(Menumodel::class, '...', '...');
I've also removed your local and foreign keys because if using Laravel, these are typically snake_case, not StudlyCase, so you may need to double check those too.

Laravel 5.4 many to many relationships with foreign key

i'm using a data table with name auct_lots_full for my Lot.php model, where primary key is lot_id, in order everything to work i used Sofa/Eloquence extension, Mappable. So this is my model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Sofa\Eloquence\Eloquence;
use Sofa\Eloquence\Mappable;
class Lot extends Model
{
use Eloquence, Mappable;
protected $table = 'auct_lots_full';
protected $maps =[
'id' => 'lot_id',
];
public function scopeFilter($query, QueryFilter $filters)
{
return $filters->apply($query);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
}
But he problem is that in some cases it keeps looking for id column as primary key. For example in LotsController.php i have this problem here :
public function show($id)
{
$lot = Lot::find($id);
return view('lots.show')->withLot($lot);
}
But i fix this problem with this solution:
public function show($id)
{
$lot = Lot::where('lot_id', $id)->first();
return view('lots.show')->withLot($lot);
}
But i understand that is just a solution for only this function...
So the same problem i have in CommentsController.php:
public function show()
{
$comments = Comment::orderBy('id', 'desc')->paginate(30);
return view('comments.browse', compact('comments'));
}
And i don't know how to fix it. Could any one explain me why is this happening? Is there a better way than use an extension? How i can fix this error in CommentsCotroller.php ?
This is the Comment.php model:
<?php
namespace App;
class Comment extends Model
{
public function lot()
{
return $this->belongsTo(Lot::class);
}
public function User()
{
return $this->belongsTo(User::class);
}
}
There is a primaryKey variable in your Model file which is id by default.
/**
* The primary key for the model.
*
* #var string
*/
protected $primaryKey = 'id';
If you override this variable in Lot model file. So your primary key will be lot_id instead of id as in default. Simply add this;
protected $primaryKey = 'lot_id';
So actually i find a proper way to do it with out Sofa/Eloquence extension, using not only foreign key but also a local key in many to many relationship. So this is the new code:
so for Lot.php i did this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Lot extends Model
{
protected $table = 'auct_lots_full';
protected $primaryKey = 'lot_id';
public function scopeFilter($query, QueryFilter $filters)
{
return $filters->apply($query);
}
public function comments()
{
return $this->hasMany(Comment::class,'lot_id', 'lot_id');
}
}
Than i did same for the Comment.php model:
<?php
namespace App;
class Comment extends Model
{
public function lot()
{
return $this->belongsTo(Lot::class, 'lot_id', 'lot_id');
}
public function User()
{
return $this->belongsTo(User::class);
}
}
So what we see above, in Lot.php model, function comments i pass foreignKey: 'lot_id' in auct_lots_full table and localKey 'lot_id' in comments table witch refers to the auct_lots_full table. In Comment.php model wi did the same but in case instead of localKey it is ownerKey. Im a bad at explaining so i will attach some images to make sense.
Lot.php
Comment.php

How to get a specific column from the joined table in HasMany relationship in Laravel Eloquent

My Model looks like this
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class appraisaltask extends Model
{
//
protected $table = 'empappraisaltask';
/*
* An invoice can has many payments
*
*/
public function ratings(){
return $this->hasMany('App\appraisalrating','empappraisaltask_id')->select(array('comment', 'rating'));
}
}
and I am doing a query in my function like this
public function getUserbasictask(){
$taskwithcomments = appraisaltask::select(array('id','taskname','description','status'))->with( array('ratings' => function($query)
{
// the condition that will be apply on the with relation
$query->where('emp_id','=',Auth::user()->empid);
}))->where('type','=','basic')->get();
return json_encode($taskwithcomments);
}
But I am getting Empty Rating object . ANy suggestion how to do that
If I remove the select() from the rating function in the model I get all the details
Any help would be appreciated
i got your issue,update your ratings function in appraisaltask model
public function ratings()
{
return $this->hasMany('App\appraisalrating','empappraisaltask_id')->select(array('emp_id','comment', 'rating'));
}
and also update query
public function getUserbasictask(){
$taskwithcomments = appraisaltask::select(array('id','taskname','description','status'))
->with(['ratings' => function($query)
{
// the condition that will be apply on the with relation
$query->where('emp_id','=',Auth::user()->empid);
}])->where('type','=','basic')->get();
return json_encode($taskwithcomments);
}
hope it will work.

Categories