trucks table have brand_id. When I create a truck I want to save the brand_id.
Truck one to one Brand.
Migration Brands
public function up()
{
Schema::create('brands', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
Migration Trucks
public function up()
{
Schema::create('trucks', function (Blueprint $table) {
$table->id();
$table->integer('brand_id');
$table->integer('year');
$table->string('owner_full_name');
$table->integer('number_of_owners')->nullable();
$table->text('comment')->nullable();
$table->timestamps();
});
}
Model Brand
class Brand extends Model
{
protected $table = 'brands';
protected $fillable = ['name'];
public function truck()
{
return $this->belongsTo(Truck::class);
}
}
Model Truck
class Truck extends Model
{
protected $table = 'trucks';
protected $fillable = [
'brand_id',
'year',
'owner_full_name',
'owner_numbers',
'comment'
];
public function brand()
{
return $this->hasOne(Brand::class);
}
}
Truck Form (I am using https://kristijanhusak.github.io/laravel-form-builder/) Form Builder
class TruckForm extends Form
{
public function buildForm()
{
$this
->add('brand_id', Field::SELECT, [
'empty_value' => 'Select Brand',
'choices' => Brand::pluck('name')->all()
])
->add('year', Field::NUMBER, [
'rules' => ['required', 'gt:1900', 'lte:' . Carbon::now()->year]
])
->add('owner_full_name', Field::TEXT, [
'rules' => ['required', new MinWordsRule(2)]
])
->add('number_of_owners', Field::NUMBER, ['rules' => 'nullable'])
->add('comment', Field::TEXTAREA, ['rules' => 'nullable'])
->add('Save or Create', Field::BUTTON_SUBMIT, [
'attr' => ['class' => 'btn btn-success']
]);
}
}
My need when create truck brand_id save being his brand
Truck Controller
public function create(FormBuilder $formBuilder)
{
$brandForm = $formBuilder->create(TruckForm::class, [
'method' => 'POST',
'url' => route('trucks.store')
]);
return view('landing.trucks.create', compact('brandForm'));
}
public function store(FormBuilder $formBuilder, Request $request)
{
$brandForm = $formBuilder->create(TruckForm::class);
$brandForm->redirectIfNotValid();
$object = new Truck();
$object->fill($request->all());
$object->save();
$object->brand()->save($request->input('brand_id'));
return redirect()->route('trucks.index');
}
First, make sure to validate your user inputs even if they came from an HTML select tag
//...
'brand_id' => 'required|exists:brands,id' // make sure your brand_id is a valid ID
//...
Then
Keep your controller simple
public function store(FormBuilder $formBuilder, Request $request)
{
$brandForm = $formBuilder->create(TruckForm::class);
$brandForm->redirectIfNotValid();
$object = new Truck();
// this line will map the brand_id attr to $obj->brand_id and link the 2 models to each others ...
$object->fill($request->all());
$object->save();
return redirect()->route('trucks.index');
}
Your relationships are switched around, as you can see here, since the Truck has the brand_id it should have the belongsTo and Brand should have the hasOne, like this:
Brand model:
class Brand extends Model
{
public function truck()
{
return $this->hasOne(Truck::class);
}
}
Truck model:
class Truck extends Model
{
public function brand()
{
return $this->belongsTo(Brand::class);
}
}
And as you can see here, you can simplify your store method to something like this:
public function store(FormBuilder $formBuilder, Request $request)
{
$form = $formBuilder->create(TruckForm::class);
$form->redirectIfNotValid();
Truck::create($form->getFieldValues());
return redirect()->route('trucks.index');
}
Or using the FormBuilderTrait:
use Kris\LaravelFormBuilder\FormBuilderTrait;
use App\Forms\TruckForm;
class TruckController extends Controller
{
use FormBuilderTrait;
public function store(Request $request)
{
$form = $this->form(TruckForm::class);
$form->redirectIfNotValid();
Truck::create($form->getFieldValues());
return redirect()->route('trucks.index');
}
}
Related
Asside from the $movie data I want to also get all the genres that a movie belongs to following this path: 127.0.0.1:8000/api/movies/{id}. My foreign keys are in the separate table so how exactly I can achieve that? My migrations:
public function up()
{
Schema::create('genres', function (Blueprint $table) {
$table->id();
$table->string('name');
});
}
public function up()
{
Schema::create('movies', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->integer('status')->nullable()->default(0);
$table->string('image_path')->default('default.png');
});
}
public function up()
{
Schema::create('genre_movie', function (Blueprint $table) {
$table->foreignId('genre_id')->constrained()->cascadeOnDelete();
$table->foreignId('movie_id')->constrained()->cascadeOnDelete();
});
}
Movie model:
class Movie extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = ['name', 'status', 'image_path'];
public function genres()
{
return $this->belongsToMany(Genre::class, 'genre_movie');
}
}
Genre model:
class Genre extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = ['name'];
public function movies()
{
return $this->belongsToMany(Movie::class, 'genre_movie');
}
}
Movie Resource:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'status' => $this->status,
'image_path' => url()->to('/images/' .$this->image_path),
];
}
Genre Resource:
public function toArray($request){
return [
'id' => $this->id,
'name' => $this->name,
];
}
Function in the controller which only returns $movie data:
public function show(Movie $movie)
{
return new MovieResource($movie);
}
I thought this would work:
public function show(Movie $movie)
{
return new MovieResource($movie->with('genres'));
}
But I receive this error: "message": "Property [id] does not exist on the Eloquent builder instance."
You can return JSON with a small change too.
public function showMovieAndGenre(Movie $movie)
{
$fullData = Movie::join('genres', 'genres.id', '=', 'movies.id')
->select([
'movies.id AS mid',
'genres.id AS gid',
'movies.name AS mname',
'genres.name AS gname',
'movies.status AS status',
'movies.image_path AS image_path'
])
->get();
return $fullData;
}
return $this->belongsToMany(Genre::class, 'genre_movie');
Consider using hasManyThrough https://laravel.com/docs/9.x/eloquent-relationships#has-many-through
hope you are safe and doing well. I am facing an issue with laravel relational table. I have three table, USER, CLIENT ,ORDER and CAR_PARKING. Now Client is related to user and ORDER is related to both Client and USER while CAR_PARKING related to ORDER only. What i am facing like issue is that when I am trying to update table ORDER it says #General error: 1364 Field 'start_date' doesn't have a default value#
Below are my different table models and controller
public function updateOrderCarParking(Request $request, $id)
{
if (Auth::check()) {
$carParkingData = $request->only('removed', 'removed_date');
$validateCarParking = Validator::make($carParkingData, [
'removed' => 'required|boolean',
'removed_date' => 'nullable'
]);
if ($validateCarParking->fails()) {
return response()->json($validateCarParking->errors(), 422);
}
$orderData = $request->only('paid', 'amount_paid', 'overdue', 'currency', 'user_id');
$validateOrder = Validator::make($orderData, [
'amount_paid' => 'required|regex:/^\d*+(\.\d{1,2})?$/',
'currency' => [
'required',
Rule::in(['USD', 'CAD'])
],
"paid" => "required|boolean",
'overdue' => 'regex:/^\d*+(\.\d{1,2})?$/'
]);
if ($validateOrder->fails()) {
return response()->json($validateOrder->errors(), 422);
}
$updateCarParking = CarParking::updateOrCreate([
'removed' => $request->removed,
'removed_date' => $request->removed_date,
]);
$order = Order::find($id);
$order->carParkings()->save($updateCarParking);
$updateOrder = Order::find($id);
$updateOrder->amount_paid = $request->amount_paid;
$updateOrder->paid = $request->paid;
$updateOrder->currency = $request->currency;
$updateOrder->overdue = $request->overdue;
$updateOrder->user_id = Auth::user()->id;
$updateOrder->save();
if ($order && $updateOrder) {
return response()->json([
'success' => true,
'message' => 'Order updated successfully',
'data' => $order
], Response::HTTP_OK);
}
} else {
return response()->json([
'success' => false,
'message' => 'Can not update',
], Response::HTTP_UNAUTHORIZED);
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
use HasFactory;
protected $fillable = ['order_type', 'amount_paid','client_id', 'user_id', 'price', 'currency', 'paid', 'overdue'];
public function user()
{
return $this->belongsTo(User::class);
}
public function client()
{
return $this->belongsTo(Client::class);
}
public function carParkings(){
return $this->hasMany(CarScrap::class);
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CarParking extends Model
{
use HasFactory;
protected $fillable = ['start_date', 'end_of_free_charge', 'order_id', 'removed', 'removed_date'];
public function order()
{
return $this->belongsTo(Order::class);
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOrdersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->decimal('price', 8, 2);
// $table->date('start_date');
$table->enum('order_type', ['Storage rent', 'Forklift', 'Ramp', 'Car Parking', 'Car Scrap', 'Shipping']);
$table->enum('currency', ['USD', 'CAD']);
$table->boolean('paid')->default('0');
$table->decimal('amount_paid')->default(0);
$table->decimal('overdue')->nullable();
$table->foreignId('client_id')->constrained('clients')->onDelete('cascade');
$table->foreignId('user_id')->constrained('users')->onDelete('cascade');
$table->timestamps();
});
Schema::enableForeignKeyConstraints();
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('orders', function (Blueprint $table) {
$table->dropConstrainedForeignId("client_id");
$table->dropConstrainedForeignId("user_id");
});
Schema::dropIfExists('orders');
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCarParkingsTable extends Migration
{
public function up()
{
Schema::create('car_parkings', function (Blueprint $table) {
$table->id();
$table->date('start_date');
$table->date('end_of_free_charge');
$table->boolean('removed')->default("0");
$table->date('removed_date')->nullable();
$table->timestamps();
$table->foreignId('order_id')->constrained('orders')->onDelete('cascade');
});
Schema::enableForeignKeyConstraints();
}
public function down()
{
Schema::table('car_parkings', function (Blueprint $table) {
$table->dropConstrainedForeignId("order_id");
});
Schema::dropIfExists('car_parkings');
}
}
What am I doing wrong?
Replace your existing method with this:
class CreateCarParkingsTable extends Migration
{
public function up()
{
Schema::create('car_parkings', function (Blueprint $table) {
$table->id();
$table->date('start_date')->nullable();
$table->date('end_of_free_charge');
$table->boolean('removed')->default("0");
$table->date('removed_date')->nullable();
$table->timestamps();
$table->foreignId('order_id')->constrained('orders')->onDelete('cascade');
});
Schema::enableForeignKeyConstraints();
}
public function down()
{
Schema::table('car_parkings', function (Blueprint $table) {
$table->dropConstrainedForeignId("order_id");
});
Schema::dropIfExists('car_parkings');
}
}
If you get error for any other field then make it nullable as I had done in start_date
Set start_date to Nullable in Database Migration.
Example:
$table->date('start_date')->nullable();
How can we imagine that only two lines of code have solved the errors. No need of setting nullable on any column. I got the solution by doing this code below:
$client = Client::findOrFail($client->id);
$client->update($request->all());
But i put in the model the relationships function. I meant in the CLIENT model i put
public function orders(){
return $this->hasMany(Order::class);
}
same thing for order model
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);
}
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
I'm having troubles to setup the right Eloquent relationships (belongsTo, hasMany, ...) for a pivot table.
I will abbreviate code for clarity.
I have two important tables: 'parties' and 'p2p_relations'.
This is the migration for parties
public function up()
{
Schema::create('parties', function ($table) {
$table->increments('id');
$table->string('name');
$table->unsignedInteger('kind');
$table->timestamps();
$table->softDeletes();
$table->foreign('kind')->references('id')->on('kinds');
});
}
This is the migration for p2p_relations (party to party relations)
public function up()
{
Schema::create('p2p_relations', function ($table) {
$table->bigIncrements('id');
$table->unsignedInteger('context');
$table->unsignedInteger('reference');
$table->datetime('start');
$table->datetime('end')->nullable();
$table->unsignedInteger('kind')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('context')->references('id')->on('parties');
$table->foreign('reference')->references('id')->on('parties');
$table->foreign('kind')->references('id')->on('kinds');
});
}
The model for Party
class Party extends Ardent
{
use SoftDeletingTrait;
protected $softDelete = true;
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $table = 'parties';
public static $rules = array(
'name' => 'required',
'kind' => 'required|numeric'
);
}
The model for Relation
class Relation extends Ardent
{
use SoftDeletingTrait;
protected $softDelete = true;
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $table = 'p2p_relations';
public static $rules = array(
'context' => 'required|numeric',
'reference' => 'required|numeric',
'kind' => 'required|numeric',
'start' => 'required|date',
'end' => 'date'
);
}
How can I set relationships so I can associate parties as context or reference in a relationship.
I thought belongsTo will help like so in class Relation
public function context() {
return $this->belongsTo('Party', 'context', 'id');
}
public function reference() {
return $this->belongsTo('Party', 'reference', 'id');
}
But when I run this unit-test I get an error: Undefined property: Relation::$context
$context = new Party();
$context->name = 'Person A';
$context->kind = 1;
$context->save();
$ref = new Party();
$ref->name = 'Company B';
$ref->kind = 2;
$ref->save();
$relation = new Relation();
$relation->start = new DateTime();
$relation->context()->associate($context);
$relation->reference()->associate($ref);
$relation->kind = 3;
$relation->save();
Any thoughts? I'm really a newbie to this framework.
Thanks to the comments provided I've learned a lot :-)
Updated my Party Model:
public function references() {
return $this->belongsToMany('Party', 'p2p_relations', 'context', 'reference')
->withPivot('reference', 'start', 'kind')
->withTimestamps() ;
}
No Relation model needed.
The pivot table works perfectly.
Thanks