Call to a member function comments() on null when use foreign key - laravel

This is error Call to a member function comments() on null, in model give a relation still show this error
Article model
function user() {
return $this->belongsTo(User::class, 'id');
}
public function comments()
{
return $this->hasMany(Comment::class, 'id');
}
Comment Model
public function user()
{
return $this->belongsTo(User::class);
}
public function article()
{
return $this->belongsTo('App\Article');
}
This is contoller
public function store(Request $request)
{
//dd($request->all());
Auth::user();
$comment = new Comment;
$comment -> user_id=Auth::user()->id;
$comment-> comment = $request->get('comment');
$article = Article::find($request->article_id);
$article->comments()->save($comment);
return redirect()->back()->with('success', 'your comment,successfully save');
}
This is blade file
<form method="post" action="{{ route('comment.store') }}">
#csrf
<div class="form-group">
<textarea class="form-control" name="comment"></textarea>
<input type="hidden" name="article_id"/>
</div>
<div class="form-group">
<input type="submit" class="btn btn-success" value="Add Comment" />
</div>
</form>

You need to set a value for the hidden field.
<input type="hidden" name="article_id" value="{{ $article->id }}"/>
Secondly for easier debugging these errors, using findOrFail() will ensure your app blows up, with a proper error message. Instead of just returning null.
$article = Article::findOrFail($request->article_id);
EDIT
You are also mixing two saving approaches together, either you associate the article to the comment or create a new comment. This is the approach i like to use.
$comment = new Comment;
$comment->user_id = Auth::user()->id;
$comment->comment = $request->get('comment');
$article = Article::find($request->article_id);
$comment->article()->associate($article);
$comment->save();

Related

404 not found on laravel post request

I'm making a post request in my form. The csrf token and the method are there.
<div class="flex">
<form action="{{ route('profile.store.follower', $user) }}" method="post">
#csrf
<input value="follow" type="hidden" name="follow" value="{{$user->id}}" >
<button type="submit" class="bg-green-700">Follow</button>
</form>
</div>
The route:
Route::get('/usersprofile/{user:name}/index', [ProfileController::class, 'index'])->name('profile.index');
Route::post('/usersprofile/{user:name}/index', [ProfileController::class, 'store'])->name('profile.store.follower');
The controller:
public function store(User $user, Request $request) {
dd($user);
$user = user::findOrFail($request->follow);
Auth::user()->following->attach($user->id);
return back();
}
The following function in the user model:
public function following() {
return $this->belongsToMany(User::class, 'followers', 'user_id', 'following_id');
}
For some reason, it's not going through. I've tried php artisan route:cache and config:cache but the error persists. I've checked the route list and the route exists.
Your hidden input has two value attributes, that's probably why it doesn't find a user and fails.
Remove the hidden input and the line $user = user::findOrFail($request->follow); - the user you want to follow already exists in $user via your route. Then use Auth::user()->following->attach($user); to follow.
<div class="flex">
<form action="{{ route('profile.store.follower', $user) }}" method="post">
#csrf
<button type="submit" class="bg-green-700">Follow</button>
</form>
</div>
public function store(User $user, Request $request)
{
Auth::user()->following->attach($user);
return back();
}

Update data in laravel 6

I try to create crud in laravel 6. Create, Read and Delete process is running well. But when Update process, the data in table not change. Could anyone help me to find the problem ? The following my code.
Route
Route::get('/blog', 'BlogController#index');
Route::get('/blog/add','BlogController#add');
Route::post('/blog/store','BlogController#store');
Route::get('/blog/edit/{id}','BlogController#edit');
Route::post('/blog/update','BlogController#update');
Controller
public function index()
{
$blog = DB::table('blog')->get();
return view('blog',['blog' => $blog]);
}
public function edit($id)
{
$blog = DB::table('blog')->where('blog_id', $id)->get();
return view('edit', ['blog'=>$blog]);
}
public function update(Request $request)
{
DB::table('blog')->where('blog_id',$request->blog_id)->update([
'blog_title' => $request->title,
'author' => $request->author]);
return redirect('/blog');
}
View
#foreach ($blog as $n)
<form method="post" action="/blog/update" />
{{ csrf_field() }}
Title <input type="text" name="title" value="{{ $n->title}}">
Author<input type="text" name="author" value="{{ $n->author}}">
<button type="submit" class="btn btn-secondary">Update</button>
</form>
#endforeach
You must provide id in your route
Route::post('/blog/update/{id}','BlogController#update');
In update method add parameter id and then find product against id
public function update(Request $request, $id)
{
DB::table('blog')->where('blog_id',$id)->update([
'blog_title' => $request->title,
'author' => $request->author]);
return redirect('/blog');
}
#foreach ($blog as $n)
<form method="post" action="{{ route('your route name'), ['id' => $$n->id] }}" />
{{ csrf_field() }}
Title <input type="text" name="title" value="{{ $n->title}}">
Author<input type="text" name="author" value="{{ $n->author}}">
<button type="submit" class="btn btn-secondary">Update</button>
</form>
#endforeach
try separating the update into two statements like so
$blog = DB::table('blog')->where('blog_id',$id)->first();
$blog->update([
'blog_title' => $request->title,
'author' => $request->author]);
Also you might want to use models in the future so you can do it like
$blog = Blog::where('blog_id',$id)->first();
Doesn't really shorten your code but it improves the readibility.
Do your update like this:
public function update(Request $request)
{
$post = DB::table('blog')->where('blog_id',$request->blog_id)->first();
$post->blog_title = $request->title;
$post->author = $request->author;
$post->update();
return redirect('/blog');
}

How to send variable from blade to controller without changing the url

In blade I have a list of books. I want to choose a specific book to show its information. And to do so I want to send with href the id of the book to my controller passing through route.
For example i have
<div class="body text-center">
<h6><b>{{($book->getName())}}</b></h6>
</div>
In href I want to add $bookId = $book->id and the route name so I can call the route with the specific name which calls a method in a controller which can use the variable $bookId
Route::get('/infromation','Books\BookController#index')->name('info');
Here's two propositions:
The first one is to use spatie/laravel-sluggable to have the book name in the URL
The second one is to access the book without changing the URL with a POST request
Using spatie/laravel-sluggable
The slug will be generated automatically from name when the book is created.
your-migration.php
Schema::create('books', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('slug')->unique()->index();
$table->string('name');
// ...
$table->timestamps();
});
web.php
// Change the URIs as you want. `{book}` is mandatory to retrieve the book though.
Route::get('/books','Books\BookController#index')->name('book.index');
Route::get('/books/{book}','Books\BookController#show')->name('book.show');
Book.php
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
class Book extends Model
{
use HasSlug;
protected $guarded = [];
public function getSlugOptions()
{
// Adapt with what you want
return SlugOptions::create()
->generateSlugsFrom('name')
->saveSlugsTo('slug')
->doNotGenerateSlugsOnUpdate();
}
public function getRouteKeyName()
{
return 'slug';
}
}
BookController.php
class BookController extends Controller
{
public function index()
{
return view('book.index');
}
public function show(Book $book)
{
// $book is retrieving using Model Binding: https://laravel.com/docs/5.8/routing#route-model-binding
return view('book.show', compact('book'));
}
}
index.blade.php
<div class="body text-center">
<a href="{{ route('book.show', $book) }}">
<h6><b>{{ $book->getName() }}</b></h6>
</a>
</div>
Using POST request (URI does not change) and without SLUG
I wouldn't recommend using this for the user experience.
The user cannot bookmark the book or share the link with someone else
When refreshing the page, it will prompt to the user if he want to re-submit the form request
web.php
Route::get('/books','Books\BookController#index')->name('book.index');
Route::post('/books','Books\BookController#show')->name('book.show');
BookController.php
class BookController extends Controller
{
public function index()
{
return view('book.index');
}
public function show()
{
$book = Book::findOrFail(request('book_id'));
return view('book.show', compact('book'));
}
}
index.blade.php
<div class="body text-center">
<form action="{{ route('book.show') }}" method="POST">
#csrf
<input type="hidden" value="{{ $book->id }}" name="book_id">
<h6>
<button type="submit">
<b>{{ $book->getName() }}</b>
</button>
</h6>
</form>
</div>
You can remove the default button style to make it looks like a link
https://stackoverflow.com/a/45890842/8068675
You can try like this
<form action="/BookName/information/<?php echo $book->id; ?>" method="post">
<div class="body text-center">
<input type="hidden" name="book_id" value="{{ $book->id }}">
<a href="/information/<?php echo $book->id; ?>">
<button type="submit" name="book_information" class="btn btn-primary">
<h6>
<b>{{($book->getName())}}</b>
</h6>
</button>
</div>
</form>
// make route like this
Route::post('/BookName/information/{id}','Books\BookController#index');
// Access the that id in controller
public function index(Request $request)
{
echo $request->book_id;
}

SQLSTATE[HY000]: General error: 1364 Field 'title' doesn't have a default value

Hi I am trying to insert data into db but it says:
SQLSTATE[HY000]: General error: 1364 Field 'title' doesn't have a
default value (SQL: insert into projects (owner_id, updated_at,
created_at) values (1, 2019-06-28 13:17:11, 2019-06-28 13:17:11))
I am following Laracasts Laravel from scratch tutorial
controller:
public function store()
{
$attributes = $this->validateProject();
$attributes['owner_id'] = auth()->id();
$project = Project::create($attributes);
//Project::create($attributes);
//Project::create(request(['title', 'description']));
Mail::to($project->owner->email)->send(
new ProjectCreated($project)
);
return redirect('/projects');
}
model:
protected $guarded = [];
table:
Schema::create('projects', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('owner_id');
$table->string('title');
$table->text('description');
$table->timestamps();
$table->foreign('owner_id')->references('id')->on('users')->onDelete('cascade');
});
blade file:
<form method="POST" action="/projects">
#csrf
<div class="field">
<label class="label" for="title">Title</label>
<div class="control">
<input type="text" class="input {{ $errors->has('title') ? 'is-danger' : ''}}" name="title" value="{{ old('title') }}" placeholder="Project title">
</div>
</div>
<div class="field">
<label class="label" for="title">Description</label>
<div class="control">
<textarea name="description" class="textarea {{ $errors->has('description') ? 'is-danger' : ''}}" placeholder="Project description">{{ old('description') }}</textarea>
</div>
</div>
<div class="field">
<div class="control">
<button type="submit" class="button is-link">Create Project</button>
</div>
</div>
#include('errors')
</form>
how to solve this issue
You have the field title on the projects table however you are not assigning it a value. As it is set as Not Nullable this will give this error.
You will need all attributes to be in the $fillable attribute on the model when using Project::create($attributes); which you do not seem to have.
An example of the $fillable would be :
protected $fillable = [
'title',
'description',
'owner_id',
];
There are several other potential causes however it is impossible to tell without you including your full Project model and the view which this request is from.
Edit
You will need to change your function to this :
public function store(ProjectRequest $request)
{
$attributes = $request->all();
$attributes['owner_id'] = auth()->id();
$project = Project::create($attributes);
Mail::to($project->owner->email)->send(
new ProjectCreated($project)
);
return redirect('/projects');
}
You can create the ProjectRequest class by running php artisan make:request ProjectRequest and then putting your validation rules in there instead.
Read more here.
Add your column name in fillable like this in your model (I guess your model name is Project.php)
So your model class should like this.
<?php
mnamespace App;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
protected $guarded = [];
protected $fillable = [
'title', 'owner_id','description'
];
public function owner()
{
return $this->belongsTo(User::class);
}
public function tasks()
{
return $this->hasMany(Task::class);
}
public function addTask($task)
{
$this->tasks()->create($task);
}
}
And then update your controller store method like this.
public function store(Request $request)
{
$attributes = $this->validateProject();
$attributes->owner_id = auth()->id();
$attributes->title = $this->request->title;
$attributes->description= $this->request->description;
$project = Project::create($attributes);
Mail::to($project->owner->email)->send(
new ProjectCreated($project)
);
return redirect('/projects');
}
The error itself is self explanatory, check this code:
$attributes['owner_id'] = auth()->id();
$project = Project::create($attributes);
here you are creating a new record in project table, and for that you are taking only one column i.e. owner_id, but in the table there is a column title which do not have a default value.
So either take all the column while creating a new record or provide those column a default value (null or something else).
To set null as default value in migration:
$table->string('title')->nullable();
or you can directly change the column in database and set its default value as null, see the below screenshot:
Unable to trace the problem you are facing. Give this code a try and please comment if you got any problem.
Inside your route file
Route::post('project', 'ProjectController#store')->name('project.store');
In your create view
<form method="POST" action="{{route('project.store')}}">
#csrf
<div class="field">
<label class="label" for="title">Title</label>
<div class="control">
<input type="text" class="input {{ $errors->has('title') ? 'is-danger' : ''}}" name="title"
value="{{ old('title') }}" placeholder="Project title">
</div>
</div>
...
<div class="field">
<div class="control">
<button type="submit" class="button is-link">Create Project</button>
</div>
</div>
#include('errors')
</form>
In your ProjectController
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
class UserController extends Controller{
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required|max:255',
]);
$post = Post::create([
'title' => $request->title,
'owner_id' => auth()->id()
]);
return redirect('/projects');
}
EDIT 1
In your previous code inside ProjectsController, instead of using $attributes try using
public function store()
{
$project = Project::create([
'title' => request('title'),
'owner_id' => request('owner_id')
]);
Mail::to($project->owner->email)->send(
new ProjectCreated($project)
);
return redirect('/projects');
}
EDIT 2
Instead of using create method, try this one
public function store()
{
$project = new Project();
$project->title = request('title');
$project->owner_id = request('owner_id');
$project->save();
...
}

Laravel user input form to query database

been trying to create a laravel form with several fields that the user can enter text/number into a field and it takes the field with data and performs a database query. Now the form works with just one field but when i add more fields it only returns data for the final query, not for the other two.
perfumes controller
class perfumescontroller extends Controller
{
public function index()
{
$pstoreNum = request('pstoreNum');
$result = perfumes::where('StoreNumber','=',$pstoreNum)
->get();
return view('perfumes',compact('result'));
}
public function perfWeekSearch()
{
$weekNum = request('perfWeekNum');
$result = perfumes::where('WeekNumber','=',$weekNum)
->get();
return view('perfumes',compact('result'));
}
}
Route::get('/perfumes', 'perfumescontroller#index');
Route::get('/perfumes', 'perfumescontroller#perfWeekSearch');
Blade:
<form action="perfumes" method="get">
{{ csrf_field() }}
<div class="input-group">
<input type="text" class="form-control" name="perfWeekNum" placeholder="Type in Store Number">
<span class="input-group-btn">
<button type="submit" class="btn btn-default">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</form>
Do i need to use some sort of check if not null method? or is there an easier way??
Thanks
I think this would be work below is your perfumes controller
class perfumescontroller extends Controller
{
public function index()
{
$data = $request->all();
if(!empty($data['pstoreNum'])){
$pstoreNum = $data['pstoreNum'];
$result = DB::table('perfumes')->where('StoreNumber','=',$pstoreNum)
->get();
return view('perfumes',compact('result'));
} else if(!empty($data['perfWeekNum'])){
$weekNum = $data['perfWeekNum'];
$result = DB::table('perfumes')->where('WeekNumber','=',$weekNum)
->get();
return view('perfumes',compact('result'));
}
}
}
and you use any with route like below:
Route::any('/perfumes', 'perfumescontroller#index');

Resources