I'm working on a Laravel 9 project. I'm new to Polymorphic relationships and believe I need to define one.
In my application, I have a parent model called Application that has a single ApplicationGBPayday model, but it could have other models in the future for different products/countries.
I've defined my Application model schema to contain a modelable morph fieldset, and in my controller where I create an Application I then need to create and link the ApplicationGBPayday, but I'm getting an error right now:
Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1364 Field 'modelable_type' doesn't have a default value
My controller I'm doing:
// create application
$application = Application::create([
'user_id' => $affiliate->user_id,
'company_id' => $affiliate->company_id,
'country_id' => $affiliate->affiliate_product->country->id,
'product_id' => $affiliate->affiliate_product->product->id,
'serve_method_id' => $affiliate->affiliate_product->serve_method->id,
'application_form_id' => $affiliate->affiliate_product->application_form->id,
'pingtree_group_id' => $affiliate->affiliate_product->pingtree_group->id,
'affiliate_id' => $affiliate->id,
'thread_uuid' => $threadUUID,
'status' => 'pending',
'submitted_at' => $submittedAt
]);
$payday = ApplicationGBPayday::create($request->all());
And here's my model for Application:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Casts\Json;
class Application extends Model
{
use HasFactory, SoftDeletes;
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'applications';
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = [];
/**
* The attributes that should be cast.
*
* #var array<string, string>
*/
protected $casts = [
'submitted_at' => 'datetime',
];
/**
* Get the parent modelable model.
*/
public function modelable()
{
return $this->morphTo();
}
}
And ApplicationGBPayday:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Casts\Json;
class ApplicationGBPayday extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'application_gb_paydays';
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = [];
/**
* The attributes that should be cast.
*
* #var array<string, string>
*/
protected $casts = [
'buyer_list' => Json::class,
'buyer_list_pending' => Json::class,
'buyer_list_accepted' => Json::class,
'buyer_list_declined' => Json::class,
'buyer_list_invalid' => Json::class,
'buyer_list_skipped' => Json::class,
'other_data_json' => Json::class,
'response_json' => Json::class,
];
/**
* Get the model's application
*/
public function application()
{
return $this->morphOne(Application::class, 'modelable');
}
}
I'm struggling to figure out how to save the morph fields since they can't be null here, yet I need the application created first and then the payday? What am I missing?
UPDATE
I've tried:
// create application
$application = Application::create([
'user_id' => $affiliate->user_id,
'company_id' => $affiliate->company_id,
'country_id' => $affiliate->affiliate_product->country->id,
'product_id' => $affiliate->affiliate_product->product->id,
'serve_method_id' => $affiliate->affiliate_product->serve_method->id,
'application_form_id' => $affiliate->affiliate_product->application_form->id,
'pingtree_group_id' => $affiliate->affiliate_product->pingtree_group->id,
'affiliate_id' => $affiliate->id,
'thread_uuid' => $threadUUID,
'status' => 'pending',
'submitted_at' => $submittedAt
]);
$payday = new ApplicationGBPayday($request->all());
$application->modelable()->save($payday);
Which gives me:
Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1364 Field 'modelable_type' doesn't have a default value (SQL: insert into applications
Related
I have created a seeder that populates data in Laravel but was having a BadMethodCallException Call to undefined method App\Models\Project::factory(). Why is this happening? Below is my seeder code.
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\{
Project, User
};
class ProjectSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Project::factory()->count(10)->create();
foreach(Project::all() as $project) {
$users = User::inRandomOrder()->take(rand(1, 3))->pluck('id');
$project->users()->attach($users);
}
}
}
First check the project factory class inside path
database/factories/ProjectFactory.php
If it not exist create it
<?php
namespace Database\Factories;
use App\Models\Project;
use Illuminate\Database\Eloquent\Factories\Factory;
class ProjectFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Project::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
//add your custom seeder data
return [
"project_tittle" => $this->faker->catchPhrase,
"client_name" => $this->faker->name(),
"days" => rand(45, 60),
"description" => $this->faker->text,
"start_date" => $this->faker->date('Y-m-d'),
"end_date" => $this->faker->date('Y-m-d'),
"current_status" => 1,
"completion_percentage" => 0
];
}
}
If your are using different namespace on model you need to add model like this in your factoryclass
protected $model = Project::class;
I hope it works for you
I've solved it temporarily by using DB facade instead of a factory.
use Illuminate\Support\Facades\DB;
DB::table('projects')->insert([
'name' => Str::random(10),
'created_at' => now(),
'updated_at' => now(),
]);
I am working on a Laravel 8 app with users and posts.
The objective is to create a bunch of posts (I already have users).
namespace Database\Factories;
// import Post model
use App\Models\Post;
// import User model
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory {
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Post::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition() {
return [
'title' => $this->faker->sentence(3),
'description' => $this->faker->text,
'content' => $this->faker->paragraph,
'user_id' => $this->faker->factory(App\Models\User::class),
];
}
}
The problem
I run php artisan tinker then Post::factory()->count(100)->create() in the terminal and I get:
InvalidArgumentException with message 'Unknown format "factory"'
UPDATE
I replace my return statement with:
return [
'title' => $this->faker->sentence(3),
'description' => $this->faker->text,
'content' => $this->faker->paragraph,
'user_id' => User::factory(),
];
I get this in the terminal:
Class 'Database\Factories\UserFactory' not found
Questions:
Where is my mistake?
Does the fact that I get the error Class 'Database\Factories\UserFactory' not found mean that I need to
create a UserFactory factory? Because there isn't one. (I wanted
to create posts, not users).
I don't suppose there is $this->faker->factory(..).
You can do
'user_id' => App\Models\User::factory()->create()->id,
EDIT:
'user_id' => App\Models\User::factory(),
Creating a UserFactory factory and using the below return statement did the trick:
return [
'title' => $this->faker->sentence(3),
'description' => $this->faker->text,
'content' => $this->faker->paragraph,
'user_id' => User::factory(),
];
So, the PostFactory class looks like this:
class PostFactory extends Factory {
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Post::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition() {
return [
'title' => $this->faker->sentence(3),
'description' => $this->faker->text,
'content' => $this->faker->paragraph,
'user_id' => User::factory(),
];
}
}
I have a problem with inserting rows in Laravel.
Theory: I use simple Laravel authentication and have two tables.
users: id, name, password.
user_details: id, userID, email
After the registration it would be useful to insert rows into both tables, and the userID = id (in users table).
RegisterController.php
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
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|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'e_r' => $data['e_r'],
]);
$details = UserDetails::create([
'firstname' => 'joco',
'lastname' => 'nagy',
'email' =>$data['email'],
'position' => 'cleaner',
'salary' => '250000',
'amount_holiday' => '40'
]);
return $user;
}
}
(I have just tried to insert fake datas. There are default values in migration files.)
Models:
User.php
<?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', 'e_r',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function user_detail(){
return $this->hasOne("App\UserDetails");
}
}
Error:
FatalThrowableError in RegisterController.php line 74: Class
'App\Http\Controllers\Auth\UserDetails' not found
I do not understand why should be my model in Auth directory.
Have you include your model UserDetails?
Include it on top:
use App\User;
use App\UserDetails;
or
Change UserDetails to App\UserDetails.
$details = App\UserDetails::create([
'firstname' => 'joco',
'lastname' => 'nagy',
'email' =>$data['email'],
'position' => 'cleaner',
'salary' => '250000',
'amount_holiday' => '40'
]);
You should use use statement eg. use Your\Name\Space\UserDetails;
Without this declaration PHP is looking for UserDetails class in your current namespace, in your case App\Http\Controllers\Auth. That's why you get
'App\Http\Controllers\Auth\UserDetails' not found
I have 2 tables: options and optionselections.
Here are the models:
use LaravelBook\Ardent\Ardent;
class Option extends Ardent
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'options';
// MASS ASSIGNMENT -------------------------------------------------------
// define which attributes are mass assignable (for security)
// we only want these 1 attribute able to be filled
protected $fillable = array('name');
public function selections()
{
return $this->hasMany('optionselection');
}
}
use LaravelBook\Ardent\Ardent;
class Optionselection extends Ardent
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'option_selections';
// MASS ASSIGNMENT -------------------------------------------------------
// define which attributes are mass assignable (for security)
// we only want these 1 attribute able to be filled
protected $fillable = array('option_id', 'name');
public function choice()
{
$this->belongsTo('option');
}
}
I'm trying to create the relationship in Laravel administrator like I've done so many times before, and I can't see why I'm getting the error: The 'choice' relationship field you supplied for optionselections is not a valid relationship method name on the supplied Eloquent model
return array(
/**
* Model title
*
* #type string
*/
'title' => 'Option Selections',
/**
* The singular name of your model
*
* #type string
*/
'single' => 'Option Selection',
/**
* The class name of the Eloquent model that this config represents
*
* #type string
*/
'model' => 'optionselection',
/**
* The columns array
*
* #type array
*/
'columns' => array(
'choice' => array(
'title' => 'Option',
'relationship' => 'choice',
'select' => 'name',
),
'selection' => array(
'title' => 'Selection'
),
),
'edit_fields' => array(
'choice' => array(
'title' => 'Option',
'type' => 'relationship',
'name_field' => 'name',
),
'name' => array(
'title' => 'Selection Name',
'limit' => 30,
),
),
'action_permissions'=> array(
),
)
I know that the method/relationship field actually does exist and is recognized outside of Laravel Administrator, because this works:
$optsel = new Optionselection();
// var_dump($svcloc);
if (method_exists($optsel, "choice")) {
echo '<br/>Recognizes!';
} else {
echo '<br/>Problem!';
}
Why I'm getting the error?
Missing the return inside the relationship method. Closed
I'm using zizaco/confide in combination with cviebrock/eloquent-sluggable.
eloquent-sluggable uses Events::listen('eloquent.saving*') for generating the slug while/before saving.
// Cviebrock\EloquentSluggable\SluggableServiceProvider:55
public function registerEvents()
{
$app = $this->app;
$app['events']->listen('eloquent.saving*', function($model) use ($app)
{
$app['sluggable']->make($model);
});
}
Since I switched to Confide for authentication the slugs are not getting generated.
My user model is simply class User extends ConfideUser. Switching to class User extends Ardent or User extends Eloquent the event eloquent.saving is getting triggered fine.
I'm not shure if this is a bug or I'm missing something.
My Model:
<?php
use Illuminate\Database\Eloquent\Model;
use Zizaco\Confide\ConfideUser;
class User extends ConfideUser
{
public $autoPurgeRedundantAttributes = true;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* Soft delete
*
* #var boolean
*/
protected $softDelete = true;
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password');
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = array(
'nickname',
'password',
'email',
'deleted_at',
'disabled',
'firstname',
'lastname',
'birthday',
// needed by ardent
'email_confirmation',
'password_confirmation'
);
public static $rules = array(
'firstname' => 'required',
'email' => 'required|email|confirmed|unique:users',
'email_confirmation' => 'required',
'nickname' => 'required|min:2|unique:users',
'birthday' => 'date:d.m.Y|before:now',
'password' => 'required|min:5|confirmed',
'password_confirmation' => 'required'
);
public $imageSizes = array(
array(64, 64),
array(250, 250)
);
public static $sluggable = array(
'build_from' => 'nickname',
'save_to' => 'slug',
);
/**
* Roles
*
* #return object
*/
public function roles()
{
return $this->belongsToMany(
'Role',
'role_user'
)
->withTimestamps();;
}
}
Seems to me like this one is a bug: https://github.com/Zizaco/confide/issues/179
As a temporary workaround you can wrap the beforeSave() method in your Model without returning anything (!):
public function beforeSave($forced = false)
{
parent::beforeSave($forced);
}