View and Controller for a Downloadpage - laravel

I need to create a downloadpage. Ich have a model Product and a model File. The create/store and the edit/update is already working. With a submit button I'm saving fields like produktname, description, etc. into products-table. Fields like filename, filePath and product_id saving into files-table. Files also uploaded to Storage. Model Product has a hasMany-relation to File and the model File has a BelongsTo-relation to Product. In the File model "product_id" is related to the Product model.
So far so good. What's also working is: Index view of FileController. I can see all uploaded files and can also download them. Through the product_id I can access the actual product show method. That's how it should be. It's possible here in the index.blade.php:
#foreach ($files as $file)
<tr>
<th>{‌{ $file->filename }}</th>
<td>download</td>
<td>{‌{ $file->product_id }}</td>
<td>{‌{ $file->id }}</td>
</tr>
#endforeach
In the show.blade.php I can see already all data from the products table. I have two buttons for downloading changelog (just a link) and working and for downloading the stored file (which is in the files table. I can't get it working for the download stored file. dd($files); is NULL. Here's the ProductController show part. I applied use App\File; on top of the controller, because I want to give the ability to access the File model.
public function show(Product $product)
{
return view('products.show', compact('product','file'));
}
In show.blade.php I get an error: compact(): Undefined variable: file
<div>
<button id="changelog" name="changelog" class="btn btn-lg btn-primary btn-block" type="submit" onclick="window.open('{‌{ $product->changelog }}')">Download Changelog</button>
<button id="filename" name="filename" class="btn btn-lg btn-success btn-block" type="submit" onclick="window.open('{‌{ $file->filename }}')">Download Installer</button>
</div>
How can I access an element of the other model or the other table? How can I expand {‌{ $file->filename }} or probably {‌{ $product->$file->filename }} to get the file to download?
I'm trying since days and can't find the solution.

Thx, for responding. I still have problems doing Eloquent and Query building, but the use of dd od var_dump helps alot and showed me that I have valuable data. The problem was to define the query.
Here's the working stuff:
Product model:
public function file()
{
return $this->hasMany('App\File', 'product_id');
}
File model:
public function product()
{
return $this->hasOne('App\Product', 'id');
}
Product controller:
public function show(Product $product)
{
$files = Product::with('file')->find($product->id)->file;
return view('products.show', compact('product', 'files'));
}
show view:
#foreach ($files as $file)
<button id="filepath" name="filepath" class="btn btn-lg btn-success btn-block" type="submit" onclick="window.open('{{ $file->filepath }}')">Download File: {{ $file->filename }}</button>
#endforeach

Related

Laravel Mega Menu Loop

I am learning laravel and was trying to create a Megamenu. But I can call parent menu, I stacked at 1st child and 2nd child.
Same children coming under every parent.
<div class="navbar-mega">
<div class="dropdown-mega">
#php
$categories = App\Models\Category::where('parent_id', 0)->orderBy('order_level','ASC')->get();
#endphp
#foreach ($categories as $item)
<button class="dropbtn-mega"> {{$item->id}}</button>
#endforeach
<div class="dropdown-content-mega">
<div class="row-mega">
#php
$subcategories = App\Models\Category::where('parent_id',
$item->id)->orderBy('name','ASC')->get();
#endphp
#foreach ($subcategories as $subcategory)
<div class="column-mega">
<h3>{{$subcategories}}</h3>
</div>
#endforeach
</div>
</div>
</div>
</div>
Database Fields
Subcategory Query Output
This code :
$subcategories = App\Models\Category::where('parent_id',$item->id)->orderBy('name','ASC')->get();
is not within the loop through the $categories as $item. So when it is executed it will also return the same set of categories (as $item will always be the same value at that point in your code.
Put it within the loop :
#foreach ($categories as $item)
<button class="dropbtn-mega"> {{$item->id}}</button>
<div class="dropdown-content-mega">
<div class="row-mega">
#php
$subcategories = App\Models\Category::where('parent_id',
$item->id)->orderBy('name','ASC')->get();
#endphp
#foreach ($subcategories as $subcategory)
<div class="column-mega">
<h3>{{$subcategories}}</h3>
</div>
#endforeach
</div>
</div>
#endforeach
and it should work fine.
You can use append for fetch sub categories, in your category model use this,
protected $appends = [
'sub_categories'
];
public function getSubCategoriesAttribute()
{
return Category::where('parent_id', $this->id)->orderBy('name','ASC')->get();
}
<div class="navbar-mega">
<div class="dropdown-mega">
#php
$categories = App\Models\Category::where('parent_id', 0)->orderBy('order_level','ASC')->get();
#endphp
#foreach ($categories as $category)
<button class="dropbtn-mega"> {{ $category->id }}</button>
#endforeach
<div class="dropdown-content-mega">
<div class="row-mega">
#foreach ($category->sub_categories as $subCategory)
<div class="column-mega">
<h3>{{ $subCategory->name }}</h3>
</div>
#endforeach
</div>
</div>
</div>
</div>
The better way to use below code in controller. And create the relations in model.
$categories = App\Models\Category::where('parent_id', 0)->orderBy('order_level','ASC')->get();
Use child parent relation in your model:
public function children()
{
return $this->hasMany(Category:Class,'parent_id');
}
And use with to get as parent-child tree
$categories = App\Models\Category::with('children)->where('parent_id', 0)->orderBy('order_level','ASC')->get();
You can check it using
dd($categories);
and use loop on it easily.
I think your table structure is not appropriate. Maybe you are trying to create an infinity category, subcategory, and other staff. In that case, you may go through this.
Table columns name should be like
id parent_id level name .....
Brief :
id as primary key, parent_id will be foreign key of your db table primary id, and other columns will be as your expectation.
How to read all the staff?
You may follow the below steps.
$categories = Category::query()->where('parent_id',0)->get() // You may put order by something.
Note: What you will get from this query?
The answer is, you will get all the parent's categories.
Now read every single parents category and their childrens.
How to read parents' category and their children?
At First Read Parent category
foreach($categories as $key=>$category){
echo $category->name; // Your Parent Category is here.
}
Secondly, Read the Parent-Child category
foreach($categories as $key=>$category){
echo $category->name; // Your Parent Category is here.
// Must check is child category found or not. Otherwise your error can be arrise.
if($categories->subCategories->count()){
foreach($categories->subCategories as $k=>$subCategory){
echo $subCategory->name;
}
}
}
A question can be here $categories->subCategories->count() && foreach($categories->subCategories as $k=>$subCategory) ?
If you have a question like this.
The answer is below :
Note: You must add a relationship method inside Category Model like A Parent Category can be More Child SubCategory
add this method to your Category Model.
public function subCategories(){
return $this->hasMany(Category::class,'parent_id');
}
Now you will get smooth output.
Have fun.

Delete multiple rows using Laravel and Vue Js

Am having a problem deleting multiple rows in Laravel and Vue Js. I am able to get the values of id as an array. When I click on delete button I get a status 200 but no record is deleted from the database. Here is my code:
In my table
<tr v-for="user in users.data" :key="user.id">
<td>{{user.id}}</td>
<td>{{user.userName}}</td>
<td><input type="checkbox" :value="user.id" v-model="checkedNames"></td>
<button class="btn btn-warning" #click=" deleteAllUser()">Delete
Selected</button>
</td>
</tr>
Vue Js
<script>
export default {
data(){
return{
checkedNames:[],
Function
deleteAllUser(){
this.form.post('api/deletehotspotusers/',{id:this.checkedNames}).then(()=>{
self.loadHotspotUsers();
}).catch(()=> {
Swal.fire("Failed!", "There was something wrong.", "warning");
});
}
}
In my controller
public function deleteAll(Request $request){
if($request->id){
foreach($request->id as $id){
HotspotUsers::destroy($id);
}
}
My route
Route::post('/deletehotspotusers', 'HotspotUsersController#deleteAll');
To delete a model record you need to call the delete method. You can try the below in the controller method
//import use statement at the top of the class
//use Illuminate\Support\Arr;
public function deleteAll(Request $request){
if($request->id){
HotspotUsers::whereIn('id', Arr::wrap($request->id))->delete();
}
}
In Vue, input type checkbox, v-model uses checked property and change event, so v-model will record either true or false based on the checked state. In order to populate the id with user.id, you need to make use of change event
<tr v-for="user in users.data" :key="user.id">
<td>{{user.id}}</td>
<td>{{user.userName}}</td>
<td>
<input type="checkbox" :value="user.id" #change="onChecked(user.id)">
</td>
<td>
<button class="btn btn-warning" #click=" deleteAllUser()">
Delete Selected
</button>
</td>
</tr>
And in the script section in methods
onChecked(id){
if(!this.names.includes(id)){
this.names.push(id)
} else {
this.names.splice(this.names.indexOf(id),1)
}
}
I am not into vue.js.
If your front-end works good, then here is the laravel code.
Make sure that $request->id is receiving the value you expected.
You can use like
Model::destroy([array of primary keys])
If your Model's primary key is id, then you can specify array of ids like [1,2,3,4].
But before make sure the input values by using logger($request->id).
Thank you

Laravel 2 submit buttons in the same form

I am building a CRUD with Laravel. Each category hasMany attachments and each attachment belongsTo a category.
In the category.edit view I want to give the user the possibility of deleting the attachments (singularly) from the Category. I tried this method but it did not work:
Registering route for the attachment:
Route::group(['middleware' => ['auth']], function () {
Route::delete('attachment/{id}', 'AttachmentController#delete')->name('attachment');
});
Handling the delete building the AttachmentController#delete method:
class AttachmentController extends Controller
{
public function delete($id) {
$toDelete = Attachment::findOrFail($id);
$toDelete->delete();
return redirect()->back();
}
}
In the CategoryController (edit method), I fetch the attachments linked to each category to be rendered inside the view:
public function edit($category)
{
$wildcard = $category;
$category = Category::findOrFail($wildcard);
$attachments = App\Category::findOrFail($wildcard)->attachments()->get()->toArray();
return view('category.edit', [
'category' => $category,
'attachments' => $attachments
]);
}
In the view, I render the attachment and the button to delete. I am fully aware of the error of having a form inside another form, nevertheless I do not know antoher approach to submit this delete request.
// update Category form
#foreach ($attachments as $attachment)
<div class="row">
<div class="col-4">
<img style="width: 100%;" src={{ $attachment['url'] }} alt="">
</div>
<div class="col-4">
<div>
<p class="general_par general_url">{{ $attachment['url'] }}</p>
</div>
</div>
<div class="col-4">
<form action="{{ route('attachment', $attachment['id']) }}" method="POST">
#csrf
#method('DELETE')
<button type="submit" class="btn btn-danger">Delete Image</button>
</form>
</div>
</div>
<hr>
#endforeach
// end of update Category form
Should I build a deleteAttachment method inside the CategoryController? If so, how can I still submit the Delete request? Also, if any other Model in the future will have attachments, should I build a deleteAttachment method inside each controller? That is cumbersome. Thanks in advance
if you don't like to use form, then use tag:
<a class="btn btn-danger" href="{{ route('attachment', $attachment['id']) }}">Delete Image</a>
And redefine the route to Route::get(...)
(or maybe use ajax for POST method if that is required)

How can I get images under a blog for a user

What I actually want is, for a specific user, I'm trying to show every image under a single blog. What I'm getting is a single blog post images for every blog.
Controller
$user_id = Session::get('id');
$user = Users::find($user_id);
$blogs = Blog::where('user_id', $user_id)->paginate(10);
$blogImage = BlogImage::where('blog_id', $blogs->pluck('id'))->get();
return view('Users.userlayout', compact('user', 'blogCat', 'blogs', 'username', 'blogImage'));
View Page
#foreach($blogs as $blog)
<div class="post">
#foreach($blogImage as $img)
<img src="{{asset('storage/blog_img/'.$img->blog_img)}}" alt="Image"
class="img-responsive">
#endforeach
<p>
<?php $str = $blog->blog_desc; ?>
{{str_limit($str, 250, "...")}}
</p>
<a href="{{URL::to('/blog-details/'.$blog->id)}}" target="_blank" class="btn_1">
Read more
</a>
</div>
<hr>
#endforeach
This is because you're using where instead of whereIn.
If you try and pass an array or a collection to where it will only use the first value.
$blogImage = BlogImage::whereIn('blog_id', $blogs->pluck('id'))->get();
Since this will return all of the BlogImage's associated with the Blog's the in the paginated list I would imagine you'll need to do a check to make sure you're only displaying the images that are associated with the specific Blog. One way you can do this is by using `#continue():
#foreach($blogImage as $img)
#continue($blogImage->blog_id !== $blog->id)
<img src="{{asset('storage/blog_img/'.$img->blog_img)}}" alt="Image" class="img-responsive">
#endforeach
All of that being said I would recommend using a one-to-many relationship between Blog and BlogImage:
Blog
public function images()
{
return $this->hasMany(BlogImage::class);
}
BlogImage
public function blog()
{
return $this->belongTo(Blog::class);
}
Then in your controller you can Eager load the images and have something like:
$blogs = Blog::with('images')->where('user_id', $user_id)->paginate(10);
And your blade file would have:
#foreach($blog->images as $image)
<img src="{{asset('storage/blog_img/'.$image->blog_img)}}" alt="Image" class="img-responsive">
#endforeach
You could then apply the same one-to-many relationship logic between User and Blog as well.

Trying to get property of non-object Laravel

i'm getting trouble in getting the data from foreign key
that i wanna get the information from table media
already make relation between 2 tables, but still error give me this Trying to get property of non-objectin spite of my table have data between those tables
Modal Dossier
public function media(){
return $this->belongsTo('App\Media');
}
Modal Media
public function dossier(){
return $this->hasOne('App\Dossier');
}
and that my view
i sent the variable $dossier and i did loop
i trying to get all info
#if($dossier->media)
<?php $ext=substr($dossier->media->url,-3) ;?>
<label class="med">
#if($ext=='pdf')
<i class="fa fa-file-pdf-o"></i>
#else
<i class="fa fa-file-word-o"></i>
#endif
{{$dossier->media->libelle}}
</label><a class="btn btn-warning btn-small pull-right" href="documents/{{$dossier->media->url}}"><i class="fa fa-print"></i></a>
<br><br>
<button id="btn-add{{$dossier->id}}" class="btn btn-primary">Ajouter un Media</button>
#else
<div class="div1{{$dossier->id}}">
<div class="alert alert-warning">Aucune media</div><button id="btn-add{{$dossier->id}}" class="btn btn-primary">Ajouter un Media</button>
</div>
#endif
Looks like $dossier is null. You should always check if object is null, like:
#if (is_null($dossier) && $dossier->media)
Check your model Dossier, it may be like:
public function media(){
return $this->belongsTo('App\Media', MEDIA_FORIGNKEY);
}
Hope this help you!

Resources