I want a user to delete a product when he clicks unlike button but I'm getting an error 404 url not found, but I have the url.
If I put dd($product) before $like = Like::findOrFail($product);
it displays the id(4) but if I put dd($like), then it throws an error 404. How can I make this function work?.
Controller
public function destroy($product)
{
$like = Like::findOrFail($product);
dd($like);
$like->delete();
return 'done';
}
Blade
<a class="remove" href="{{ route('product.unlike', ['product' => $product->id]) }}" > Unlike </a>
Route
Route::get('product/{product}/unlike', ['as' => 'product.unlike', 'uses' => 'LikeController#destroy']);
Like.php
class Like extends Model
{
use SoftDeletes;
protected $table = 'likeables';
protected $fillable = [
'user_id',
'product_id',
'likeable_id',
'likeable_type',
];
public function products()
{
return $this->morphedByMany('App\Product', 'likeable');
}
delete request should be post request not get
web.php
Route::delete('product/{product}/unlike','LikeController#destroy')->name('product.unlike');
blade.php
<form action="{{ route('product.unlike',[$product->id]) }}" method="post">
#csrf
#method('DELETE')
<button type="submit" class="remove"> Unlike </button>
</form>
controller
use App\Product;
...
public function destroy(Product $product) {
$product->delete();
return 'done';
}
Hope this helps!
Detach the Products corresponding to the like.
public function destroy($product)
{
Like::where('product_id', $product)
->where('user_id', auth()->user()->id)
->delete();
return 'done';
}
findOrFail will throw an exception which will cause the 404 when it can't find a record. You are using SoftDeletes so the record can exist in the database but doesn't mean that it hasn't been 'soft deleted'. If it has been soft deleted the scope will make it act like it isn't there.
Check your record with id == 4 to see if it has a deleted_at column with a value. If it does, it was deleted (soft deleted). You will have to adjust your query to be able to retrieve soft deleted records.
Laravel 6.x Docs - Eloquent - Soft Deletes - Querying Soft Deleted Models
Related
I want to delete a single row of data in my pivot table. I don't get any error but when try to click on the button. It did not redirect me to anywhere so the delete function is not performed.
In the picture above I want to delete the highlighted id for user_id = 3
My scenario is that the user suddenly can't make it to even_id = 6 so the user wants to delete/unjoined the event.
route
Route::get('/user/event/{event}', 'HomeController#destroy')->name('user.event.destroy');
blade
#foreach ($events as $event)
<tr>
<td>{{$loop->index +1 }}</td>
<td>{{$event->event_name}}</td>
<td>{{$event->event_date}}</td>
<td>
<form method="POST" action="{{ route('user.event.destroy',$event)}}">
#csrf
#method('DELETE')
<a class="btn btn-danger">Unjoined!</a>
</form>
</td>
</tr>
#endforeach
controller
public function storeEventUser(Request $request)
{
$user = User::find(Auth::user()->id);
//how I storing my pivot data (just to show if anyone asking)
$user->events()->syncWithoutDetaching([$request->event_id]);
}
public function destroy($event)
{
$event= Event::findOrFail($event_id);
$user->events()->detach($event);
return redirect()->back()->with('success','Deleted.');
}
Event model
public function users()
{
return $this->belongsToMany(User::class,'event_user','event_id','user_id');
}
user model
public function events()
{
return $this->belongsToMany(Event::class,'event_user','user_id','event_id');
}
I am adjusting your controller method to use Route Model Binding for simplicity:
public function destroy(Event $event)
{
Auth::user()->events()->detach($event);
// or from the other side of the relationship
// $event->users()->detach(Auth::user());
return redirect()->back()->with('success', 'Deleted.');
}
As stated in the comments you need to adjust your route to Route::delete if you want to use the DELETE HTTP method that your form is spoofing via the #method('DELETE') blade directive.
Side note:
Auth::user() returns a User instance so you don't need to query for it again, in your storeEventUser method:
$user = Auth::user();
I added a CRUD interface for my user's table, and instead of a delete button, I used a block button. Which blocks a user (sets bloque field in the database from 0 to 1). I added a new function in my controller called block which is supposed to do the job yet I get a MethodNotAllowedHttpException error every time I click the blocking button.
UserController
public function block($id)
{
$user = User::find($id);
$user->bloque = 1;
$user->save();
return redirect('/users')->with('success', 'Utilisateur bloqué');
}
The blocking HTML fragment
<form action="{{ route('users.block', $user->id)}}" method="get">
#csrf
<!-- #method('DELETE')-->
<button class="btn btn-danger" type="submit">Bloquer</button>
</form>
Routes
Route::get('/block', [
'uses' => 'UserController#block',
'as' => 'users.block'
]);
I think the problem is related to id value, It should be instantiated from $request object. Like:
public function block(Request $request)
{
$user = User::find($request->id);
$user->bloque = 1;
$user->save();
return redirect('/users')->with('success', 'Utilisateur bloqué');
}
Since I started with my first Laravel project I've been having the error
Trying to get property 'column_name' of non-object nonstop, and most of the time I've been able to fix it one way or another, but the problem is, I have no idea of why I get the error, or how can I prevent it. For example,
// In my controller I have this domPDF function...
public function pdfgen(Request $request, $id) {
$data = Table::find($id);
View()->share('data', $data);
if ($request -> has('download')) {
$pdf = PDF::loadView('pdf/pdfgen');
return $pdf ->download('pdfgen.pdf');
}
return view('pdf/pdfgen');
}
// In my blade file I have a table calling this column...
<td>{{ $data->column }}</td>
// and this link making the request in the pdfgen function...
<a class="btn btn-primary" href="{{ route('pdfgen', ['download'=>'pdf']) }}">Download PDF</a>
// And in my routes of web.php...
Route::get('/pdfgen/{id}', array('as' => 'pdfgen', 'uses' => 'PDFController#pdfgen'));
and whenever I press that download link, I get a Whoops page with the trying to get property 'column' of non-object (View: /usr/src/workapp/resources/views/pdf/pdfgen.blade.php). Why am I getting this error and not the open/save dialog?
EDIT: Forgot to add, before trying to get specific data with $id, I called the whole table ($data = Table::all();) and used a #foreach in the blade view to print it in the table
EDIT 2: Adding the model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Table extends Model
{
protected $table = 'table';
protected $primaryKey = 'id';
public $incrementing = false;
protected $fillable = [
// all columns are strings, even id
'id',
'column',
'column2',
'column3',
];
public function table2()
{
return $this->hasMany('App\Table2');
}
}
When you do find($id) and the record is not present, it returns null. So if you try to access any property ->column, it will throw error.
You can either do findOrFail($id) or have condition if (is_null($data)) or on frontend have $data->column ?? 'defaultvalue
'
Now, the second situation where your model is present but you still get error, do :
$data = Table::find($id);
dd(array_keys($data->toArray()));
You should see the column you are trying to access if it is present.
Lastly, if it is not present in above step but is there in the table, then check for protected $hidden = [] setting of your model which essentially hides certain columns.
This happend because your $data might be null and your record with given $id might not exists in your database.
Try to change your code like below:
Table::findOrFail($id);
From now on if your table with given id doesn't exist, it'll automatically return 404 page.
I'm using laravel 5.4 and the latest version of yajra/laravel-datatables as a service.
I have it working fine with one datatable on a page. I want to create a dashboard of unrelated tables. Users, products, bookings etc.
I was hoping to have my controller look something like this:
public function index(ProductsDataTable $productDatatable, UsersDataTable $userDatatable)
{
$user = Auth::user();
$products = $user->products;
return view('admin.dashboard', compact('products', 'user', 'productDatatable', 'userDatatable'));
}
and in my blade do
#section('content')
{!! $productDatatable->table() !!}
{!! $userDatatable->table() !!}
#endsection
#push('scripts')
{!! $dataTable->scripts() !!}
#endpush
However this obviously doesn't work. I'm unsure how to proceed.
I tried to create a route for each datatable but wasn't sure how to reference it from my dashboard controller.
I'm sure there's a better way of implementing multiple tables in one view, but this is what I came up with after reviewing this. Comments/improvements would be highly appreciated.
Controller
The controller will render the tables once in the index() method but will fetch data from both the getUsers() method or getProducts() method.
// DashboardController.php
public function index(UsersDataTable $usersDataTable, ProductsDataTable $productsDataTable)
{
return view('dashboard.index', [
'usersDataTable' => $usersDataTable->html(),
'productsDataTable' => $productsDataTable->html()
]);
}
//Gets Users JSON
public function getUsers(UsersDataTable $usersDataTable)
{
return $usersDataTable->render('admin.dashboard');
}
//Gets Products JSON
public function getProducts(ProductsDataTable $productsDataTable)
{
return $productsDataTable->render('admin.dashboard');
}
Routes
Add two extra routes that will be used to fetch Users and Projects data.
// web.php
Route::get('/', 'DashboardController#index')->name('dashboard.index');
Route::get('projects', 'DashboardController#getProjects')->name('dashboard.projects');
Route::get('users', 'DashboardController#getUsers')->name('dashboard.users');
DataTables Service Class
For both the UsersDataTable and ProductsDataTable service classes, include the relevant routes we created above.
// UsersDataTable.php
public function html()
{
return $this->builder()
->minifiedAjax( route('dashboard.users') );
}
View
// dashboard.blade.php
#section('content')
{!! $productsDataTable->table() !!}
{!! $usersDataTable->table() !!}
#endsection
#push('scripts')
{!! $productsDataTable->scripts() !!}
{!! $usersDataTable->scripts() !!}
#endpush
Submitted a question to the creator of the package. This is his response:
Unfortunately, DataTable service class is designed to handle single instance. However, I think we can make a workaround for it by adding additional query param in our request for us to identify which class is being requested to handle the request.
Maybe something like below:
public function index(ProductsDataTable $productDatatable, UsersDataTable $userDatatable)
{
if (request()->has('product') {
return $productDatatable->render('view');
}
if (request()->has('user') {
return $productDatatable->render('view');
}
$user = Auth::user();
$products = $user->products;
return view('admin.dashboard', compact('products', 'user', 'productDatatable', 'userDatatable'));
}
Step 1:
Define a route '/home-page' in web.php/route.php' (depending on the laravel version you are using) that returns the view called 'dt.blade.php'. (we will create this view in step 4)
i.e. Route::get('/home-page', function(){
return view('dt');
});
Step 2:
Suppose you want to display two dataTables in 'dt.blade.php' view. (first datatable shows all the students in a school while other shows all the classes in a school)
To do that, you need to create two Builder instances ('Builder' class belongs to DataTables package) in the '/home-page' route's callback function and pass them to the 'dt.blade.php' view . i.e
Route::get('/home-page', function() {
$student_dt = app(Builder::class)->columns(['id', 'student_name'])->ajax('/show-students-datatable')->setTableId('t1');
$classes_dt = app(Builder::class)->columns(['id', 'class_name'])->ajax('show-classes-datatable')->setTableId('t2');
return view('dt', compact('student_dt', 'classes_dt'));
});
Step 3
Now define two more routes in web.php/route.php file:
Route::get('/show-students-datatable', function () {
return datatables(App\Student::query()->select(['id', 'student_name']))->toJson();
});
Route::get('/show-classes-datatable', function () {
return datatables(App\Class::query()->select(['id', 'class_name'])))->toJson();
});
Step 4
Define the 'db.blade.php' view, this view show both the dataTables that were passed to it in step 1.
#extends('layouts.master')
#section('content')
{{ $student_dt->table() }}
{{ $classes_dt->table() }}
#endsection
#push('scripts')
{{$student_dt->scripts()}}
{{$classes_dt->scripts()}}
#endpush
I'm trying to create post page with comments; however, it's not working when I add the comment to a post because the system doesn't recognize the post id. What I'm I doing wrong that it doesn't know that the post_id is equal to $post_id
I'm getting the following error:
SQLSTATE[HY000]: General error: 1364 Field 'post_id' doesn't have a default value (SQL: insert into comments (body, updated_at, created_at) values (This is a test comment, 2017-08-15 19:51:47, 2017-08-15 19:51:47))
COMMENTS FORM
<div class="well">
<h4>Leave a Comment:</h4>
<form role="form" method="post" action="{{ $post->id }}/comments">
{{ csrf_field() }}
<div class="form-group">
<textarea name="body" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
ROUTE
Route::post('/posts/{post}/comments', 'CommentController#store');
CONTROLLER
public function store(Post $post)
{
$post->addComment(request('body'));
return back();
}
COMMENT MODEL
class Comment extends Model
{
protected $fillable = ['body'];
public function post()
{
return $this->belongsTo(Post::class);
}
}
POST MODEL
class Post extends Model
{
public function addComment($body)
{
Comment::create([
'body' => $body,
'post_id' => $this->id
]);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
}
post_id isn't in fillable array:
class Comment extends Model
{
protected $fillable = ['body', 'post_id']; //<---
...
}
I see, your controller function doen't know what post your talking about. You need to use the post id that is coming back from your form and locate the post then you can save the new comment like this
$comment = new App\Comment(['message' => 'A new comment.']);
$post = App\Post::find(1);
$post->comments()->save($comment);
As shown in the Laravel Docs 5.4 Eloquent it will fill the id in for you.
Also if I remember correctly you do not need to add ['post_id'] to your array of fillable fields.
The SQL error can be resolved by using a "column modifier". (see below)
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});
Laravel Docs 5.4 Migrations
in your table in mysql make sure your post_id is auto increment or can be "null". This error is saying post_id has no value and cant be default.
From the look of your code post_id is your primary key but not set to auto increment