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

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();
});

Related

How Can I Query Polymorphic Relationship in Laravel 8

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>
...

Display primary video for specific ad/property in Laravel

I am working on a project for ads/properties in Laravel. I have gallery of multiple videos for each individual ad. I want to be able to select one of those videos with radio button and make it primary video for that ad (show that particular video next to ad). I have has many relationship between property and video. I am trying to update my is_main_video column to be 1 if it is main or 0 if it isn't and then display that video if it is 1 in my view. I am having trouble to write that method in my controller I get success message but my is_main_video column remains null. Any help is appreciated. Here are my tables and code.
properties (id, title, location, price)
videos (id, filename_video, model_id, is_main_video)
In videos table model_id column is foreign key that connects to properties table.
PropertyController.php
public function update(StorePropertyInfo $request, Property $property, Video $video)
{
$videoExtensions = ['mp4', '3gp', 'wmv', 'flv', 'avi'];
$image_arr = array_filter(explode(',', $request->image), 'strlen');
foreach ($image_arr as $key => $value) {
$file = explode('.', $value);
ext = end($file);
if (in_array($ext, $videoExtensions)) {
$query = Property::query();
if ($request->has('radio')) {
$request->get('radio');
}
if ($request->radio) {
$query->whereHas('videos', function ($query) use ($request) {
$query->where('is_main_video', 'like', '%' . $request->radio . '%');
});
}
$data = $query;
$video->where('filename_video', $value)
->update([
'model_id' => $property->id,
'is_main_video' => $data
]);
};
$request->validated();
return redirect()
->back()
->with('message', 'Property information updated');
}
}
edit.blade.php
<input type="hidden" id="hideninput" data-src="property/{{$property->id}}/gallery"value="{{old('video',$video)}}" name="video">
#if (old('video', $video))
#foreach (array_filter(explode(',',old('video', $video)), 'strlen') as $key =>$value)
<div id="{{'div_video_'.$key}}" class="col-md-3" style="padding: 15px;">
<input type="radio" name="radio" value="radio">Make main
<button data="{{$key}}" type="button" class="closebuttonvideo">
<span aria-hidden="true">×</span>
</button>
<video name="video" id="{{'video_'.$key}}" data={{$value}} src="/storage/property/{{$property->id}}/gallery/{{$value}}" class="video-js vjs-default-skin" controls preload="auto" data-setup='{"inactivityTimeout": 0}' width="180" height="180"></video>
</div>
#endforeach
#endif
videos table migration
public function up()
{
Schema::table('videos', function (Blueprint $table) {
$table->boolean('is_main_video')->nullable()->default(null);
$table->unique(['model_id', 'is_main_video']);
});
}
Property.php
protected $appends = ['is_main_video'];
public function videos()
{
return $this->hasMany(Video::class, 'model_id');
}
Video.php
public function properties()
{
return $this->belongsTo(Property::class);
}
I would do a partial rewrite, something like this:
PropertyController.php in edit(); Retrieving a property with attached videos.
return view('edit', [
'property' => Property::with('videos')->find(1),
]);
edit.blade.php
#foreach($property->videos as $video)
<input type="radio" name="main_video" value="{{ $video->id }}">Video {{ $video->id }}<br>
#endforeach
PropertyController.php in update(); Toggle the is_main_video attribute of each video of the property.
foreach ($property->videos as $video) {
$video->is_main_video = ($video->id == $request->input('main_video'));
$video->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>

SQLSTATE[23000] Integrity constraint violation: 1452 in a many-to-many relationship in laravel 5.3

I've got a BlogPost Controller which has a user form that takes inputs from the user through the create() method. Then that form redirects to the store method on the same controller. The problem I'm facing is with the many-to-many relationship. BlogPost model has a many-to-many relationship with the BlogTag model. I'm taking input from a user through checkboxes. The user can choose multiple radio buttons associated with individual tags (form code has been posted below). Everything seems to work fine, but when I'm trying to attach all the tag ids to the post instance in my store() method. I get the error that is shown below. I've looked through all the available solutions on the internet but nothing seems to work for my case. The store method has also been posted below.
QueryException in Connection.php line 761: SQLSTATE[23000]: Integrity
constraint violation: 1452 Cannot add or update a child row: a foreign
key constraint fails (erp_system_solution.posts_tags, CONSTRAINT
posts_tags_ref_tag_id_foreign FOREIGN KEY (ref_tag_id) REFERENCES
blog_tags (tag_id) ON DELETE CASCADE ON UPDATE CASCADE) (SQL:
insert into posts_tags (ref_post_id, ref_tag_id) values (2, 34),
(7, 34), (8, 34), (15, 34))
Form for posting a BlogPost
{{Form::open(array(
'action' => 'Blog\BlogPostController#store',
'class' => 'form-horizontal',
'method' => 'POST',
))}}
{{ Form::hidden('user_id', Auth::user()->user_id) }}
<div class="form-group">
{{ Form::label("post_title", "Post Title", array("class" => "col-sm-2 control-label")) }}
{{ Form::text ("post_title", "", array("class" => "col-sm-6")) }}
</div>
<div class="form-group">
{{ Form::label("post_body", "Post Body", array("class" => "col-sm-2 control-label")) }}
{{ Form::textarea("post_body", "", array("class" => "col-sm-6 col-sm-offset-2 top-info-panels", "rows" => "16", "columns" => "2")) }}
</div>
<div class="form-group">
{{ Form::label("published", "Publish Blog Post", array("class" => "col-sm-2 control-label")) }}
{{ Form::radio("published", "Yes", true) }} Yes
{{ Form::radio("published", "No") }} No
</div>
<div class="form-group">
{{ Form::label("category_id", "Choose a Category", array("class" => "col-sm-2 control-label")) }}
{{ Form::select("category_id", $categories, '-----Choose Any One-----') }}
</div>
<div class="form-group">
{{ Form::label("tag_id", "Choose Appropriate Tags", array("class" => "col-sm-2 control-label")) }}
<div class="col-sm-offset-2">
#for($i=1; $i<count($tags)+1; $i++)
{{ Form::checkbox("tag_id[]", $i), array("class" => "col-sm-offset-2 col-sm-10") }} {{ $tags[$i] }}
#endfor
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
{{Form::submit('Create Post', array("class" => "btn btn-warning"))}}
</div>
</div>
{{Form::close()}}
BlogPostModel
<?php
namespace App;
use App\PostsTagsPivot as Pivot;
use App\BlogCategory;
use App\BlogTag;
use App\Comment;
use App\RegisteredUser;
use Illuminate\Database\Eloquent\Model;
class BlogPost extends Model
{
public $timestamps = true;
protected $table = 'blog_posts';
protected $primaryKey = 'post_id';
protected $fillable = ['post_title', 'post_body', 'published', 'registered'];
public function post_category() {
return $this->belongsTo(BlogCategory::class, 'category_id');
}
public function posts_with_tags() {
return $this->belongsToMany(BlogTag::class, 'posts_tags', 'ref_tag_id', 'ref_post_id');
}
public function comments() {
return $this->hasMany(Comment::class, 'comment_id');
}
public function posts_author() {
return $this->belongsTo(RegisteredUser::class, 'user_id');
}
}
BlogPostController
public function store(Request $r) {
$u_id = $this->user::find((int)$r->input('user_id'));
$cat_id = $this->category::find((int)$r->input('category_id'));
$tag_id = $r->input('tag_id');
$role = $this->user::find((int)$r->input('user_id'))->has_role($u_id);
$registered = ($role == 'super_admin') ? true : false;
$published = ($r->input('published') == 'Yes') ? true : false;
$create_post = $this->blog_posts::create(['post_title' => $r->input('post_title'), 'post_body' => $r->input('post_body'), 'published' => $published, 'registered' => $registered]);
$create_post->save();
$create_post->posts_with_tags()->attach($tag_id);
$create_post->save();
$create_post->posts_author()->associate($u_id);
$create_post->save();
$create_post->post_category()->associate($cat_id);
if($create_post->save()) return redirect()->route('blog_post.create')->with('post_saved', 'Your post has been saved');
else return redirect()->route('blog_post.create')->with('post_not_saved', 'Something went wrong');
}
BlogTagModel
<?php
namespace App;
use App\BlogPost;
use Illuminate\Database\Eloquent\Model;
class BlogTag extends Model
{
public $timestamps = true;
protected $table = 'blog_tags';
protected $primaryKey = 'tag_id';
protected $fillable = ['tag_name', 'post_id', 'tag_id'];
public function tags_on_posts() {
return $this->belongsToMany(BlogPost::class, 'posts_tags', 'ref_tag_id', 'ref_post_id');
}
}
Migration for a pivot table joining BlogPost with BlogTag
public function up()
{
Schema::create('posts_tags', function ($table) {
$table->integer('ref_tag_id')->unsigned()->index();
$table->foreign('ref_tag_id')->references('tag_id')->on('blog_tags')->onDelete('cascade')->onUpdate('cascade');
$table->integer('ref_post_id')->unsigned()->index();
$table->foreign('ref_post_id')->references('post_id')->on('blog_posts')->onDelete('cascade')->onUpdate('cascade');
});
}
Well, I figured it out. The solution is to change the ordering in posts_with_tags() action/method
It was:
public function posts_with_tags() {
return $this->belongsToMany(BlogTag::class, 'posts_tags', 'ref_tag_id', 'ref_post_id');
}
It should be:
public function posts_with_tags() {
return $this->belongsToMany(BlogTag::class, 'posts_tags', 'ref_post_id', 'ref_tag_id');
}

Laravel update makes new table rule instead of updating

I have a company table and an attributes table with all sorts of value in it.
One company hasMany attributes and an attribute belongsTo a company.
Now I have a value inside the attributes table with a 'account_nr_start' (for example, when a new user is added to a company its account_id starts counting up from 1000).
Controller:
public function __construct(Company $company, User $user)
{
if(Auth::user()->usertype_id == 7)
{
$this->company = $company;
}
else
{
$this->company_id = Auth::user()->company_id;
$this->company = $company->Where(function($query)
{
$query->where('id', '=', $this->company_id )
->orWhere('parent_id','=', $this->company_id);
}) ;
}
$this->user = $user;
$this->middleware('auth');
}
public function edit(Company $company, CompaniesController $companies)
{
$companies = $companies->getCompaniesName(Auth::user()->company_id);
$attributes = $company->attributes('company')
->where('attribute', '=', 'account_nr_start')
->get();
foreach ($attributes as $k => $v) {
$nr_start[] = $v->value;
}
return view('company.edit', ['company' => $company, 'id' => 'edit', 'companies' => $companies, 'nr_start' => $nr_start]);
}
public function update(UpdateCompanyRequest $request, $company, Attribute $attributes)
{
$company->fill($request->input())->save();
$attributes->fill($request->only('company_id', 'attribute_nr', 'value'))->save();
return redirect('company');
}
HTML/Blade:
<div class="form-group {{ $errors->has('_nr_') ? 'has-error' : '' }}">
{!! HTML::decode (Form::label('account_nr_start', trans('common.account_nr_start').'<span class="asterisk"> *</span>', ['class' => 'form-label col-sm-3 control-label text-capitalize'])) !!}
<div class="col-sm-6">
{!! Form::text('value', $nr_start[0], ["class"=>"form-control text-uppercase"]) !!}
{!! $errors->first('account_nr_start', '<span class="help-block">:message</span>') !!}
</div>
</div>
When I update a company now, it will upload like the last input here: :
So it makes a new rule, while it needs to edit the current attribute rule instead of making a new rule with an empty company_id/attribute.
If I understand what you are trying to do, I think this will fix your problem. The issue you have is the Attribute model is a new instance of the model rather than retrieving the model you need.
before running fill() from the attributes method try this
$new_attribute = $attributes->where('company_id', '=', $company->id)->where('attribute', '=', 'account_nr_start')->first();
Then run the fill()
$new_attribute->fill($request->only('company_id', 'attribute_nr', 'value'))->save();

Categories