I am trying to attatch book and warehouses upon creating a new book in my laravel project.
At the moment i have a checkbox for each warehouse, in my view:
#foreach($warehouses as $warehouse)
<input type="checkbox" name="checked[]" value="{{ $warehouse->id }}">
{{ $warehouse->address }}
<br/>
#endforeach
And i have the many to many relations in my book and warehouse models:
Book:
class Book extends Model
{
use HasFactory;
protected $table = 'books';
protected $fillable = [
'ISBN', 'publisher_id', 'author_id', 'year', 'title', 'price',
];
public function warehouses()
{
return $this->belongsToMany(Warehouse::class);
}
Warehouse:
class Warehouse extends Model
{
use HasFactory;
protected $table = 'warehouses';
protected $fillable = [
'name', 'address', 'phone', 'url',
];
public function books()
{
return $this->belongsToMany(Book::class);
}
When submitting the foreach in the form on my book.create view, i try to attach each checked warehouses in the same process as creating the new book:
My Create method:
public function create()
{
$authors = Author::all();
$selectedAuthor = Book::first()->author_id;
$publishers = Publisher::all();
$selectedPublisher = Book::first()->publisher_id;
$warehouses = Warehouse::all();
$selectedWarehouse = Book::first()->warehouse_id;
return view('books.create', compact(['authors', 'publishers', 'warehouses'],
['selectedAuthor', 'selectedPublisher', 'selectedWarehouse']
));
}
And my store method to store the created data:
public function store(Request $request)
{
$request->validate([
'ISBN' => 'required',
'author_id' => 'required',
'publisher_id' => 'required',
'year' => 'required',
'title' => 'required',
'price' => 'required',
]);
try {
Book::create($request->all());
$book = Book::first(); // Book::first(); saves to the first found book (id 1), needs to be fixed to the requested book.
foreach ($request->checked as $value){
$book->warehouses()->attach([$value]);
}
return redirect()->route('books.index')
->with('success','Book created successfully.');
} catch (\Illuminate\Database\QueryException $e) {
var_dump($e->errorInfo);
}
}
The problem is my
$book = Book::first();
saves to the first found book (id 1, even though i might be creating book id 43), needs to be fixed to the requested book that is currently being created.
I have updated my store method by assigning
Book::create($request->all());
To my $book variable which solved the problem, my store method now looks like this:
public function store(Request $request)
{
$request->validate([
'ISBN' => 'required',
'author_id' => 'required',
'publisher_id' => 'required',
'year' => 'required',
'title' => 'required',
'price' => 'required',
]);
try {
$book = Book::create($request->all());
foreach ($request->checked as $value){
$book->warehouses()->attach([$value]);
}
return redirect()->route('books.index')
->with('success','Book created successfully.');
} catch (\Illuminate\Database\QueryException $e) {
var_dump($e->errorInfo);
}
}
And saves the many-to-many relational data upon storing.
Thank you very much for the help Dennis :-)
Related
Good day
am new to laravel and am working on a sports project. i have created teams and managers of the team. i would like each manager to register players to his specific team eg a Chelsea manager who registers his players to Chelsea club/team. if possible how can i also register through csv file in case we have a lot of players or squad
below are my controllers and models
`
this is my players model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Player extends Model
{
use HasFactory;
protected $table = 'players';
protected $primaryKey = 'id';
protected $fillable = ['user_id', 'team_id'];
public function team()
{
return $this->belongsTo(Team::class, 'team_id');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
}
below is my controller for the players for creating the players
public function store(Request $request)
{
$request->validate([
'name' => 'required',
'email' => 'required',
'password' => 'required'
]);
$name = $request->name;
$email = $request->email;
$password = bcrypt($request->password);
$teamID = $request->team_id;
$role_id = '2';
$createdUser = User::create([
'name' => $name,
'email' => $email,
'password' => $password,
'role_id' => $role_id
]);
Player::create([
'user_id' => $createdUser->id,
'team_id' => $teamID
]);
return redirect()->route('player.index');
}
`
Im building CRUD for my application in Laravel 9. I defined some fields in my database as NOT NULL. Those values will be completed by code at the time a new user is created.
The first field Im dealing with is 'creado' (same as 'created at' in english) field (and I dont want to use built in timestamp)
User model:
public $timestamps = false;
protected $fillable = [
'username',
'password',
'apellidos',
'nombres',
'tipoDocumento',
'nroDocumento',
'cuit',
'cuil',
'fechaNacimiento',
'sexo',
'domicilio',
'domicilioNro',
'domicilioPiso',
'domicilioDepto',
'localidad',
'codigoPostal',
'telefonoFijo',
'telefonoCelular',
'telefonoAlt',
'email',
'creado', //This is the value
];
protected $hidden = [
'password',
'password_repeat', //This value is still being displayed in error msg...
'remember_token',
];
protected $casts = [
'creado' => 'datetime', //Dont think its necessary
];
public function setPasswordAttribute($password)
{
$this->attributes['password'] = bcrypt($password);
}
public function setCreadoAttribute()
{
//This method never get called...
$this->attributes['creado'] = date("Y-m-d H:i:s");
}
RegisterRequest:
public function rules()
{
return [
'username' => 'required|unique:clientes,username',
'password' => 'required|min:8',
'password_repeat' => 'required|same:password',
'apellidos' => 'required',
'nombres' => 'required',
'fechaNacimiento' => 'required',
'sexo' => 'required',
'tipoDocumento' => 'required',
'nroDocumento' => 'required|unique:clientes,nroDocumento',
'cuil' => 'nullable|min:11|max:11',
'cuit' => 'nullable|min:11|max:11',
'domicilio' => 'required',
'domicilioNro' => 'required',
'localidad' => 'required',
'codigoPostal' => 'required',
'telefonoCelular' => 'required',
'email' => 'required|unique:clientes,email',
'creado' => 'nullable|date',
];
}
Controller:
public function register(RegisterRequest $request)
{
$cliente = Clientes::create($request->validated());
return redirect("login")->with("success","Bla Bla Bla");
}
In view, all fields are present, except 'creado'. If I add input type text named creado, it works. Else the field its not included in the query. I dont know why its not working when I marked it as nullable.
$casts array and setCreado can be removed.
Then, you can use an accessor, in your model:
protected function creado(): Attribute
{
return Attribute::make(
get: fn ($value) => date("Y-m-d H:i:s"),
);
}
Mas info ;) Accessors
Importante this:
This method name should correspond to the "camel case" representation of the true underlying model attribute / database column when applicable.
Finally, I was able to fix this using this approach:
In ClientsController
public function register(RegisterRequest $request)
{
$cliente = new Cliente;
$cliente = Cliente::make($request->validated());
$cliente->setCreadoAttribute();
$cliente->save();
return redirect("login")->with("success","Cuenta creada exitosamente");
}
In Client model:
public function setCreadoAttribute()
{
$this->attributes['creado'] = date("Y-m-d H:i:s");
}
Im not really sure if this is the best way or the best practice to accomplish what I was needing, but for now it works.
From the docs
If you need to customize the names of the columns used to store the timestamps, you may define CREATED_AT and UPDATED_AT constants on your model:
<?php
class Flight extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'updated_date';
}
This is my Item model. I have made a function arrayPackageItemSelect that gets the id and equivalent it to the item name.
class Item extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'name',
'price',
'itemdescription',
'activeInactive'
];
public function packageitems()
{
return $this->hasMany(PackageItem::class);
}
public static function arrayPackageItemSelect()
{
$arr = [];
$items = Item::all();
foreach($items as $item){
$arr[$item->id] = $item->name;
}
return $arr;
}
}
my PackageItem Model
class PackageItem extends Model
{
protected $fillable = [
'user_id',
'item_id',
'price'
];
protected $table='packageitems';
public static function itemModel()
{
return $this->belongsTo(Item::class);
}
}
my PackageItem Controller (CREATE) and getting the Item ID from another table (Foreign key) so I can put a category for it.
public function addPackageItem(Request $request)
{
$user = Auth::user();
$item = Item::arrayPackageItemSelect();
echo $item; // when I echo this I get Array to Conversion String in POSTMAN
$fields = $request->validate([
'user_id' => 'required',
'item_id' => 'required',
'price' => 'required|numeric'
]);
// // echo $items;
$package = PackageItem::create([
'user_id' => $user->id,
'item_id' => $item,
'price'=> $fields['price']
]);
return response($package, 201);
}
What I get when I echo the Items
The results I get from POSTMAN
My Schema
This is where my reference is https://www.artofcse.com/learning/product-view-insert-update-delete
Can anybody help me what is wrong?
In your controller (addPackageItem method):
$package = PackageItem::create([
'user_id' => $user->id,
'item_id' => $fields['item_id'],
'price'=> $fields['price']
]);
Also, i think there is an error in your PackageItem model. belongsTo should not be called in a static method :
public function itemModel()
{
return $this->belongsTo(Item::class);
}
I am currently doing this as title says like this:
$user = User::where('username', request('username'))->first();
$posts = [];
$comments = [];
foreach($user->posts as $post){
foreach($post->comments as $comment){
array_push($comments, [
'id' => $comment->id,
'body' => $comment->body,
'user' => $comment->user->only(['name', 'id']),
]);
}
array_push($posts, [
'title' => $post->title,
'id' => $post->id,
'body' => $post->body,
'comments' => $comments,
]);
}
return response()->json([
'user' => $user->only(['name', 'avatar', 'age']),
'posts' => $posts,
]);
Is there a shorter way of doing this like:
$user->only(['name', 'avatar', 'age'])->withPostsOnly(['id', 'title', 'body'])->withCommentsOnly(['id', 'body']);
I know there is a way to make methods inside models that return these parts of data and then to use it same as above but shorter.
But is there any way to use something like getNameAttribute($value) for relations so I can say:
$user->only(['id', 'name', 'age', 'posts']);
And in posts value I need to have all posts and relationship data like comments and users that are connected to comments.
So basically in User model:
public function posts() {
return $this->hasMany('App/Post')->only('id', 'title', 'body', 'comments');
}
And inside Post model:
public function comments() {
return $this->hasMany('App/Comment')->only('id', 'body', 'user');
}
And inside Comment model:
public function comments() {
return $this->belongsTo('App/User')->only('id', 'name');
}
Thanks
You are probably overcomplicating it to be honest.
$user = User::where('username', request('username'))->first();
$user->load(['posts.comments']);
return response()->json($user);
This is a simplified version maybe but still should indicate you can just load relationships on models.
I have the following tables for my many to many relationship: soldhomestests, tasks and soldhomestest_task (as the pivot).
My soldhomestests table has already been populated with data. How do I get my soldhomestest_task pivot table to populate with data upon the creation of a new task that meets conditions in my soldhomestest table? In my example, I want to store the relationship data when the following conditions are met:
'tasks.city' = 'soldhomestests.city'
'tasks.address' = 'soldhomestests.address'
I can't seem to find any documentation on how to proceed with this?
MODELS:
class Task extends Model
{
protected $fillable = [
'address', 'city', 'state',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function soldhomestests()
{
return $this->belongsToMany('App\Soldhomestest');
}
}
class Soldhomestest extends Model
{
public function tasks()
{
return $this->belongsToMany('App\Task');
}
}
CONTROLLER:
public function store(Request $request)
{
$this->validate($request, [
'address' => 'required|max:255',
'city' => 'required|max:255',
'state' => 'required|max:255',
]);
$request->user()->tasks()->create([
'address' => $request->address,
'city' => $request->city,
'state' => $request->state,
]);
return redirect()->route('settings.index');
}
Don't believe this is the Laravel way but I modified my controller to create an array of IDs using the where condition:
public function store(Request $request)
{
$this->validate($request, [
'address' => 'required|max:255',
'city' => 'required|max:255',
'state' => 'required|max:255',
]);
$newtask = $request->user()->tasks()->create([
'address' => $request->address,
'city' => $request->city,
'state' => $request->state,
]);
$condition = DB::table('soldhomestests')->where([
['soldhomestests.address', '=', $request->address],
['soldhomestests.city', '=', $request->city],
])->pluck('id');
$lastid = $newtask->id;
$tasksoldhome = Task::find($lastid);
$tasksoldhome->soldhomestests()->sync($condition);
return redirect()->route('settings.index');
}
Using eloquent, you can do this way.
$task=new Task();
$task->city=$request->city;
$task->address=$request->address;
$task->save();
$soldhometests=Soldhometest::all();
foreach($soldhometests as $soldhometest)
{
if($task->city==$soldhometest->city && $task->address==$soldhometest->address)
{
$soldhometest_task=new SoldhometestTask(); // pivot model
$soldhometest_task->task_id=$task->id;
$soldhometest_task->soldhometest_id=$soldhometest->id;
$soldhometest_task->save();
}
}