Cannot call to a public function of Model (Laravel) - php

I just started learning Laravel, I'm newbie. I've got a problem, I'm watching Laravel Course for beginners and learning, was doing exactly the same as in he tutorial, but still ended up with a problem. I hope to find a solution soon. I'll explain it a little bit.
The project is kind of a clone of Instagram. Users can post images to page.
I have this function in User model
User.php
public function posts()
{
return $this->hasMany(Post::class);
}
And I'm trying to access it from my PostsController
PostsController.php
class PostsController extends Controller
{
public function create()
{
return view('posts.create');
}
public function store()
{
$user = auth()->user();
$data = request()->validate([
'caption' => 'required',
'image' => ['required', 'image']
]);
auth()->user()->posts()->create($data);
\App\Models\Post::create($data);
dd(request()->all());
}
}
I'm doing exactly as in tutorial, but for some reason this line is failing at posts() call.
auth()->user()->posts()->create($data);
I'm getting that it's undefined method. But it is indeed defined in User.php
EDIT:
Exact error I'm getting is:
Illuminate\Database\QueryException
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: posts.user_id (SQL: insert into "posts" ("caption", "image", "updated_at", "created_at") values (Caption, C:\xampp\tmp\php2E32.tmp, 2021-05-19 12:16:08, 2021-05-19 12:16:08))
And foreign key is user_id.
Actually I just checked my posts table and it seems it is stored in database, so it's working, but how to get rid of this error then?

this is a silly mistake of you..you are adding same post twice. once with relationship association and again from post model.
auth()->user()->posts()->create($data);
\App\Models\Post::create($data); //this is causing the issue here.
with relationship association auth()->user()->posts()->create($data), post is inserted to the database. as the foreign key user_id is coming from relationship. but in the next line \App\Models\Post::create($data), your $data array is missing user_id and thus the NOT NULL constraint failed error occurs. you can't insert a row with user_id being null. and this line is actually adding duplicate data. remove this line. use either one of the method.
with relationship association
$data = request()->validate([
'caption' => 'required',
'image' => ['required', 'image']
]);
auth()->user()->posts()->create($data);
or using model directly
$data = request()->validate([
'caption' => 'required',
'image' => ['required', 'image']
]);
$data['user_id'] = auth()->user()->id; //added user_id in the validated data array
\App\Models\Post::create($data);
and vs code always don't know all of your functions. depending on vs code to find a problem is not the best way.

Note:: you need to use Post Model and you can directly create data Using Post::create() method.
//Import Data
use Illuminate\Http\Request;
use App\Modes\Post;
class PostsController extends Controller
{
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
//Check Validation
$data = request()->validate([
'caption' => 'required',
'image' => ['required', 'image']
]);
//Get Login User Data in $user variable
$user = auth()->user();
//Store user id into $data variable which we can pass into $data Variable.
$data[‘user_id’] = $user->id;
//Create Data Using create() method.
$post = Post::create($data);
//Final Save Your Data
if( $post->save() ) {
dd(“data save successfully”);
}else{
dd(“something went wrong”);
}
}
}

Related

Laravel 8: Checking user's data with database table does not work properly

I have created a two factor authentication system, and it redirects user to token.blade.php where he must enters the token that is going to be sent to his phone number and also stored at active_codes table.
Now I want to check if the user has entered the same token code that was stored at active_codes table which looks like this:
And then at the Controller, I tried this:
public function submit(Request $request)
{
$data = $request->validate([
'token' => 'required|min:6'
]);
if($data['token'] === auth()->user()->activeCode()->code){
dd('same');
}
}
But when I enter the same token, I get this error:
ErrorException Undefined property:
Illuminate\Database\Eloquent\Relations\HasMany::$code
so my question is how to check if the requested token code of user, is as same as the token code which is stored on the DB ?
Note: The relationship between User and ActiveCode Models is OneToMany.
User.php:
public function activeCode()
{
return $this->hasMany(ActiveCode::class);
}
ActiveCode.php:
public function user()
{
return $this->belongsTo(User::class);
}
Your solution is pretty easy, you are not doing ->first() or ->get(), so you are trying to access a model property on a HasMany class.
This code should be similar to:
auth()->user()->activeCode()->first()->code
But if you have more than 1 code, then you should do something like:
public function submit(Request $request)
{
$data = $request->validate([
'token' => 'required|min:6'
]);
if(auth()->user()->activeCode()->where('code', $data['token'])->exists()){
dd('same');
}
}

Insert array of arrays in Lumen with Eloquent ORM

The POST request I'm sending looks like this:
{ "array1":
[
{"title":"my blogADD","description":"myblogdescriptionADD","status":1},
{"title":"my blogUPDATEDADD","description":"myblogdescriptionUPDATEDADD","status":1},
{"title":"my blog33ADD","description":"myblogdescription33ADD","status":1}
]
}
Its JSON format, headers have been set.
The controller code which gets the request looks like this:
public function create(Request $request){
$this->validate($request, [
'array1' => 'present|array',
'array1.*.title' => 'required',
'array1.*.description' => 'required'
]);
$data = $request->getContent();
$data = json_decode($data, true);
//dd($data);
Article::insert($data);
}
Now, I've looked into multiple questions and answers on SO on this problem, and the findings are somehow contradictory.
Model::insert() shall be able to insert multiple rows in ONE call.
However, as you can see, this hasn't worked for me so far.
Model::create() is only able to create one new row, but I found solutions which use loops to iterate over the arrays. I would very very much like to avoid such a solution, unless someone can FOR CERTAIN tell me that there is no other, simple solution. Because I very much believe that there must be one.
When I input the json_decoded ARRAY then I get the response that an Array to String conversion is hindering the process.
When I input the mere JSON-String, then I get the error:
"Argument 1 passed to Illuminate\Database\Query\Builder::insert() must be of the type array, string given, called in E:\LumenTut\firstTut\vendor\illuminate\database\Eloquent\Builder.php on line 1350"
Well, here are two links to SO posts which, in my opinion, basically dealt with the same problem. But somehow it seems they could solve it and I can't, so I wonder what I am missing:
How to insert a multidimensional array in a database using laravel
laravel 5.6 bulk inserting json data
For completeness, here is the full Code of ArticleController.php:
EDIT:
<?php
namespace App\Http\Controllers;
//use Validator;
use App\Article;
use Illuminate\Http\Request;
class ArticleController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
//
}
//
public function showAllArticles(){
return response()->json(Article::get(['title', 'description', 'status'])); // ::get([]) spezifiziert die zu referenzierenden Attribute
// ::all() referenziert alle Attribute einer Tabelle/Relation
}
public function showOneArticle($id){
return response()->json(Article::find($id));
}
public function create(Request $request){
$this->validate($request, [
'array1' => 'present|array',
'array1.*.title' => 'required',
'array1.*.description' => 'required'
]);
$data = $request->getContent();
//$data = json_decode($data, true);
//dd($data);
Article::insert($data);
}
public function update($id, Request $request){
$this->validate($request, [
'title' => 'required',
'description' => 'required'
]);
$article = Article::findOrFail($id);
$article->update($request->all());
return response()->json($article, 200);
}
public function delete($id, Request $request){
Article::findOrFail($id)->delete();
return response('Deleted Successfully', 200);
}
public function resetRecords(Request $request){
Article::where('id', '>', 2)->delete();
}
}
From the looks of it, it feels like you are trying to push array1 directly in your table, whereas you need to push the content of it so maybe try like this, in your controller code:
$requestData = $request->all();//this will give you an array with key array1
$data = $requestData['array1'];//this will give you data you want to insert
Article::insert($data);
Based on the error. You are not passing an array. You can change the $data with
$data = $request->all();
$request->all() returns the data from the post in array.
You can rewrite your create method with the following.
public function create(Request $request){
$request->validate([
'array1' => 'present|array',
'array1.*.title' => 'required',
'array1.*.description' => 'required'
]);
$data = $request->all();
Article::insert($data['array1']);
}

Laravel Eloquent $model->save() not saving but no error

When updating my Post model, I run:
$post->title = request('title');
$post->body = request('body');
$post->save();
This does not update my post. But it should according to the Laravel docs on updating Eloquent models. Why is my model not being updated?
I get no errors.
The post does not get updated in the db.
Besides not being updated in the db, nothing else seems odd. No errors. Behavior as normal.
Result of running this test to see if save succeeded was true.
This Laravel thread was no help
Post model:
class Post extends Model
{
protected $fillable = [
'type',
'title',
'body',
'user_id',
];
....
}
Post controller:
public function store($id)
{
$post = Post::findOrFail($id);
// Request validation
if ($post->type == 1) {
// Post type has title
$this->validate(request(), [
'title' => 'required|min:15',
'body' => 'required|min:19',
]);
$post->title = request('title');
$post->body = request('body');
} else {
$this->validate(request(), [
'body' => 'required|min:19',
]);
$post->body = request('body');
}
$post->save();
return redirect('/');
}
Bonus info
Running dd($post->save()) returns true.
Running
$post->save();
$fetchedPost = Post::find($post->id);
dd($fetchedPost);
shows me that $fetchedPost is the same post as before without the updated data.
Check your database table if the 'id' column is in uppercase 'ID'. Changing it to lower case allowed my save() method to work.
I had the same and turned out to be because I was filtering the output columns without the primary key.
$rows = MyModel::where('...')->select('col2', 'col3')->get();
foreach($rows as $row){
$rows->viewed = 1;
$rows->save();
}
Fixed with
$rows = MyModel::where('...')->select('primary_key', 'col2', 'col3')->get();
Makes perfect sense on review, without the primary key available the update command will be on Null.
I had the same problem and changing the way I fetch the model solved it!
Was not saving even though everything was supposedly working just as you have mentioned:
$user = User::find($id)->first();
This is working:
$user = User::find($id);
You have to make sure that the instance that you are calling save() on has the attribute id
Since Laravel 5.5 laravel have change some validation mechanism I guess you need to try this way.
public function store(Request $request, $id)
{
$post = Post::findOrFail($id);
$validatedData = [];
// Request validation
if ($post->type == 1) {
// Post type has title
$validatedData = $request->validate([
'title' => 'required|min:15',
'body' => 'required|min:19',
]);
} else {
$validatedData = $request->validate([
'body' => 'required|min:19',
]);
}
$post->update($validatedData);
return redirect('/');
}
Running dd() inside a DB::transaction will cause a rollback, and the data in database will not change.
The reason being, that transaction will only save the changes to the database at the very end. Ergo, the act of running "dump and die" will naturally cause the script to cease and no therefore no database changes.
Check your table if primary key is not id ("column name should be in small letters only") if you have set column name with different key then put code in your Model like this
protected $primaryKey = 'Id';
So this might be one of the possible solution in your case also if your column name contains capital letters.
Yes this worked for me fine,
You should have column names in small letter,
If you don't have then mention it in the model file, mainly for primaryKey by which your model will try to access database.
For use save () method to update or delete if the database has a primary key other than "id". need to declare the attribute primaryKey = "" in the model, it will work
Try this
public function store($id,Request $request)
{
$post = Post::findOrFail($id);
// Request validation
if ($post->type == 1) {
// Post type has title
$request->validate([
'title' => 'required|min:15',
'body' => 'required|min:19',
]);
$post->update([
'title' => request('title');
'body' => request('body');
]);
} else {
$request->validate([
'body' => 'required|min:19',
]);
$post->update([
'body' => request('body');
]);
}
return redirect('/');
}
In my experience, if you select an Eloquent model from the db and the primary_key column is not part of the fetched columns, your $model->save() will return true but nothing is persisted to the database.
So, instead of doing \App\Users::where(...)->first(['email']), rather do \App\Users::where(...)->first(['id','email']), where id is the primary_key defined on the target table.
If the (sometimes micro-optimization) achieved by retrieving only a few columns is not really of importance to you, you can just fetch all columns by doing \App\Users::where(...)->first(), in which case you do not need to bother about the name of the primary_key column since all the columns will be fetched.
If you using transactions.
Do not forget call DB::commit();
It must look like this:
try{
DB::beginTransaction();
// Model changes
$model->save();
DB::commit();
}catch (\PDOException $e) {
DB::rollBack();
}
I have the same issue although there are try / catch block in controller#action() but there were no response, it just stops at $model->save(); there is no log entry either in apache error.log or laravel.log. I have just wrapped the save() with try / cactch as follows, that helped me to figure out the issue
try{
$model->save();
}
catch (\PDOException $e) {
echo $e->getMessage();
}
I have been experiencing the same issue and found a workaround. I found that I was unable to save() my model within a function called {{ generateUrl() }} on my home.blade.php template. What worked was moving the save() call to the controller that returns the home.blade.php template. (IE, save()ing before the view is returned, then only performing read operations within {{ generateUrl() }}.)
I was (and am) generating a state to put in a URL on page load:
<!--views/home.blade.php-->
Add Character
Below is what did not work.
// Providers/EveAuth.php
function generateUrl()
{
$authedUser = auth()->user();
if (!$authedUser) {
return "#";
}
$user = User::find($authedUser->id);
$user->state = str_random(16);
$user->save();
$baseUrl = 'https://login.eveonline.com/oauth/authorize?state=';
return $baseUrl . $user->state;
}
This was able to find() the User from the database, but it was unable to save() it back. No errors were produced. The function appeared to work properly... until I tried to read the User's state later, and found that it did not match the state in the URL.
Here is what did work.
Instead of trying to save() my User as the page was being assembled, I generated the state, save()d it, then rendered the page:
// routes/web.php
Route::get('/', 'HomeController#index');
Landing at the root directory sends you to the index() function of HomeController.php:
// Controllers/HomeController.php
public function index()
{
$authedUser = auth()->user();
if ($authedUser) {
$user = User::find($authedUser->id);
$user->state = str_random(16);
$user->save();
}
return view('home');
}
Then, when generating the URL, I did not have to save() the User, only read from it:
// Providers/EveAuth.php
function generateUrl()
{
$authedUser = auth()->user();
$user = User::find($authedUser->id);
$baseUrl = 'https://login.eveonline.com/oauth/authorize?state=';
return $baseUrl . $user->state;
}
This worked! The only difference (as far as I see) is that I'm save()ing the model before page assembly begins, as opposed to during page assembly.

rules() function in Laravel Request doesn't create unique slugs

I'm trying to make simple unique slugs. The slugs are saved correctly in database, so the function is working. I have problems with making them unique.
I have this rule in TagCreateRequest.php
public function rules()
{
$rules = [
'tag' => 'required|min:3',
'tag_slug' => 'required|alpha_dash|unique:tag,tag_slug,'
];
$rule = 'unique:tag';
$segments = $this->segments();
$id = intval(end($segments));
if ($id != 0) {
$rule .= ',tag_slug,' . $id;
}
$rules['tag_slug'][] = $rule;
return $rules;
}
and this in my store function in the controller
public function store(TagCreateRequest $request)
{
$tag = new Tag();
foreach (array_keys($this->fields) as $field) {
$tag->$field = $request->get($field);
}
$tag->save();
return redirect()->route('tags');
}
The error is about trying to add duplicate value
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'unique slug' for key 'tags_tag_unique'
Can someone help me to fix this issue?
You can access the id field magically. ID must be the same route parameter used in your route.
If you use id parameter like as Route::put('post/{id}/update') then you can magically access the id parameter inside your form request. Otherwise, if you call the parameter of {post} Route::put('post/{post}/update'), in your form request you must be call $this->post instead of $this->id, ok?
Please try it:
public function rules()
{
$rules = [
'tag' => 'required|min:3'
];
$slugRule = 'required|alpha_dash|unique:tag_slug';
if (! empty($this->id)) {
$slugRule = 'required|alpha_dash|unique:tag_slug,'.$this->id;
}
$rules['tag_slug'] = $slugRule;
return $rules;
}
This FormRequest will work fine on the store() and update() methods if you inject him in both methods.
See it:
// Your store route
Route::post('/post/store', ['as' => 'post.store', 'uses' => 'YourController#store']);
// YourController store method
public function store(NameSpaced\FormRequest $request)
{
// ...
}
// Your update route
Route::post('/post/{id}/update', ['as' => 'post.update', 'uses' => 'YourController#store']);
// YourController update method
public function update(NameSpaced\FormRequest $request)
{
// ...
}
$rules = [
'tag' => 'required|min:3',
'tag_slug' => 'required|alpha_dash|unique:[table name],[column name]'
];
Try this the first is table name and the second is column name that you wanted to unique, write without adding square braces. or you just pass table name like this,
$rules = [
'tag' => 'required|min:3',
'tag_slug' => 'required|alpha_dash|unique:[table name]'
];
laravel auto checks for the column.
I hope it helps.
I would suggest that you automatically generate a new slug whenever you are creating a tag. I got myself in same issues that you have listed here, so i decided on automatically generating whenever i am creating a new item. I used laravel-sluggable. It automatically generates unique slugs.
As per your question, i have defined a unique slug rule in one of my demo apps like this:
public function rules()
{
return [
'name' => 'required|string|max:255',
'slug' => 'required|string|max:255|unique:categories,slug,'.$this->segment(3),
];
}
Please note that $this->segment(3) refers to the id of the model being updated in the backend pages, it can be different in your application.

Laravel 5.2 save data to m:n table

I have problem with saving data to m:n table layout in laravel 5. I have table appliances and table documentations, where pivot table is documentation_appliance.
Models are:
class Appliances extends Model
{
public function documentations()
{
return $this->belongsToMany('documentations');
}
}
and
class Documentation extends Model
{
public function appliances()
{
return $this->belongsToMany('appliances');
}
}
Now I try to save data to table in my Controller
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'file_name' => 'required',
]);
if($request->hasFile('file_name') ) {
$fname = $request->file('file_name')->getClientOriginalName();
$request->file('file_name')->move(
base_path() . '/public/files/documentation/', $fname
);
}
$document = new Documentation();
$document->name = $request->name;
$document->filename = $fname;
if($document->save()) {
$doc_ids = $request->documentation_appliance;
$document->appliances()->sync($doc_ids);
}
return view('backend.documentation.index', [
'documentations' => $this->documents->getDocuments(),
]);
}
Data to table documents are saved corectly, image is stored, but I have problem with saving data to pivot table. Screen displays me this error:
FatalErrorException in compiled.php line 10191:
Class 'appliances' not found
in compiled.php line 10191
nothing more, I guess I have bad use of class somewhere or am I doing bad something else? Thanks everyone for help.
according to https://laravel.com/docs/5.2/eloquent-relationships#many-to-many your table name must be appliance_documentation not documentation_appliance.

Categories