Get incorrect table when tried to insert - laravel

I have a bizarre problem with my insert. So my migration is :
class CreatePhotoCategoryTable extends Migration {
public function up()
{
Schema::create('photo_category',function($table){
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::drop('photo_category');
}
}
My Model :
class PhotoCategory extends Eloquent {
protected $fillable = array('name');
public static $rules = array(
'name' => 'required',
);
}
And my controller:
class PhotoCategory extends BaseController{
public function getAddPage(){
return View::make('admin.photo_category.addPhotoCategory');
}
public function postCreate(){
$validator = Validator::make(Input::all(), \PhotoCategory::$rules);
if($validator->passes()){
$oPhotoCategory = new \PhotoCategory();
$oPhotoCategory->name = Input::get('name');
$oPhotoCategory->save();
$iLastId = $oPhotoCategory->id;
return Redirect::to('/administration/category_photo/edit/'.$iLastId)
->with('message_succes','Succes');
}
return Redirect::to('/administration/category_photo/add')
->with('message_error','Error')
->withErrors($validator)
->withInput();
}
Evident my table in database is called photo_category but when I tried to save into this table I get en sql error :
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'photo_categories' doesn't exist. So why my save() method get table photo_categories instead of photo_category. Please help me.

The naming convention for database tables in Laravel is plural. So Laravel assumes from your model name PhotoCategory that your table is called photo_categories. You have two options:
Change the name of your table to photo_categories
Specify the table name in your model by adding:
protected $table = 'photo_category';

Make sure you name your controllers with different names from your models, as this might bring you some issues since both are classes and both have the same name.
And also your Model class represents your database table so you need to specify your table name as
protected $table = 'photo_category';

Related

laravel 8 store request with foreign key user_id not working

I would like to store the corresponding logged in user when adding a new School data. What I'm trying to do is store the logged in user_id in the schools table, in order to know on who added the school data. I have a users table already, which will establish the relation in the schools table.
My goal is when an admin is logged in, he/she can see all of the School records, otherwise if it's a user, then only fetch the records he/she added. The problem is that I can't figure out on when and where to insert the user_id data during the store request as I'm getting an error "user id field is required". Here's what I've tried so far:
Migration:
class CreateSchoolsTable extends Migration
{
public function up()
{
Schema::create('schools', function (Blueprint $table) {
$table->id();
$table->string('school_name');
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
}
}
School Model:
class School extends Model
{
use HasFactory;
protected $fillable = ['school_name', 'user_id'];
public function User() {
return $this->belongsTo(User::class);
}
}
Store Request:
class StoreSchoolRequest extends FormRequest
{
public function rules(): array
{
return [
'school_name' => 'required|string|max:255',
'user_id' => 'required|exists:users,id'
];
}
}
Controller:
class SchoolController extends Controller
{
public function store(StoreSchoolRequest $request) {
$school_data = $request->validated();
$user_id = \Auth::user()->id;
$school_data['user_id'] = $user_id;
School::create($school_data );
return Redirect::route('schools.index');
}
}
Any inputs will be of big help! Thanks.
Laravel has elegant way to bind authenticated user_id. Remove user_id from request class and chaining method. Also setup relationship from User model to School Model
Form Request Class
class StoreSchoolRequest extends FormRequest
{
public function rules(): array
{
return [
'school_name' => 'required|string|max:255',
];
}
}
User Model
protected $fillable = ['school_name', 'user_id'];
...
// new line
public function schools() {
return $this->hasMany(School::class);
}
Your Controller
class SchoolController extends Controller
{
public function store(StoreSchoolRequest $request) {
auth()->user()->schools()->create($request->validated());
return Redirect::route('schools.index');
}
}
UPDATE ANSWER
Since user_id value is school name (based on image link from comment), probably there's something wrong either in User or School model. Here the quick fix
Your Controller
class SchoolController extends Controller
{
public function store(StoreSchoolRequest $request) {
auth()->user()->schools()->create(
array_merge(
$request->validated(),
['user_id' => auth()->id()]
)
);
return Redirect::route('schools.index');
}
}
You can add 'created_by' and 'updated_by' fields to your table. so you can register in these fields when additions or updates are made.
Then you can see who has added or updated from these fields.
class School extends Model
{
use HasFactory;
protected $fillable = ['school_name', 'user_id', 'created_by', 'updated_by'];
public function User() {
return $this->belongsTo(User::class);
}
}
Your controller part is correct but since you get the logged in user, you wont be having user_id in the request. So you should remove the rules about user_id from your StoreSchoolRequest.
class StoreSchoolRequest extends FormRequest
{
public function rules(): array
{
return [
'school_name' => 'required|string|max:255'
];
}
}
Problem is here ..
$school_data = $request->validated();
Since you are using $request->validated()..
You have to safe()->merge user_id into it , here Docs : .
$validated = $request->safe()->merge(['user_id' => Auth::user()->id]);
Then put this $validated into create query , Thanks. –

Property [countries] does not exist on this collection instance

I am trying to create a drop down menu by with eloquent from where I can go to subcontinent with drop down and subcontinent to countries with sub-dropdown. The relationship is Subcontinent has many countries.
Models
Subcontinent
class Subcontinent extends Model
{
protected $guarded = [];
public function countries()
{
return $this->hasMany(Division::class, 'country_name', 'id');
}
}
Country
class Division extends Model
{
protected $table = 'divisions';
protected $fillable = [
'country_name', 'subcontinent_id'
];
public function subcontinent()
{
return $this->belongsTo(Subcontinent::class, 'country_name', 'id');
}
}
The table name of country is divisions and the model name is also Division.
Table
country/division
Schema::create('divisions', function (Blueprint $table) {
$table->id();
$table->string('country_name');
$table->bigInteger('subcontinent_id');
$table->timestamps();
});
Database formation
$subcontinents = Subcontinent::orderBy('id', 'DESC')->get();
But when I try to call dd($subcontinents->countries) it gives me property does not exist error.
"Property [countries] does not exist on this collection instance."
with $subcontinents = Subcontinent::find(1);
the dd still gives null value. How can I call subcontinents to countries!
you have misconception about second and third option in relationship method. for belongsTo relationship, the second argument is the foreign key of the child table and the third argument is the primary key or the reference key of the parent table.
your Division model relationship should be
public function subcontinent()
{
return $this->belongsTo(Subcontinent::class, 'subcontinent_id', 'id');
}
and for hasMany relationship the second argument is the foreign key in the child table. For SubContinent model the relationship would be
public function countries()
{
return $this->hasMany(Division::class, 'subcontinent_id', 'id');
}
and when you use $subcontinents = Subcontinent::orderBy('id', 'DESC')->get(); you get a collection, not an object. you have to loop over to get values and relationship data from this.
foreach($subcontinents as $subcontinent) {
$subcontinent->$subcontinent_name;
$subcontinent->countries;
}
and when you use $subcontinents = Subcontinent::find(1); you get an object. you can directly access its values. just update the relationship method. and you will get values by $subcontinents->countries then.

Eloquent hasOne seems to be updating wrong table

I am getting an integrity constraint violation on an update to my users table when I am adding the current User to a Product. I am also using uuids instead of auto-incrementing so it adds another layer of complexity. I think I might be declaring the relationships wrong.
The error looks like it is trying to update the users table tryiSQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: users.uuid (SQL: update "users" set "uuid" = ?, "updated_at" = 2019-09-24 13:18:05 where "uuid" = 8ee98fac-11f7-5114-b9f1-772fe9732a49)
users table
uuid
User.php
public function products(){
return $this->hasMany('App\Product', 'user_uuid', 'uuid');
}
products table
uuid
user_uuid
Product.php
class Product extends Model
{
use SoftDeletes;
use uuidTrait;
protected $primaryKey = 'uuid';
public $incrementing = FALSE;
public function user(){
return $this->hasOne('App\User', 'uuid', 'user_uuid');
}
public static function boot(){
parent::boot();
static::creating(function(Product $instance){
$instance->user()->save(auth()->user());
});
}
}
You need the uuid of the current user
static::creating(function(Product $instance){
if(empty($instance->uuid)){
$instance->uuid = auth()->user()->user_uuid;
}
});
or you use the associate function
$product = new Product;
//...
$product->save();
$user = User::find(Auth::user()->id);
$user->associate($product);
$user->save();

How to properly implement this polymorphic relationship in Laravel?

I am trying to build an inventory for users in Laravel 5.8, however the items have their own properties, therefore I needed to set up a polymorphic relationship. When attaching items to users, it tries to add the model User to the table on itemable_type and the user's ID to itemable_id aswell as add the User's ID to user_id, something I could workaround by passing the models I need, but when I try to retrieve them it tries to find item with itemable_type = 'App\Models\User', which makes me think something's completely wrong here. Can I have some orientation on how to solve it?
class User extends Model
{
public function inventory()
{
return $this->morhpToMany(InventoryItem::class, 'itemable', 'user_inventories', null, 'itemable_id')
->withPivot('amount', 'notes');
}
}
class InventoryItem extends Model
{
public $timestamps = false;
protected $table = 'character_inventories';
protected $fillable = [
'character_id', 'itemable_type', 'amount', 'parent_id', 'notes'
];
public function cloth()
{
return $this->mophedByMany(Cloth::class, 'itemable');
}
public function food()
{
return $this->morphedByMany(Food::class, 'itemable');
}
// Other similar relations
}
// The Inventory migration:
Schema::create('user_inventories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->unsignedInteger('itemable_id');
$table->string('itemable_type');
$table->unsignedInteger('amount')->default(0);
$table->text('notes', 65535)->nullable();
$table->foreign('character_id')->references('id')->on('characters');
});
The expected result is the User model to have different items in his inventory, but the relation is trying to query by joinning to itself and filtering by user type instead of actual items.
The error:
Syntax error or access violation: 1066 Not unique table/alias: 'user_inventories' (SQL:
select `user_inventories`.*,
`user_inventories`.`itemable_id` as `pivot_itemable_id`,
`user_inventories`.`itemable_type` as `pivot_itemable_type`,
`user_inventories`.`amount` as `pivot_amount`,
`user_inventories`.`parent_id` as `pivot_parent_id`,
`user_inventories`.`notes` as `pivot_notes`
from `user_inventories`
inner join `user_inventories` on `user_inventories`.`id` = `user_inventories`.`itemable_id`
where `user_inventories`.`itemable_id` in (4)
and `user_inventories`.`itemable_type` = App\Models\User)
I highly suspect that you have to references the user table in the inventory relation. In general it is a million times easier just following the Laravel convention for naming.
public function inventory()
{
return $this->morhpToMany(InventoryItem::class, 'itemable', 'users', null, 'itemable_id')
->withPivot('amount', 'notes');
}

SQLSTATE[42S02]: Base table or view not found: 1146 error laravel

I have been trying to solve a problem for couple hours.
Basically I'm getting:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'tp-laravel.image_location' doesn't exist (SQL: select location_id from image_location where image_id = 3) error.
Is this coming from a bad controller/model/migration? This is happening when I try to add an image in my website.
I have been trying to change stuff, add stuff and look on google a lot, but nothing solved it.
Image.php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Image extends Model
{
protected $fillable = ['name'];
public function locations()
{
return $this->belongsToMany(Location::class);
}
public function getUpdatedAtAttribute($date)
{
return Carbon::parse($date)->locale('fr')->diffForHumans(Carbon::now());
}
}
Location.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
protected $fillable = ['name'];
public function locations()
{
return $this->belongsToMany(Image::class);
}
}
Here are the create and store methods from my controller:
public function create()
{
$locations = Location::pluck('name', 'id');
$users = User::pluck('name', 'id');
return view('posts.create', compact('locations'));
}
public function store(Request $request)
{
$image = Image::create(request()->all());
$image->locations()->sync(request()->get('locations'));
$user->users()->sync(request()->get('users'));
return redirect('/accueil');
}
And finally my image migration
Schema::create('images', function (Blueprint $table) {
$table->bigIncrements('id');
$table->BigInteger('location_id')->unsigned()->index();
$table->BigInteger('user_id')->unsigned()->index();
$table->foreign('location_id')->references('id')->on('locations')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('name', 100);
$table->timestamps();
});
When I press the create button in my view, the submit it's supposed to add the image in the database with user and location linked to it as a foreign key but the above error pops up.
Thanks!
The error is coming from
public function locations()
{
return $this->belongsToMany(Location::class);
}
Laravel assumes that you have intermediate table named alphabetically, for that is image_location and this table does not exist on your database.
The only way is to create such table, or if you have created the table with different name you can pass second parameter as table name. So it became:
public function locations()
{
return $this->belongsToMany(Location::class, 'TABLE_NAME');
}

Resources