Data not Saving into pivot table using Laravel Api Resource - php

please I am new to Laravel, I want to use Laravel API Resource to store database inside database.
I have 3 Tables
Users
Category
Category_User (this is a pivot table)
In my Controller (OnboardsControllers), I have this to store data
public function store(Request $request)
{
$category_user = Category_User::firstOrCreate(
[
'user_id' => $request->user()->id,
'category_id' => $request->$category->id,
],
);
return new CategoryUserResource($category_user);
}
In my CategoryUserResource I have this
public function toArray($request)
{
return [
'user_id' => $this->user_id,
'category_id' => $this->category_id,
'created_at' => (string) $this->created_at,
'updated_at' => (string) $this->updated_at,
];
In my Pivot Table, I have this
public function up()
{
Schema::create('category_user', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('category_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamps();
});
}
In my model, I added this
protected $fillable = [
'user_id', 'category_id',
];
In my route/api
Route::post('/category_user', 'OnboardsController#onboardupdate');
I believe the error is here
'user_id' => $request->user()->id,
When I removed it, it didn't returned any error
When I tried to save to my database using Postman to test, it not saving. Please, I don't know what I am doing wrong.
Thanks

To be honest, you do not need a model Category_User (but you need a table).
In Laravel a more concise approach is used:
public function store(Request $request)
{
$user = User::find($request->input('user_id'));
$user->categories()->attach($request->input('category_id'));
}
Also I'm not sure if you have declared a method categories() in model User:
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
I also strongly doubt the existence of method user() of class Request.
If the request parameter has a name category_id, then you need to access it like this:
$request->input('category_id');

Related

Get data from tables with one to one relation for API in Laravel

I'm working on my first Laravel project, and I want to create a REST Api for android application. In my system, I have two tables: categories and images. Table images has column category_id which is a foreign key that references column id on category table.
The categories table
//users table migration
class CreateCategoriessTable extends Migration
{
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
...
}
The images table
class CreateImagesTable extends Migration
{
public function up()
{
Schema::create('images', function(Blueprint $table){
$table->increments('id');
$table->string('name')
$table->integer('category_id')->unsigned();
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('cascade');
$table->timestamps();
});
}
...
}
In the Images model class I did it:
class Images extends Model
{
protected $fillable = ['name'];
protected $hidden = array('created_at', 'updated_at');
public function category(){
$this->belongsTo('App\Category');
}
}
I also created CategoryResource() class as:
class CategoryResource extends JsonResource
{
public function toArray($request)
{
return [
'id'=> $this->id,
'name' => $this->name,
];
}
}
So, I created a CategoryController to with the API methods, and configured the routes to access the corresponding function. The api/category/ url via GET is redirect to the index function of my controller, and the function is like that:
public function index()
{
$categories = Category::get();
return CategoryResource::collection($categories);
}
With this, I can get the categories table data, but I would like merge the users and images table, and get something like this as response:
[
{
'id': 1,
'name': 'category_name',
'image': 'image_name'
}
]
How I can do this?
First add a hasOne relation in Category model for image like this
Category Model
public function image(){
return $this->hasOne('App\Image');
}
Now specify the relation in your CategoryResource
class CategoryResource extends JsonResource
{
public function toArray($request)
{
return [
'id'=> $this->id,
'name' => $this->name,
'image' => new ImageResource($this->whenLoaded('image'))
];
}
}
Create ImageResource for loading images
class ImageResource extends JsonResource
{
public function toArray($request)
{
return [
'id'=> $this->id,
'name' => $this->image_name,
];
}
}
Finally load images relations with eager load in your controller like this
public function index()
{
$categories = Category::with('image')->get();
return CategoryResource::collection($categories);
}

MassAssignmentException _token - Saving users and tasks

I am using Laravel Framework 5.5.22.
I am having users and tasks in my db. My tasks have the following schema:
Schema::create('tasks', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('user_id')->unsigned();
$table->timestamps();
});
My users model looks like the following
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function task()
{
return $this->hasMany('App\Task');
}
}
I would like to store the task from a user in the database. See below the store method I have tried:
public function store(Request $request)
{
$this->validate($request, [
'newTaskName' => 'required|min:3|max:190',
]);
Auth::user()->task()->Create($request->all()); //here I get the error
Session::flash('success', 'New task has been successfully added.');
return redirect()->route('tasks.index');
}
However, I get the following error at this line Auth::user()->task()->Create($request->all());:
Illuminate\Database\Eloquent\MassAssignmentException _token
Any suggestions why the request is not safed properly?
Try with DB
$insertData = [
"name" => $request->name,
"user_id" => \Auth::id()
];
DB::table('tasks')->insert($insertData);
OR if you have model created as Task
$task = new Task($insertData);
$task->save();
Use the ->except() method instead of all():
Auth::user()->task()->create($request->except('_token'));
at Task Model add this line :
protected $guarded = ['_token'];

Laravel - Eloquent attach() not working for models

TL;DR
Trying to get three models to interact using eloquent for a rest api.
User - belongsToMany(pulls)
Pull - belongsToMany(user) && belongsToMany(boxes)
Box - belongsToMany(pulls)
The pull_user table is working perfectly, I can just attach a user after I save a pull. Saving a box works fine but the attach doesn't work/enter anything into the pivot table (I get no errors though).
The Problem
I can't get a pivot table that associates two of my models together to attach() after a save. I have the three models listed above, the pivot is working for pull_user but not for pull_box even though the save for box is working perfectly. I am able to save a box without an error but the association just never occurs (no error).
The Code
pull_box.php
class PullBox extends Migration
{
public function up()
{
Schema::create('pull_box', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('pull_id');
$table->integer('box_id');
});
}
public function down()
{
Schema::dropIfExists('pull_box');
}
}
Pull.php
class Pull extends Model
{
protected $fillable = ['from', 'to', 'runit_id', 'start_time', 'end_time', 'box_count', 'pull_status', 'audit_status', 'status', 'total_quantity', 'accuracy'];
public function users(){
return $this->belongsToMany('App\User');
}
public function boxes(){
return $this->belongsToMany('App\Box');
}
}
Box.php
class Box extends Model
{
protected $fillable = ['user_id','from', 'to', 'runit_id', 'start_time', 'end_time', 'pull_id', 'total_quantity', 'status', 'accuracy'];
public function pulls(){
return $this->belongsToMany('App\Pull');
}
}
BoxController.php
public function store(Request $request)
{
$this->validate($request, [
'user_id' => 'required|integer',
...
]);
$user_id = $request->input('user_id');
...
$box = new Box([
'user_id' => $user_id,
...
]);
$pull = Pull::whereId($pull_id)->first();
if($box->save()){
$pull->boxes()->attach($box->id);
$box->view_box = [
'href' => 'api/v1/box/' . $box->id,
'method' => 'GET'
];
$message = [
'msg' => 'Box created',
'box' => $box,
'pull' => $pull_id
];
return response()->json($message, 201);
}
$response = [
'msg' => 'Box creation error, contact supervisor',
];
return response()->json($response, 404);
}
The Solution
I need to know how I can get this association working. I am going to need to add a new layer in under the pull for Item, but I don't want to move one before I solve this. I think that my problem has to stem from a syntactical/logical error on my part but I can't see it. There are a bunch of questions on SO that are very close to giving me a solution, but after reading them I wasn't able to solve my problem.
Any help is appreciated.
Try renaming your pull_box table to box_pull, pivot tables on laravel must be in alphabetical order. If you want to use custom name on pivot table you have to extends your pivot, for example:
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class PullBox extends Pivot
{
protected $table = 'pull_box';
}
And your many to many relationships:
class Pull extends Model
{
protected $fillable = ['from', 'to', 'runit_id', 'start_time', 'end_time', 'box_count', 'pull_status', 'audit_status', 'status', 'total_quantity', 'accuracy'];
public function users(){
return $this->belongsToMany('App\User');
}
public function boxes(){
return $this->belongsToMany('App\Box')->using('App\PullBox');
}
}
class Box extends Model
{
protected $fillable = ['user_id','from', 'to', 'runit_id', 'start_time', 'end_time', 'pull_id', 'total_quantity', 'status', 'accuracy'];
public function pulls(){
return $this->belongsToMany('App\Pull')->using('App\PullBox');
}
}

Laravel Seeding using Factory for one to one relation

I want to create a test data using laravel seed. I can seed for one table. Here is :
ModelFactory.php:
/** #var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define(App\User::class, function (Faker\Generator $faker) {
static $password;
return [
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
'type' => '0'
];
});
UsersTableSeeder.php :
<?php
use Illuminate\Database\Seeder;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run() {
factory(App\User::class, 50)->create()->each(function ($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
}
}
I have two tables which are users and user_information. They have one-to-one relation. I want to seed user_information with users. But i have no idea, how i can do...
My models relation functions :
User.php
public function userInformation() {
return $this->hasOne('App\UserInformation', 'user_id', 'id');
}
UserInformation.php
public function users() {
return $this->belongsTo('App\User', 'user_id', 'id');
}
Laravel version is 5.3
I followed these docs :
https://laravel.com/docs/5.3/seeding
https://laravel.com/docs/5.3/database-testing#writing-factories
Answering because this came up in a Google search and might help others:
AFAIK the model hasn't got anything to do with seeding, that's used for query building and constraints.
What can do is create a user, every time you call on your factory that requires the user_id.
Credit to prodigy10 for this answer.
$factory->define(User_Information::class, function ($faker) use ($factory) {
return [
'name' => $faker->company(),
'user_id' => factory(User::class)->create()->id
];
});
For one-to-one relationships, its good practice to make the relationship methods singular
User.php
public function userInformation()
{
return $this->hasOne('App\UserInformation', 'user_id', 'id');
}
UserInformation.php
public function user()
{
return $this->belongsTo('App\User', 'user_id', 'id');
}
Above solution for Laravel 8, userInformation factory will have :
'user_id' => User::factory()->create()->id,
if you need to create userInformation table only when there's a corresponding user, the above solution will seed new user_ids into the userinformation table and you may end up with more userinformation rows than users. To fix this, you need to seed only UserInformation Factory seeder in DatabaseSeeder run method and not UserFactory. it will automatically seed the users table.
Alternatively, if you have the users table already defined and wants to seed userInformation table for your number of users.
For Laravel 8, its is shown below:
public function definition()
{
$users = User::all();
return [
'name' => $this->faker->company,
'user_id' => $this->faker->unique()->numberBetween(1, $users->count())
];
}
Since its a one to one relationship. You can generate the list of users and use unique and numberBetween functions to fill unique user_ids.
This works in Laravel 9. Amend your DatabaseSeeder.php such as:
public function run()
{
User::factory(10)->create()->each(function ($user) {
$phone = Phone::factory()->make();
$user->phone()->save($phone); // phone() is hasOne ralationship in User.php
});
}
You don't need to define user_id column in PhoneFactory.php. The Laravel automatically saves corresponding user_id in the database.

Laravel Eloquent Relationships - Integrity constraint violation

I have 3 models: Priority, Task and User
Priority
can be assigned to many tasks
belongs to one user
Code ...
class Priority extends Model
{
protected $fillable = ['name', 'hexcolorcode'];
protected $casts = [
'user_id' => 'int',
];
public function task()
{
return $this->hasMany(Task::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
Task
has one priority assigned
belongs to one user
Code ...
class Task extends Model
{
protected $fillable = ['name'];
protected $casts = [
'user_id' => 'int',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function priority()
{
return $this->hasOne(Priority::class);
}
}
User
can have many tasks
can have many priorities
Code ...
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function tasks()
{
return $this->hasMany(Task::class);
}
public function priorities()
{
return $this->hasMany(Priority::class);
}
}
TaskController
class TaskController extends Controller
{
protected $tasks;
private $priorities;
public function __construct(TaskRepository $tasks, PriorityRepository $priorities)
{
$this->middleware('auth');
$this->tasks = $tasks;
$this->priorities = $priorities;
}
public function index(Request $request)
{
return view('tasks.index', [
'tasks' => $this->tasks->forUser($request->user()),
'priorities' => $this->priorities->forUser($request->user())
]);
}
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'description' => 'required',
'priority' => 'required'
]);
$request->user()->tasks()->create([
'name' => $request->name,
'description' => $request->description,
'priority_id' => $request->priority
]);
return redirect('/tasks');
}
public function edit(Task $task)
{
$this->authorize('edit', $task);
return view('tasks.edit', compact('task'));
}
public function update(Request $request, Task $task)
{
$this->validate($request, [
'name' => 'required|max:255',
]);
$task->update($request->all());
return redirect('/tasks');
}
public function destroy(Request $request, Task $task)
{
$this->authorize('destroy', $task);
$task->delete();
return redirect('/tasks');
}
}
Error
Now when I want to store a task it gives me following error:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails (tasks.tasks,
CONSTRAINT tasks_priority_id_foreign FOREIGN KEY (priority_id)
REFERENCES priorities (id)) (SQL: insert into tasks (name,
user_id, updated_at, created_at) values (test task, 1,
2016-05-01 14:11:21, 2016-05-01 14:11:21))
Is it possible with this construct or do I have to use Polymorphic Relations between priority table and tasks table?
My Tables
Database Model Picture: http://picpaste.de/mysql-kBH4tO5T.PNG
class CreatePrioritiesTable extends Migration
{
public function up()
{
Schema::create('priorities', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->char('name');
$table->char('hexcolorcode', 7);
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
});
}
}
class CreateTasksTable extends Migration
{
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('name');
$table->text('description');
$table->integer('priority_id')->unsigned();
$table->timestamps();
$table->foreign('priority_id')->references('id')->on('priorities');
$table->foreign('user_id')->references('id')->on('users');
});
}
}
UPDATE
PriorityController
class PriorityController extends Controller
{
protected $priorities;
public function __construct(PriorityRepository $priorities)
{
$this->middleware('auth');
$this->priorities = $priorities;
}
public function index(Request $request)
{
return view('priority.index', [
'priorities' => $this->priorities->forUser($request->user()),
]);
}
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'hexcolorcode' => 'required|max:7'
]);
$request->user()->priorities()->create($request->all());
return redirect('/priorities');
}
public function edit(Priority $priority)
{
$this->authorize('edit', $priority);
return view('priority.edit', compact('priority'));
}
public function update(Request $request, Priority $priority)
{
$this->validate($request, [
'name' => 'required|max:255',
'hexcolorcode' => 'required|max:7'
]);
$priority->update($request->all());
return redirect('/priorities');
}
public function destroy(Request $request, Priority $priority)
{
$this->authorize('destroy', $priority);
$priority->delete();
return redirect('/priorities');
}
}
In your store method. The create method it says :
user->tasks(). This bit will only inserting data in user and tasks table. Thats why you have foreign key error. As you are not updating one of your tables(priority) and also you have added foreign keys in tables as i csn see from migration.
What you are trying to achieve is right if you had a pivot table called task_user where you had userid, taskid and a priority_id. That would be perfect as you would simply update the priority column with userid and taskid. Thats one way but it will require few changes OR you can insert data into user and tasks table seperately for which you will need to just change the query. What do you prefer? I can show you an example for which you like.
//for Priority
// store
$priorities = new Priority;
$priorities->name = Input::get('priority_name');
$priorities->hexcolorcode = Input::get('hexcolorcode');
$priorities->save();
$priority = Priority::select('id')->orderBy('created_at', 'desc')->first();
//for Task
$tasks = new Task;
$tasks->name = Input::get('task_name');
$tasks->priority_id = Input::get('priority');
$priorities->save();
// redirect
return Redirect::to('some view please change this');
Please explain views or show screenshots, how are you handling it. For now, I have given you the solution with one controller handling priorities and tasks.
SOLUTION
I added the priority_id attribute to the fillable array inside the task model.
protected $fillable = ['name', 'description', 'priority_id'];
I had an understanding problem, because user_id is assigned automatically from the framework, but it isn't specified in fillable array. That's because I say $request->user->tasks->create(); it is assigned from the framework, but priority_id is assigned through the user, so it is mass assigned and need to be specified in the fillable array.
#Murlidhar Fichadia

Categories