How to check data from pivot table? - laravel

I have an Event and User model which have a pivot table called event_users.
In the pivot table event_id and user_id is saved when user press participate button.
I have displayed all the event list.
Now i want to display event which is participated as participated and not participated as participate.
i have tried
controller
public function vieweventlist()
{
$data['events'] = Event::with('users')->get();
return view('page',$data);
}
blade file
#foreach($events as $event)
<h1>Event Name</h1>
#foreach($event->users as $check)
#if($check->pivot->user_id == auth()->user()->id && $check->pivot->event_id == $event->id)
<button type="button" class="btn participateevent" disabled>Participated</button>
#else
<button type="button" class="btn participateevent">Participate</button>
#endif
#endforeach
#endforeach
I have set belongsToMany relation in both the Event and User models.
The problem with this code is second foreach loop is pivot table loop. Suppose I have one data in pivot table. I have list down 5 events. Because of pivot table foreach (Second one) only one button is shown in blade file which is participated but doesn't show #else participate button.

Your second foreach makes it so only events who has participants (ether the logged in user or not) will show a button (participated or participate). If an event has no users attached to it, no button will be shown.
If you want to get the list of events with the information "if the current user is already participating to it or not" then here is a better way.
Controller
public function vieweventlist(){
$data['events'] = Event::withCount('users', function($user) {
$user->where('id','=', auth()->id());
})->get();
return view('page',$data);
}
Blade
#foreach($events as $event)
<h1>Event Name</h1>
#if($event->users_count)
<button type="button" class="btn participateevent" disabled>Participated</button>
#else
<button type="button" class="btn participateevent">Participate</button>
#endif
#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.

Getting id value from url in controller and displaying values associated laravel

I'm trying to create a ticket management system with laravel jetstream and livewire. In the user page there's a table with all tickets that the user created. When the user clicks on the button to open one specific ticket, it should pass the id of the ticket and redirect to another page where it receives the data of that ticket he clicked, like title, message, etc..
The id is passed through the url, but my main problem is that whenever I try to display that data in the view, nothing shows, no errors either. I think that something might be wrong with my controller.
Here's my route:
Route::get('tickets.answers/{id}', [TicketsController::class, 'answers']);
The button to redirect to that specific ticket:
<a href="{{ url('tickets.answers' . '/'. $ticket->id ) }}" > <x-jet-secondary-button >
See Answer
</x-jet-secondary-button></a>
AnswersController:
public function render(Request $request)
{
$tickets = Ticket::where('id', $request->url('id'));
return view('livewire.tickets.answers', [
'tickets' => $tickets,
]);
}
And how I'm trying to display in my blade:
#foreach($tickets as $key => $ticket)
<!-- This example requires Tailwind CSS v2.0+ -->
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg leading-6 font-medium text-gray-900">
Ticket nº {{$ticket->id}} - {{$ticket->title}}
</h3>
</div>
</div>
#endforeach
In your TicketsController you can fetch the id like this
public function answer(Request $request, int $id)
{
// Use the find() method, instead of where(), when searching for the primary key
$tickets = Ticket::find($id);
// .. more
}
In your routes files you specify an answer method, so use this in your TicketsController.
// See how to name a route
Route::get('tickets.answers/{id}', [TicketsController::class, 'answers'])->name('tickets.answers');
Then use the named route in your view like this:
<a href="{{ route('tickets.answers', ['id' => $ticket->id]) }}">
You can see a similar example in the Laravel docs.

View and Controller for a Downloadpage

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

Laravel: How to create link buttons on a view dynamically?

I'm making a College Administration website where a professor can log in.
I have a dashboard, where my dynamically generated button should be placed: (right now it just has dummy buttons!)
Generated by this view file, which I will have to modify soon:
<div class="container d-flex flex-column align-items-center justify-content-center">
<h1>IA DASHBOARD</h1>
<br>
<div class="grid2">
SUBCODE 1</button>
SUBCODE 2</button>
SUBCODE 3</button>
</div>
Tables in the Database:
the table iamarks contains the data (student info, and marks) that is to be displayed after /subcode/{subcode} narrows it down to records of just the students that are in the class assigned to current logged-in professor.
classroom_mappers is a table used to map a professor to a classroom with a subject. It makes sure that one classroom only has one professor for a particular subject.
the routes currently in my web.php:
route::get('/ia', 'IAController#show')->middleware('auth');
Route::get('/subcode/{subcode}', 'IAController#showTable')->middleware('auth');
...and these are the methods inside my controller:
//shows buttons to the user:
public function show(){
$subcodes = DB::table('classroom_mappers')
->select('subcode')
->where([['PID','=', auth()->user()->PID]])
->get();
return view('ia',compact('subcodes'));
}
//when user clicks a button, subcode is to be generated and a table is to be shown:
//it works, I tried it by manually typing in subcode value in URL.
public function showTable($subcode){
$sem = DB::table('classroom_mappers')
->where([['PID','=', auth()->user()->PID],
['subcode','=',$subcode]])
->pluck('semester');
$division = DB::table('classroom_mappers')
->where([['PID','=', auth()->user()->PID],
['semester','=',$sem],
['subcode','=',$subcode]])
->pluck('division');
$data = DB::table('iamarks')
->where([['semester','=',$sem],
['division','=',$division],
['subcode','=',$subcode]])
->get();
return view('subcode',compact('data'));
}
My Problem:
To be able to generate the {subcode} in the URL dynamically, I want to create buttons in the dashboard using the data $subcodes. The controller hands over the $subcodes (an array of subject codes which belong to logged in professor) which are to be made into buttons from the show() method.
The buttons should have the name {subcode} and when clicked, should append the same subject code in the URL as {subcode}.
How do I make use of $subcodes and make the buttons dynamically?
How do I make sure the buttons made for one user are not visible to another user?
I managed to find the solution, thanks to Air Petr.
Apparently, you can't nest blade syntax like {{some_stuff {{ more_stuff }} }} and it generates a wrong php code. I modified the solution by Air Petr to:
<div class="grid2">
#foreach ($subcodes as $subcode)
<a href="<?php echo e(url('/subcode/'.$subcode->subcode));?>">
<button class="btn btn-outline-primary btn-custom-outline-primary btn-custom">
<?php
echo e($subcode->subcode);
?>
</button>
</a>
#endforeach
</div>
It generates the buttons perfectly. The buttons for one user are not visible to another, since I'm using PID constraint in a query (['PID','=', auth()->user()->PID]).
Pass the passcodes array to view:
$subcodes = []; // Array retrieved from DB
return view('subcode', compact('subcodes'));
And in subcode.blade.php, loop through each subcode:
<div class="grid2">
#foreach($subcodes as $subcode)
<a href="{{ url('/subcode/' . $subcode->subcode) }}">
<button class="btn btn-outline-primary btn-custom-outline-primary btn-custom">SUBCODE {{ $subcode->subcode }}</button>
</a>
#endforeach
</div>
You can loop your codes to create buttons. Something like this (it's for "blade" template engine):
<div class="grid2">
#foreach ($subcodes as $subcode)
{{ $subcode->subcode }}</button>
#endforeach
</div>
Since you're using PID constrain in a query (['PID','=', auth()->user()->PID]), you'll get buttons for that specific PID. So there's no problem.

Gate Fascade and Model Policies

I'm currently trying to find out if you can add a Gate Fascade to a Policy or if there's a better way to handle my situation.
I have a list of users with each having ONE role and each role can have MANY permissions. All of this is stored in my database with the correct relationships established in my models.
I am trying to show or not show a delete icon based on whether a user can delete another user in my HTML list of users.
Example:
Lets say user1 has a role of 3 which is a site-admin. Site admins have the permission to delete users, however they are NOT able to delete other users who have the same role as them or a role higher than theirs.
When user1 accesses the /users uri they are shown the HTML table of users in the database and as the last table column are the actions that can be performed on the row for that user row. The available action icons are edit and delete. For the delete icon I want a policy to be ran to make sure than the authenicated user can delete users first but also pass the current row's user object and see if the user has the same role id or higher in which case it will NOT display that icon.
<?php
namespace App\Policies;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class UserPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
//
}
public function delete(User $user) {
return Auth::user()->role->permission and $user->role_id < Auth::user()->role_id and $user->id != Auth::user()->id;
}
}
/reources/views/partials/tables/actions.blade.php
<td class="actions">
<i class="icon wb-edit" aria-hidden="true"></i>
<i class="icon wb-eye" aria-hidden="true"></i>
#can('delete-user', $user)
<form class="inline" method="POST" action="{{ route('users.delete', [$user->id]) }}">
{{ method_field('DELETE') }}
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-sm btn-icon btn-pure btn-default on-default" data-toggle="tooltip" data-original-title="Delete"><i class="icon wb-trash" aria-hidden="true"></i></button>
</form>
#endcan
</td>
Rewrite your policy method like this (I used your own syntax and assumed it's true):
public function delete(User $authUser, User $user) {
return $authUser->role->permission and
$user->role_id < $authUser->role_id and
$user->id != $authUser->id;
}
In your policy methods, first argument is always your authenticated user, and other arguments are what you pass through methods like #can or Gate::allow.

Resources