Relation one to many it doesn't work - php

https://imgur.com/a/ob9rjIz
There are two tables one called user and another called user_relation_user
My relation is an user to many user_relation_user and in my migration. I want to create 10 user with php artisan tinker so i run factory(App\User::class, 10)->create(); at the end i access to my database so do select * from users there are 10 users but in user_relation_user isn't 10 id or it's empty
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Administrator extends Model
{
protected $table = 'user_relation_user';
protected $primaryKey = 'id';
protected $fillable = ['user_id'];
public function users(){
return $this->belongsTo(User::class,'user_id');
}
}
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function administrator(){
return $this->hasMany(Administrator::class,'user_id');
}
}
//hasMany
My migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUserRelationUserTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('user_relation_user', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('user_id_admin')->unsigned();
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*foreign
* #return void
*/
public function down()
{
Schema::dropIfExists('user_relation_user');
}
}

The relation you define is correct,you just need to define a relation in user model as well.
Example:
Suppose you are developing a blog system where user can post blogs.
then there will be two models user model and blog model
In User model you have to define user relation as below:
public function blogs()
{
return $this->hasmany(Blog::class);
}
Then in blogs model
public function users()
{
return $this->belongsTo(User::class);
}

Related

How can if fix this Laravel one to many with a custom foreign key behavior

I'm new to laravel and trying to make two tables with a one (customer) to many(table) relation and a custom Foreign Key tables.customer(I can not change this)
The connection is over customers.id on tables.customer.
After Running php artisan migrate:fresh --seed everything is created as expected. But tables.customer is always 0.
I don't get any errors. And both tables are created correctly.
What do I miss?
Here are my settings:
Models:
Customers.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Customers extends Model {
use HasFactory;
public function tables() {
return $this->hasMany(Tables::class, 'customer');
}
public $timestamps = false;
}
Tables.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tables extends Model {
use HasFactory;
public function customers() {
return $this->belongsTo(Customers::class, 'customer');
}
public $timestamps = false;
}
Migration:
customers
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up() {
Schema::create('customers', function (Blueprint $table) {
$table->string('id', 6)->primary();
$table
->string('img', 23)
->nullable()
->default(null);
$table->tinyText('name');
$table->tinyInteger('active')->default(1);
$table->bigInteger('created'); // unix timestamp when created
$table
->bigInteger('status')
->nullable()
->default(null); // null not deleted / unix timestamp when deleted
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down() {
Schema::dropIfExists('customers');
}
};
tables
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up() {
Schema::create('tables', function (Blueprint $table) {
$table->string('id', 8)->primary();
$table->tinyText('number');
$table->string('customer', 6); // TODO: repalce with uuid
$table->bigInteger('created'); // unix timestamp when created
$table
->bigInteger('status')
->nullable()
->default(null); // null not deleted / unix timestamp when deleted
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down() {
Schema::dropIfExists('tables');
}
};
Factories:
CustomersFactory.php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* #extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Customers>
*/
class CustomersFactory extends Factory {
/**
* Define the model's default state.
*
* #return array<string, mixed>
*/
public function definition() {
return [
'id' => $this->faker->unique()->regexify('[A-Za-z0-9]{6}'),
'name' => $this->faker->company(),
'active' => $this->faker->boolean(),
'created' => $this->faker->unixTime(),
'status' => $this->faker->boolean() ? null : $this->faker->unixTime(),
];
}
}
TablesFactory.php
namespace Database\Factories;
use App\Models\Customers;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* #extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Tables>
*/
class TablesFactory extends Factory {
/**
* Define the model's default state.
*
* #return array<string, mixed>
*/
public function definition() {
return [
'id' => $this->faker->unique()->regexify('[A-Za-z0-9]{8}'),
'number' => $this->faker->unique()->numberBetween(1, 1000),
'customer' => Customers::factory()->create()->id,
'created' => $this->faker->unixTime(),
'status' => $this->faker->boolean() ? null : $this->faker->unixTime(),
];
}
}
Seeders:
customersSeeder.php
namespace Database\Seeders;
use App\Models\Customers;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class CustomersSeeder extends Seeder {
/**
* Run the database seeds.
*
* #return void
*/
public function run() {
Customers::factory()
->count(10)
->hasTables(20)
->create();
}
}
TablesSeeder.php
namespace Database\Seeders;
use App\Models\Tables;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class TablesSeeder extends Seeder {
/**
* Run the database seeds.
*
* #return void
*/
public function run() {
//
}
}
DatabaseSeeder.php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder {
/**
* Seed the application's database.
*
* #return void
*/
public function run() {
$this->call([CustomersSeeder::class]);
}
}
Your issue is that you did not tell each model that the id is not an integer, it is by default (check the source code).
So add this to both models:
protected $keyType = 'string';
public $incrementing = false;
Read about that here.
By inspecting your models, you are recommended to define the table name first.
// ========== SPECIFY TABLE TO USE (https://stackoverflow.com/a/51746287/19250775) ========== //
protected $table = "users";
And then you need to define fillable properties in order to mass assign your database, as the docs said.
// ========== MASS ASSIGNABLE ATTRIBUTES ========== //
protected $fillable =
[
'id',
'name',
'email',
];
Or if you want every column becomes fillable just add guarded attribute.
protected $guarded = [];

Laravel model create() and fill() methods doesn't work

I have the following model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
protected $fillable = ['*'];
public $dates = ['page_available_untill'];
public static function findByUUID(string $uuid): self|null
{
return self::where('page_uuid', $uuid)->get()->first();
}
}
Model seeder:
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run()
{
Review::create([
'page_uuid' => ReviewUUIDGenerator::generate(),
'order_id' => 10000
]);
}
}
Migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateReviewsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('reviews', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->integer('order_id');
$table->string('page_uuid');
$table->dateTime('page_available_untill')->nullable();
$table->integer('operator_speed')->nullable();
$table->integer('operator_quality')->nullable();
$table->integer('operator_politeness')->nullable();
$table->integer('master_arrival_speed')->nullable();
$table->integer('master_work_quality')->nullable();
$table->integer('master_politeness')->nullable();
$table->enum('materials_quality', ['Хорошее', 'Плохое', 'Не устанавливали'])->nullable();
$table->enum('would_recommend', ['Да', 'Нет', 'Затрудняюсь ответить'])->nullable();
$table->double('payment_summ', 9, 2)->nullable();
$table->text('comment')->nullable();
$table->json('photos')->default(json_encode([]));
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('reviews');
}
}
Basically the model stores a review info for a given job (let's say for example my job is to help people make some documents and after my job is done i ask my clients to submit a review to my job)
The problem is:
when i set $fillable = ['*']; i can access model attributes like an object properties, BUT i cant create a new model or fill model with some model attributes if i don't hard code needed properties to $fillable like $fillable = ['page_available_untill', 'order_id', 'etc'] is that how it acually works or i don't understand something?
protected $guarded = [];
Replace protected $fillable = ['*']; by protected $guarded = [];
protected $fillable = ['*'];
this please enter column name in fillable, for example
protected $fillable = ['page_uuid','order_id'];
Add column name in fillable and let me know if its working or not
In eloquent ORM, $fillable attribute is an array containing all those fields of table which can be filled using mass-assignment.
Mass assignment refers to sending an array to the model to directly create a new record in Database.
Refer this
https://laravel.com/docs/9.x/eloquent#mass-assignment
You can't use * in fillable method. You have to add all needed column in the fillable.

SQLSTATE[42P01]: Undefined table: 7

I'm newbiу in laravel 9. I just want create simple blog with the tables:users, stories,comments.I have next relationship
users->stories(One To Many, hasMany laravel) ,
stories->users(One To Many (Inverse) / Belongs To),
users->comments(One To Many, hasMany laravel) ,
comments->users(One To Many (Inverse) / Belongs To),
stories->comments(One To Many, hasMany laravel) ,
comments->stories(One To Many (Inverse) / Belongs To).
class User
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use App\Models\Story;
use App\Models\Comment;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* #var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* #var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function stories()
{
return $this->hasMany(Story::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
}
class Story:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Model\User;
use App\Model\Comment;
class Story extends Model
{
use HasFactory;
protected $fillable = ['description', 'textStory'];
public function user()
{
return $this->belongsTo(User::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
}
class Comment:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Story;
use App\Models\User;
class Comment extends Model
{
use HasFactory;
public function storyFunction()
{
return $this->belongsTo(Story::class);
}
public function userFunction()
{
return $this->belongsTo(User::class);
}
}
Stories migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('stories', function (Blueprint $table) {
$table->id();
$table->string('description');
$table->text('textStory');
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('stories');
}
};
Comments migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->text('textComment');
//$table->foreignId('story_id')->constrained('stories')->onDelete('cascade');
/*$table->foreign('story_id')
->references('id')->on('stories')
->onDelete('cascade');*/
$table->timestamps();
});
Schema::table('comments', function(Blueprint $table) {
$table->foreignId('user_id')->constrained()->onDelete('cascade');
});
Schema::table('comments', function(Blueprint $table) {
$table->foreignId('story_id')->constrained()->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('comments');
}
};
But when i run php artisan migrate or php artisan migrate:refresh i see next error:
SQLSTATE[42P01]: Undefined table: 7 ?z?????С?s??: ??NВ????N??╡?????╡ "stories
" ???╡ N?N?NЙ?╡N?NВ??N??╡NВ (SQL: alter table "comments" add constraint "comment
s_story_id_foreign" foreign key ("story_id") references "stories" ("id") on dele
te cascade)
But if i delete or comment next strings in comments migration file:
Schema::table('comments', function(Blueprint $table) {
$table->foreignId('story_id')->constrained()->onDelete('cascade');
});
Migration run succesfull.
Please help me resolve this error.
Most likely, the table that Laravel finds using the conventions is missing. Specify the table explicitly as an argument to the constrained method like this Schema::table('comments', function(Blueprint $table) {
$table->foreignId('story_id')->constrained('Your_table_name')->onDelete('cascade');
});Foreign Key Constraints

Get data from hasMany/belongsTo laravel elequent relations

I have two models products and image where product can have one or more image and image have one product related to and these are my models
product model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use OwenIt\Auditing\Contracts\Auditable;
use OwenIt\Auditing\Auditable as AuditableTrait;
class Product extends Model implements Auditable
{
use HasFactory, AuditableTrait;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'price',
'description'
];
/**
* Get all of the comments for the Product
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function images(): HasMany
{
return $this->hasMany(Image::class);
}
}
product migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProductsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->double('price');
$table->text('description');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('products');
}
}
image model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Image extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'filename',
];
/**
* Get the user that owns the Image
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function product(): BelongsTo
{
return $this->belongsTo(Product::class);
}
}
image migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateImagesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->id();
$table->string('filename');
$table->bigInteger('product_id')->unsigned();
$table->timestamps();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('images');
}
}
i made a productController to manage data, but i don't get the full response i only get each table data not with the relation included in the response
I am using laravel 8x
edits
productController php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return Product::with('images')->get();
}
}
In Product model:
public function image()
{
return $this->hasOne(Image::class, 'pro_id');
}
In Image model:
public function product()
{
return $this->belongsTo(product::class, 'pro_id');
}
In controller:
$img = product::find($id)->image->filename;
Make sure there is a record for the product in the image table. Otherwise you have to manage the errors.

ErrorException Trying to get property 'User' of non-object ( laravel )

I am getting the error:
ErrorException Trying to get property 'User' of non-object
from the statements below which don't seem to work:
$user = Mobile::find(3)->User;
dd($user);
rest of the code is as follows:
usercontroller.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Mobile;
use Hash;
class UserController extends Controller
{
public function addUserMobile()
{
$user = new User;
$user->name = "Test Name";
$user->email = "test#mnp.com";
$user->password = Hash::make("12345678");
$user->save();
$mobile = new Mobile;
$mobile->mobile = '123456789';
$user->mobile()->save($mobile);
}
public function index()
{
// get user and mobile data from User model
$user = User::find(3);
// var_dump($user->name);
// var_dump($user->mobile->mobile);
// // get user data from Mobile model
$user = Mobile::find(3)->User;
dd($user);
// // get mobile number from User model
// $mobile = User::find(3)->mobile;
// dd($mobile);
}
}
mobile.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function mobile()
{
return $this->hasOne(Mobile::class);
// note: we can also inlcude Mobile model like: 'App\Mobile'
}
}
mobile table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateMobilesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('mobiles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->string('mobile');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('mobiles');
}
}
mobile database
user database
"3" is user_id btw.
The problem is you are querying the Mobile with id 3 (which does not exist) and then calling the user relation.
$user = Mobile::find(3)->user;
Since Mobile::find with an id that doesn't exist returns null, you are calling ->user on null, and you will get the error you mentioned.
Also, you should add a belongsTo relation in your Mobile model:
public function user()
{
return $this->belongsTo(User::class);
}
Now, after fixing your query to use user_id, you can do:
$user = Mobile::where('user_id', 3)->first()->user;

Categories