I have a new Laravel 9 application and I am trying to use Keycloak as an SSO.
I am using this package to achieve that. I created the migrations and the seeders to have some data. I am using my own user model extending the KeycloakUser provided by the package.
My seeder does not run and I get this error message:
Call to undefined method App\Models\User::create()
My Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Vizir\KeycloakWebGuard\Models\KeycloakUser;
class User extends KeycloakUser
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array<int, string>
*/
protected $fillable = [
'firstname',
'surname',
'email',
'role',
];
/**
* Get the company that owns the user.
*/
public function company()
{
return $this->belongsTo(Company::class);
}
/**
* Get the comments for the user.
*/
public function comments()
{
return $this->hasMany(Comment::class);
}
}
The 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('users', function (Blueprint $table) {
$table->id();
$table->string('firstname');
$table->string('surname');
$table->string('email')->unique();
$table->unsignedBigInteger('company_id')->nullable();
$table->enum('role', ['user', 'admin', 'superadmin'])->default('user');
$table->rememberToken();
$table->timestamps();
$table->foreign('company_id')->references('id')->on('companies');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('users');
}
};
The seeder
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
User::create([
'firstname' => 'Aaaa',
'surname' => 'Bbbb',
'email' => 'ab#first.com',
'role' => 'superadmin',
]);
}
}
What you can try to do is copy KeycloakUser into app\Models.
Rename the file and class to User and than add extends Model.
namespace Vizir\KeycloakWebGuard\Models;
use Auth;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
class User extends Model implements Authenticatable
{
....
// all of these methods are originated from KeycloakUser
And dont forget to adjust your config/auth.php
'providers' => [
'users' => [
'driver' => 'keycloak-users',
'model' => App\Models\User::class,
],
// ...
]
Related
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 = [];
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
I'm trying to create a migration to add tables and columns to my database and all I get is this error.
PHP Fatal error: Cannot declare class CreateJuegosTable, because the name is already in use in C:\xampp\htdocs\2020-21-DAW2-M12-Royal-Dice\database\migrations\2021_05_10_000000_create_juegos.php on line 7
this is the code I'm trying to run:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateJuegosTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('juegos', function (Blueprint $table) {
$table->id();
$table->string('juego');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('juegos');
}
}
This is the file names, I changed and the error still there
This is the model
<?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',
];
}
check migrations and rename if any exists with the name "Juegos". if refactor/rename does not work open the migration and rename directly.... then run below command to clear cache
php artisan optimize
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateJuegosTable---(rename this)---- extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('juegos'---(rename this)----, function (Blueprint $table) {
$table->id();
$table->string('juego');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('juegos'----(rename this)----);
}
}
Getting : "PHP Recoverable fatal error: Object of class Database\Factories\RoleFactory could not be converted to string in C:\Users\kk\Desktop\imageupload\iu\database\factories\RoleFactory.php on line 25"
when executing this :
Role::factory()->count(5)->make();
Role.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
use HasFactory;
public function users(){
return $this->belongsToMany('App\Models\user');
}
}
User.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 users(){
return $this->belongsToMany('App\Models\role');
}
}
RoleFactory.php
<?php
namespace Database\Factories;
use App\Models\Role;
use Illuminate\Database\Eloquent\Factories\Factory;
class RoleFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Role::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'name'=>$this->faker->JobTitle
];
}
}
UserFactory.php
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
/**
* Indicate that the model's email address should be unverified.
*
* #return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function unverified()
{
return $this->state(function (array $attributes) {
return [
'email_verified_at' => null,
];
});
}
}
Create_roles_table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRolesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('roles');
}
}
create_role_user_table
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRoleUserTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('role_user', function (Blueprint $table) {
$table->id();
$table->foreignId('role_id')->constrained()->onDelete('cascade');
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('role_user');
}
}
i want to ask about error "Too few arguments to function Illuminate\Database\Eloquent\Model::setAttribute(), 1 passed "
i try to register users, i use php artisan make:auth to build my authentication. But, i add one field in users migration. and i try to use uuid. this is my code :
User Model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Traits\Uuids;
class User extends Authenticatable
{
use Notifiable;
use Uuids;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $guarded = ['id'];
protected $table = 'users';
protected $fillable = [
'name', 'email', 'password','phone_number',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
Register Controller
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* #var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'phone' => 'required|numeric|min:8',
'password' => 'required|string|min:6|confirmed',
'password_confirmation' => 'required|same:password',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return \App\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'phone_number' => $data['phone'],
'password' => Hash::make($data['password']),
]);
}
}
Users Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->uuid('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->integer('phone_number');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
Uuids Trait
<?php
namespace App\Traits;
trait Uuids
{
/**
*
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->{$model->uuid} =
str_replace('-', '', \Uuid::generate(4)->string);
});
}
}
Please give me advice. Thank You.
I can't find any reference about property or magic property you wrote as below (like a method getUuidAttribute for example)
$model->{$model->uuid} = str_replace('-', '', \Uuid::generate(4)->string);
So, I assume above code would compiled as
$model->{null} = str_replace('-', '', \Uuid::generate(4)->string);
I guess you're looking for $model->id which has the type of database column as a uuid. But, obviously, you can't have a dynamic database column name as it is wrong at all. Example of dynamic column if your snippet is working properly
$model->'6b324d55-433c-455a-88b6-feb2ee6c3709' = 'c3bec822-e5ee-4d91-b1a3-f5f552fd004a';
Something isn't right, right? It would be better if it look like this.
$model->id = 'c3bec822-e5ee-4d91-b1a3-f5f552fd004a';
And of course, make your latest snippet be something as follow
<?php
namespace App\Traits;
trait Uuids {
// to make model run this 'boot' method, append it with your trait name
protected static function bootUuids() { // <-- bootUuids
// parent::boot();
static::creating(function ($model) {
$model->id = str_replace('-', '', \Uuid::generate(4)->string);
});
}
}
Assuming your tables use UUID for primary key
$table->uuid('id')->primary();
Review your trait by setting the value directly to the id
<?php
namespace App\Traits;
use Illuminate\Support\Str;
trait UsesUuid
{
protected static function bootUsesUuid()
{
static::creating(function ($model) {
if (! **$model->id**) {
**$model->id** = (string) Str::uuid();
}
});
}
public function getIncrementing()
{
return false;
}
public function getKeyType()
{
return 'string';
}
}
Now use trait in your model
<?php
namespace App\Models;
use App\Traits\UsesUuid;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Group extends Model
{
use HasFactory;
**use UsesUuid;**
The full post is here
Create good solutions out there guys :)