How Can I Query Polymorphic Relationship in Laravel 8 - php

I am able to create and even delete a polymorphic row from my app, but I can not for the life of me able to figure out how to query the relationship so I can update the row. My models and controller methods are below--all work except for public function updateManifest($id). I didn't include all the update code I've been trying over the past day and a half because it would be too much and not really relevant, but I can tell you that I can only get as deep as the Workorder model, I can't seem to query anything related through the poly relationship so I can query all the manifest objects. Thank you.
Workorder.php
class Workorder extends Model
{
...
public function manifest(){
return $this->morphMany(Manifest::class, 'manifestable');
}
}
Manifest.php
class Manifest extends Model
{
use SoftDeletes;
protected $fillable = [
'stream_id', 'manifest_number', 'manifest_quantity', 'manifest_rate',
'manifest_total', 'manifestable_id', 'manifestable_type', 'stream_description_plus'
];
public function manifestable(){
return $this->morphTo();
}
}
edit.php (Workorder controller)
class Edit extends Component {
public function mount(Workorder $workorder, Manifest $manifest)
{
$this->workorder = $workorder;
$this->manifest = $manifest->manifestable;
$this->workorder_number = $workorder->workorder_number;
$this->workorder_po_number = $workorder->workorder_po_number;
$this->workorder_status = $workorder->workorder_status;
$this->workorder_job_notes = $workorder->workorder_job_notes;
$this->project_id = $workorder->project_id;
$this->customer_id = $workorder->customer_id;
$this->generator_id = $workorder->generator_id;
$this->prevailing_wage = $workorder->prevailing_wage;
$this->touched = false;
}
public function addManifest($id)
{
Manifest::create([
'workorder_id' => $this->workorder->id,
'stream_description_plus' => $this->stream_description_plus,
'manifest_number' => $this->manifest_number,
'manifest_quantity' => $this->manifest_quantity,
'manifest_rate' => $this->manifest_rate,
'manifestable_id' => $this->workorder->id,
'manifestable_type' => get_class($this->workorder)
]);
return redirect()->route('admin.workorder.edit', $this->workorder->id);
}
public function updateManifest($id)
{
$record = Workorder::find($id);
/* dd($record);*/
$record->update([
'stream_description_plus' => $this->stream_description_plus,
'manifest_number' => $this->manifest_number,
'manifest_quantity' => $this->manifest_quantity,
'manifest_rate' => $this->manifest_rate,
]);
return redirect()->route('admin.workorder.edit', $this->workorder->id);
}
public function deleteManifest($id)
{
$record = Manifest::findOrFail($id);
$record->delete();
return redirect()->route('admin.workorder.edit', $this->workorder->id);
}
public function render()
{
$items = Item::all();
$users = User::all();
$projects = Project::all();
$generators = Generator::all();
$customers = Customer::all();
$personnel = Personnel::all();
$streams = Stream::all();
return view('livewire.admin.workorders.edit',
compact('items', 'projects', 'generators',
'customers', 'personnel', 'users', 'streams'));
}
}
update form
...
<form wire:submit.prevent="updateManifest({{$man->id}})" method="PUT">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<select wire:model="stream_id"
class="mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 border-gray-300 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5">
<option value="">
Select Waste Stream
</option>
#foreach($streams as $stream)
<option value="{{$stream->id}}">{{$stream->stream_description}}</option>
#endforeach
</select>
#error('stream_description')
<span class="error">{{ $message }}</span>
#enderror
</div>
</form>
...

Related

How to prevent printing duplicate record in blade foreach while using model relation in laravel

I'm using laravel 9.11
I have a stock table containing items and each item is related to a specific place,
table snapshot
I have another form to make changes of values and I want to loop throw all places that exist in stock table but withouh making duplicate record.
snapshot of the error
showing the error
I do have all record of stock places and made a loop throw it but I want a way to avoid duplicating the records.
Blade code
<div class="mb-3">
<label for="place_name" class="block mb-2 mt-2 text-sm font-medium text-gray-900 dark:text-gray-400">
Select a Place
</label>
<select id="place_name" name="selectPlace"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 cursor-pointer">
<option selected value="">Choose a Place</option>
#foreach($stocks as $stock)
<option value="{{ $stock->places->id }}">{{ $stock->places->name }}</option>
#endforeach
</select>
#error('selectPlace') <p class="input_validate">{{ $message }}</p> #enderror
</div>
Controller code
public function transfer() {
$assets = Asset::all();
$places = Place::all();
$quantities = AssetQuantity::all();
$services = Service::all();
$stocks = Stock::all();
return view('stock.transfer', [
'assets' => $assets,
'places' => $places,
'quantities' => $quantities,
'services' => $services,
'stocks' => $stocks
]);
}
Stock Model
class Stock extends Model
{
use HasFactory;
protected $fillable = ['current_stock', 'asset_id', 'place_id', 'quantity_id'];
public function assets() {
return $this->belongsTo(Asset::class, 'asset_id');
}
public function places() {
return $this->belongsTo(Place::class, 'place_id');
}
// Relation to know quantity of assets
public function quantity() {
return $this->belongsTo(AssetQuantity::class, 'quantity_id');
}
}
Place Model
class Place extends Model
{
use HasFactory;
protected $fillable = [
'name'
];
public function stocks() {
return $this->hasMany(Stock::class, 'place_id');
}
}
I think you can eager load Stock::with('places')->get() and later map your collection
with something like.
$stocksCollection = Stock::with('places')->get();
$collection = $stocksCollection->map(function ($array) {
return collect($array)->unique('place_id')->all();
});

How do I show a dynamic navigation bar on a dynamic web page in Laravel?

I have a dynamic navigation bar, created however it won't show on the dynamic web page.
The current output is:
ErrorException
Undefined variable: navContent (View: C:\Users\Computer
Angel\Documents\blog\resources\views\page\dynamic.blade.php)
The desired output is my dynamic.blade.php where the pageContent is the dynamic page content the user inputted through a form and the dynamic navigation bar in the tags.
This is my dynamic.blade.php:
<nav>
#foreach($navContent as $nav)
{!!nav-navName!!}
#endforeach
</nav>
<body>
{!!$pageContent->pageContent!!}
</body>
This is my NavController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Nav;
use DB;
use Illuminate\Database\MySqlConnection;
class NavController extends Controller
{
public function index()
{
$navs = Nav::all();
return view('navManagement', compact('navs'));
}
public function create()
{
return view('createNav');
}
public function store(Request $request)
{
$data = request()->validate([
'navName' => 'required',
'navLink' => 'required',
]);
$nav = new Nav([
'navName' => $request->get('navName'),
'navLink' => $request->get('navLink'),
]);
$nav->save();
return redirect('/n');
}
public function show($navName)
{
$navContent = DB::table('navs')->where('navName',$navName)->first();
return view('page.dynamic', ['navContent' => $navContent]);
}
public function edit($navName)
{
$navContent = DB::table('navs')->where('navName',$navName)->first();
return view('editNav', ['navContent' => $navContent]);
}
public function update(Request $request)
{
$data = $request->validate([
'navName' => 'required|exists:navs,navName',
'navLink' => 'required'
]);
$obj = \App\Nav::where('navName', $request->navName)
->update([
'navLink' => $request->navLink
]);
return redirect('/n');
}
public function destroy(Request $request)
{
$obj = \App\Nav::where('navName', $request->navName)
->delete();
return redirect('/n');
}
}
This is my PageController.php:
<?php
namespace App\Http\Controllers;
use App\Page;
use Illuminate\Http\Request;
use DB;
use Illuminate\Database\MySqlConnection;
class PageController extends Controller
{
public function index()
{
$pages = Page::all();
return view('pageManagement', compact('pages'));
}
public function create()
{
//This will load create.blade.php
return view('createPage');
}
public function store(Request $request)
{
$data = request()->validate([
'title' => 'required',
'URI' => 'required|min:5|max:10|',
'pageContent' => 'required',
]);
$page = new Page([
'title' => $request->get('title'),
'URI' => $request->get('URI'),
'pageContent' => $request->get('pageContent'),
]);
$page->save();
return redirect('/p');
}
public function show($URI)
{
$pageContent = DB::table('pages')->where('URI',$URI)->first();
return view('page.dynamic', ['pageContent' => $pageContent]);
}
public function edit($URI)
{
$pageContent = DB::table('pages')->where('URI',$URI)->first();
return view('editPage', ['pageContent' => $pageContent]);
}
public function update(Request $request)
{
$data = $request->validate([
'title' => 'required',
'URI' => 'required|min:5|max:10|exists:pages,URI',
'pageContent' => 'required'
]);
$obj = \App\Page::where('URI', $request->URI)
->update([
'title' => $request->title,
'pageContent' => $request->pageContent
]);
return redirect('/p');
}
public function destroy(Request $request)
{
$obj = \App\Page::where('URI', $request->URI)
->delete();
return redirect('/p');
}
}
This is my Nav.php:
class Nav extends Model
{
protected $fillable = ['navName', 'navLink'];
}
This is my Page.php:
class Page extends Model
{
protected $fillable = ['title', 'URI', 'pageContent'];
}
This is my migration for pages:
public function up()
{
Schema::create('pages', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('URI');
$table->text('pageContent');
$table->timestamps();
});
}
This is my migration for nav:
public function up()
{
Schema::create('navs', function (Blueprint $table) {
$table->id();
$table->string('navName');
$table->string('navLink');
$table->timestamps();
});
}
This is my createNav.blade.php:
<form action="/storeNav" method="post">
#csrf
<label for="navName">Navigation Bar Option Name:</label><br>
<input type="text" id="navName" name="navName" autocomplete="off" value="{{ old('navName') }}">
<br>
#error('navName') <p style="color: red">{{ $message }}</p> #enderror
<label for="navLink">Navigation Bar Option Link:</label><br>
<input type="text" id="navLink" name="navLink" autocomplete="off" value="{{ old('navLink') }}">
<br>
#error('navLink') <p style="color: red">{{ $message }}</p> #enderror
<input type="submit" value="Submit">
</form>
This is my createPage.blade.php:
<form action="/storePage" method="post">
#csrf
<label for="title">Title:</label><br>
<input type="text" id="title" name="title" autocomplete="off" value="{{ old('title') }}"><br>
#error('title') <p style="color: red">{{ $message }}</p> #enderror
<label for="URI">URI:</label><br>
<input type="text" id="URI" name="URI" autocomplete="off" value="{{ old('URI') }}"><br>
#error('URI') <p style="color: red">{{ $message }}</p> #enderror
<label for="pageContent">Page Content:</label><br>
<textarea id="pageContent" name="pageContent" value="{{ old('pageContent') }}"></textarea>
#error('pageContent') <p style="color: red">{{ $message }}</p> #enderror
<input type="submit" value="Submit">
</form>
This is my web.php:
Route::get('/page/{URI}', 'PageController#show');
Route::get('/page/{URI}/edit', 'PageController#edit');
Route::get('/p', 'PageController#index');
Route::get('/createPage', 'PageController#create');
Route::post('/storePage', 'PageController#store');
Route::patch('/page/{URI}', 'PageController#update');
Route::delete('/page/{URI}', 'PageController#destroy');
Route::get('/nav/{navName}/edit', 'NavController#edit');
Route::get('/n', 'NavController#index');
Route::get('/createNav', 'NavController#create');
Route::post('/storeNav', 'NavController#store');
Route::patch('/nav/{navName}', 'NavController#update');
Route::delete('/nav/{navName}', 'NavController#destroy');
Below is my github repository link, if you want to take a look at my full code, or you want to try run the code in your Integrated Development Environment.
https://github.com/xiaoheixi/blog
Thanks for reading! :D
If is complaining that it can't find a variable called $navContent.
I can't see you passing it to either of the views you are calling from your index() functions.
return view('navManagement', compact('navs'));
return view('pageManagement', compact('pages'));
You would need to set that varaible and pass it to the view
// Get the nav content however you want, this is just a crude example
$navContent = $this->getMyNavContent();
return view('navManagement', [
'navs' => $navs,
'navContent' => $navContent
]);
I'm guessing you want to find a way to embed the dynamic nav without having to add the navContent every time you render a view, as that's what the other answer is suggesting. You could achieve this using a middleware, say dynamicNav and registering your routes under that middleware group.
In that middleware you can do all the logic of fetching the nav content and then use something like merge, as shown here:
$request->merge(['dynamicNav' => $navContent]);
This way your middleware will add the data to every request which goes through it, although I wouldn't recommend this solution.
What I would do is cache the nav content and retrieve in the view using the cache() helper, then override the save() method of the model to also update the cache when the DB is updated (to avoid duplicate code, you could create a trait for the fetching of the nav). Example:
// in your model
public function save(array $options = [])
{
Cache::put('nav-content', getNavContent());
parent::save();
}

Laravel Model binding many to many realtionship does not populate data

I have two tables with a many to many relation (Project and Center, the pivot table is ProjectCenter).
These are my models:
Project:
class Project extends Model {
public function centers()
{
return $this->belongsToMany('App\Models\Center', 'ProjectCenter', 'IDProject', 'IDCenter');
}
public function getCenterListAttribute()
{
return $this->centers->lists('IDCenter')->all();
}
}
Center:
class Center extends Model {
public function projects()
{
return $this->belongsToMany('App\Models\Project', 'ProjectCenter', 'IDCenter', 'IDProject');
}
}
Controller -> edit:
public function edit($id)
{
$project = Project::find($id);
$centerList = Center::lists('Name', 'IDCenter')->toArray();
return view('project/add', array('centerList' => $centerList))->with('project', $project);
}
And the view:
{!! Form::label('centers_list', 'Center*') !!}
{!! Form::select('centers_list[]',
$centerList,
null,
array(
'class' => 'form-control ',
'required' => 'required',
'multiple' => true,
'data-placeholder' =>
'Select a center'
)
) !!}
But I can not select the data already stored previously.
For example: the project 8 (IDProject) has two centers (1 and 2) but the data is not populated in the multiple select:
What am I doing wrong?
You all time get same result $centerList = Center::lists('Name', 'IDCenter')->toArray(); but you must be get product centers using query with model.
$project = Project::with("centers:Name,IDCenter")->find($id);
$centerList = $project->centers->pluck('Name', 'IDCenter')->toArray();
I already solve the problem using a foreach to select the related centers:
<select multiple="multiple" name="centers[]" id="centers" class="form-control select2" required="required" data-placeholder="Select a center">
#if($centerList)
#foreach($centerList as $key => $center)
<option value="{{$key}}" {{ (collect($selectedCenters)->contains($key)) ? "selected='selected'" : '' }} >{{$center}}</option>
#endforeach
#endif
</select>

Display name of select form rather than it's Id (error:Trying to get property of non-object) laravel 5

I have 2 tables tn_client and tn_project, which project have 1 client while client can have many projects, rather than displaying client id on my table, i want display its client name but when i did that its said trying to get property of non-object.
Trying to get property of non-object (View:
C:\xampp\htdocs\PKL\netxcel-activityreport-11b90b878d39\resources\views\project.blade.php)
Above is the full error that i get, and below is the tables
tn_project
tn_client
CONTROLLER
public function index(){
Log::info('Entering index');
return view('project')
->with('title','Project')
->with('projects',Project::with('client','invoice')->get())
->with('clients',Client::all())
->with('invoices', Invoice::all());
}
//get all data
public function getAll(){
return Response::json(
array(
'content' => Project::with('client','invoice')->get(),
'status' => 'success',
)
);
}
public function createOrEdit(){
$currentUsername = Auth::user()->name;
$isUpdate = false;
$projectId = Input::get('prevId');
//populate data
$project = new Project;
if($projectId != ""){
$project = Project::where('cv_id','=',$projectId)->firstOrFail();
$project->cv_updated_by = $currentUsername;
$project->cn_updated_at = Carbon::now();
$isUpdate = true;
} else{
$project->cv_created_by = $currentUsername;
$project->cn_created_at = Carbon::now();
}
$project->cv_id = Input::get('projectId');
$project->cv_name = Input::get('projectName');
$project->cv_client_id = Input::get('clientId');
$project->cn_invoice_method = Input::get('invoiceId');
$project->cn_project_rate = Input::get('projectRate');
$project->cn_note = Input::get('note');
//execute
if($isUpdate){
Log::info("entering update mode");
Project::where('cv_id','=',$projectId)->update(['cv_id'=>$project->cv_id,
'cv_name'=>$project->cv_name,
'cv_client_id'=>$project->cv_client_id,
'cn_invoice_method'=>$project->cn_invoice_method,
'cn_project_rate'=>$project->cn_project_rate,
'cn_note'=>$project->cn_note,
'cn_updated_at'=>$project->cn_updated_at,
'cv_updated_by'=>$project->cv_updated_by]);
}else{
$project->save();
}
return Response::json(
array(
'content' => Project::with('client','invoice')->get(),
'status' => 'success',
)
);
}
Model
PROJECT
<?php
namespace Activity;
use Illuminate\Database\Eloquent\Model;
class Project extends Model {
protected $table = 'tn_project';
public $timestamps = false;
protected $fillable = [
'cv_id',
'cv_name',
'cv_client_id',
'cn_invoice_method',
'cn_project_rate',
'cn_note',
'cn_created_at',
'cv_created_by',
'cn_updated_at',
'cv_updated_by'
];
public function client(){
return $this->belongsTo('Activity\Client','cv_client_id','cn_id');
}
public function invoice(){
return $this->hasOne('Activity\Invoice','cn_id','cn_invoice_method');
}
}
CLIENT
<?php
namespace Activity;
use Illuminate\Database\Eloquent\Model;
class Client extends Model {
protected $table = 'tn_client';
public $timestamps = false;
protected $fillable = [
'cv_name',
'cv_contact',
'cv_email',
'cv_phone',
'cv_address',
'cn_created_at',
'cn_created_by',
'cn_updated_at',
'cn_updated_by'
];
public function project(){
return $this->hasOne('Activity\Project', 'cv_id', 'cn_id');
}
}
VIEW
this is my select form
<div class="col-md-9">
<select name="clientId" id="clientId" class="form-control" placeholder="Select Client">
#foreach ($clients as $client)
<option value='{{$client->cn_id}}'>{{$client->cv_name}}</option>;
#endforeach
</select>
</div>
This is how i called the function to display it in my view
#foreach($projects as $project)
<tr class="odd gradeX">
<td>{{$project->cv_id}}</td>
<td>{{$project->cv_name}}</td>
<td>{{$project->client->cv_name}}</td><!--This is what cause an -->
<td>{{$project->cn_invoice_method}}</td>
<td>{{$project->cn_project_rate}}</td>
<td>{{$project->cn_note}}</td>
<td>
<a class="btn btn-success" title="edit" data-id={{$project->cv_id}} data-action="project-edit"><i class="fa fa-pencil"></i></a>
<a class="btn btn-danger" title="delete" data-id={{$project->cv_id}} data-action="project-delete"><i class="fa fa-times"></i></a>
</td>
</tr>
#endforeach
im still new to laravel, and what did i do wrong that make such an error like that?
I found the answer, i got the reference from here so based on that reference and the basic of x->y->z, we got to check first that x->y have some value in it if yes we got to check whether it's an object or just an array, in my case it was an array so rather doing something like this
{{$project->client->cv_name}}
which is that how to display an object, we should do something like this
{{$project->client['cv_name']}}
and that is how you solve your problem, cheers :D

Laravel 4 Creating Form for adding record with relationship

I have created very basic Model. I have persons table and emails table.
Also I have create a link in the persons/show.blade.php ("Add mail").
My models are
class Person extends Eloquent {
protected $table = 'persons';
public function email()
{
return $this->HasMany('Email');
}
}
and
class Email extends Eloquent {
protected $table = 'emails';
public static $rules = array(
'email'=>'required|unique:emails'
);
public function person()
{
return $this->belongsTo('Person');
}
}
How can I pass the $person->id to the new Controller?
In my show.blade.php for Person I added
{{ HTML::linkRoute('email.adduseremail','Προσθήκη Email',array($person->id))}}
and I added to my EmailController
public function adduseremail($id)
{
return View::make('email.createforuser',['id'=>$id]);
}
public function storeforuser($pid)
{
$validator = Validator::make(Input::all(),Email::$rules);
if ($validator->fails()) {
$messages = $validator->messages();
foreach ($messages->all('<li>:message</li>') as $message)
return Redirect::back()->withInput()->WithErrors($messages);
}
$person = Person::FindorFail($pid);
$email = new Email;
$email->email = Input::get('email');
$email->person()->associate($person);
$email->save();
return Redirect::route('person.index');
}
and my createforuser view is
<p>
{{Form::open(['route'=>'email.storeforuser'])}}
<div>
{{Form::label('email', 'Email:')}}
{{Form::input('text', 'email')}}
{{$errors->first('email')}}
</div>
</br>
<div>
{{Form::submit('Submit')}}
</div>
{{Form::close()}}
<p>
I keep getting Trying to get property of non-object (View: /var/www/laravel/app/views/email/show.blade.php)
Is there any example using Form and Models for inserting new objects to the database for 'belongsTo' Relationship? I couldn't find anything complete , just partial examples.
I generally use laravel sessions or laravel cache to tempererally save an id that i need to use later like:
Session::set('personId',$person->id);
Session::get('personId');
The same is for cache except cache will only last for the current request session is persistent for the session
Hope that helps
I am no sure if I 'm supposed to answer my own question but finally I found a solution.
I set two new routes
Route::post('email/adduseremail/{pid}', array('uses'=>'EmailController#adduseremail','as' => 'email.adduseremail'));
Route::post('email/storeforuser/{pid}', array('uses' =>'EmailController#storeforuser','as' => 'email.storeforuser'));
and created the corresponding methods in my Controller
public function adduseremail($id)
{
$pname = Person::Find($id)->name;
$psurname = Person::Find($id)->surname;
return View::make('email.createforuser',array('id'=>$id,'name'=>$pname, 'surname'=>$psurname));
}
and
public function storeforuser($pid)
{
$validator = Validator::make(Input::all(),Email::$rules);
if ($validator->fails())
{
$messages = $validator->messages();
foreach ($messages->all('<li>:message</li>') as $message)
return Redirect::back()->withInput()->WithErrors($messages);
}
$person = Person::FindorFail($pid);
$email = new Email;
$email->email = Input::get('email');
$email->person()->associate($person);
$email->save();
return Redirect::route('person.show',array($person->id));
}
then on my view blade pages I can pass the parameters from View to Form and so on
person.show.blade.php
{{Form::Open(array('route' => array('email.adduseremail', $person->id),'method' => 'POST','style'=>'display:inline;'))}}
{{Form::submit('Add Email')}}
{{Form::close()}}
and
email.createforuser.blade.php
{{Form::open(array('route'=>array('email.storeforuser',$id),'method' => 'POST','style'=>'display:inline;'))}}
{{Form::label('email', 'Email:')}}
{{Form::input('text', 'email')}}
{{Form::submit('Submit')}}
Hope it helps others also

Categories