Field doesn't have default value upon factory seeding against a one to many relationship - laravel

I have one speciality that can have many procedures.
I am wanting to seed both the speciality with many procedures.
Models:
Speciality
class Speciality extends Model
{
protected $fillable = ['name'];
public function procedures() {
return $this->hasMany('App\Procedure');
}
}
Procedure
class Procedure extends Model
{
protected $fillable = ['speciality_id', 'name'];
public function speciality() {
return $this->belongsTo('App\Speciality');
}
}
Factories:
Speciality
$factory->define(App\Speciality::class, function (Faker $faker) {
return [
'name' => 'Example'
];
});
Procedure
$factory->define(App\Procedure::class, function (Faker $faker) {
return [
'name' => $faker->realText(20)
];
});
Seeding:
public function run()
{
factory(App\Speciality::class)->create()
->each(function($speciality) {
$speciality->procedures()
->saveMany(factory(App\Procedure::class, rand(5,20))
->make()
);
});
}
The error shown is:
SQLSTATE[HY000]: General error: 1364 Field 'speciality_id' doesn't
have a default value (SQL: insert into procedures (name,
updated_at, created_at) values (It means much the., 2018-04-17
19:09:31, 2018-04-17 19:09:31))
speciality_id isn't set as a value within the procedure factory, because it's the foreign key to the speciality. But my understanding of using $speciality->procedures() is it would automatically assign the speciality_id upon seeding.
Why is this error happening please. Many thanks.

I may be wrong here but I think there is just a small issue of when you call make:
public function run()
{
factory(App\Speciality::class)->create()
->each(function($speciality) {
$speciality->procedures()
->saveMany(factory(App\Procedure::class, rand(5,20))->make());
});
}
Never used this with saveMany() before though, only save(), but try it out?

Related

use relationship in model accessor in laravel

Suppose I have a Course model like this :
class Course extends Model
{
public $primaryKey = 'course_id';
protected $appends = ['teacher_name'];
public function getTeacherNameAttribute ()
{
$this->attributes['teacher_name'] = $this->teacher()->first()->full_name;
}
public function teacher ()
{
return $this->belongsTo('App\User', 'teacher', 'user_id');
}
}
And in the other hand there is a User model like this :
class User extends Authenticatable
{
public $primaryKey = 'user_id';
protected $appends = ['full_name'];
public function getFullNameAttribute ()
{
return $this->name . ' ' . $this->family;
}
public function course ()
{
return $this->hasMany('App\Course', 'teacher', 'user_id');
}
}
As you can see there is a hasMany relationship between those.
There is an full_name accessor in User model.
Now I want to add a teacher_name accessor to Course model that uses it's teacher relations and gets full_name of teacher and appends to Course always.
In fact I want whenever call a Course model, it's related teacher name included like other properties.
But every time , when call a Course model , I got this error :
exception 'ErrorException' with message 'Trying to get property of non-object' in D:\wamp\www\lms-api\app\Course.php:166
That refers to this line of Course model :
$this->attributes['teacher_name'] = $this->teacher()->first()->full_name;
I do not know how can I solve that and what is problem exactly.
the right way to do this is:
COURSE
public function setTeacherNameAttribute ()
{
$this->attributes['teacher_name'] = $this->teacher->full_name;
}
$this->attributes['teacher_name'] = $this->teacher()->first()->full_name;
Should be
$this->attributes['teacher_name'] = $this->teacher->full_name;
First thing is that you want to reference the relationship, so loose the brackets (), and because the relationship is belongsTo, you will have one user / teacher returned. So you don't need the first().
We haven't seen your fields but probably you will have to change:
return $this->belongsTo('App\User', 'teacher', 'user_id');
to
return $this->belongsTo('App\User', 'foreign_key', 'other_key');
where foreign_key and other_key are the primary keys that you need to make the join on.
Check this link from the documentation for reference:
https://laravel.com/docs/5.4/eloquent-relationships#one-to-many-inverse

How to filter/select on intermediate (pivot) table columns in Laravel (5.4)

How do I create a column just in a pivot (intermediate) table in Laravel (5.4) and then filter results on it?
I have two models, Films and CastAndCrew. CastAndCrew are the various directors, producers, actors who work on a film. The pivot table should define the type of relationship between a CastAndCrew member and a Film. Obviously it's possible for someone to be e.g. an actor in one film and a producer on another, so I can't define this in their entry in the CastAndCrew table because it'll only be true for one film, and may be different for other films they worked on. So I assume I have to define the relationship in a pivot table, but I'm not sure how to do this exactly. What I've got so far:
class Film extends Model
{
protected $fillable = array('filmtitle', 'description');
public function List_Directors()
{
return $this->belongsToMany('App\CastAndCrew')->withPivot('type')->wherePivot('type', 'director');
}
public function List_Actors()
{
return $this->belongsToMany('App\CastAndCrew')->withPivot('type')->wherePivot('type', 'actor');
}
}
and
class CastAndCrew extends Model
{
protected $fillable = array('firstname', 'lastname');
public function List_Films_With_Director()
{
return $this->belongsToMany('App\Film')->withPivot('type')->wherePivot('type', 'director');
}
public function List_Films_With_Actor()
{
return $this->belongsToMany('App\Film')->withPivot('type')->wherePivot('type', 'actor');
}
}
When new CastAndCrew members get added to the site, I'm intending to use the attach method, e.g. to add a new director:
$newcastcrew->CastAndCrew::create(['firstname' => Request::get('firstname'), 'lastname' => Request::get('lastname')]);
$newcastcrew->List_Films_With_Director()->attach($filmID, ['type' => 'director']);
1.) Is that right?
2.) Does the ->withPivot('type') create the 'type' column in the Pivot table? If not, where/how do I define it?
2.) Presumably the ->wherePivot('type', 'director') clause in Film->List_Directors() then returns CastAndCrew members who are directors of that film? (which is what I want)
Corrections much appreciated!
Thanks
Your idea and logic is perfectly fine. You might want to add a relationship without the type condition to fetch all the films of user and all the cast and crew of a film. You also need to name your methods and relationships better. I've cleaned up the code for you. Feel free to use this if you prefer.
class Film extends Model
{
protected $fillable = array('filmtitle', 'description');
public function castAndCrew()
{
return $this->belongsToMany('App\CastAndCrew')->withPivot('type');
}
public function directors()
{
return $this->castAndCrew()->wherePivot('type', 'director');
}
public function actors()
{
return $this->castAndCrew()->wherePivot('type', 'actor');
}
}
class CastAndCrew extends Model
{
protected $fillable = array('firstname', 'lastname');
public function films()
{
return $this->belongsToMany('App\Film')->withPivot('type');
}
public function filmsAsDirector()
{
return $this->films()->wherePivot('type', 'director');
}
public function filmsAsActor()
{
return $this->films()->wherePivot('type', 'actor');
}
}

How to use Relation::morphMap() for diffrent class

I am using laravel polymorphic relation.
I have defined two morphTo relations for two purpose.
My question is that ,but when I am defining the key of Relation::morphMap() function array , then my array key is same for one case, so I want to know is there any way by which I can specify that I am defining relation for specific class.
My first relation....
Package.php
public function provider()
{
return $this->morphTo(null, 'map_type_id', 'map_id');
}
Venue.php
public function packages()
{
return $this->morphMany(VendorPackage::class, 'map', 'map_type_id', 'map_id');
}
Vendor.php
public function packages()
{
return $this->morphMany(VendorPackage::class, null, 'map_type_id', 'map_id');
}
I want to set the key to compare with map_type_id so I am setting the key in service provider.
Relation::morphMap([
config('evibe.roles.planner') => \Vendor::class,
config('evibe.roles.artist') => \Vendor::class,
config('evibe.roles.venue') => \Venue::class,
], false);
My 2nd morphTo relation
Ticket Booking.php
public function provider()
{
return $this->morphTo(null, 'map_type_id', 'map_id');
}
Venue.php
public function bookings()
{
return $this->morphMany(TicketBooking::class,null,'map_type_id','map_id');
}
Decors.php
public function bookings()
{
return $this->morphMany(TicketBooking::class,null,'map_type_id','map_id ');
}
Now again I have to define the morphTo in service provider because I am not using the default Model name.
so my morphTo in service providers became like this.
Relation::morphMap([
config('evibe.roles.planner') => \Vendor::class,
config('evibe.roles.artist') => \Vendor::class,
config('evibe.roles.venue') => \Venue::class,
config('evibe.ticket_type.venues') => \Venue::class,
config('evibe.ticket_type.decors') => \Decor::class
], false);
Now my problem is that key config('evibe.roles.planner') and config('evibe.ticket_type.venues) has the same value 3, so when both things is accessed by the relationship then it is throwing error, because array have same key.
So I want to ask is there any other way to define different morphMap for different relationship.
Lets start by defining the polymorphic relations
Firts relation....
Package.php
public function provider() {
return $this->morphTo(null, 'map_type_id', 'map_id');
}
Venue.php
public function packages() {
// you should provide the relation name, in our exemple its called `provider` as a second parameter
return $this->morphMany(VendorPackage::class, 'provider', "venues");
}
Vendor.php
public function packages() {
// you should provide the relation name, in our exemple its called `provider` as a second parameter
return $this->morphMany(VendorPackage::class, 'provider', "vendors");
}
Second Relation
TicketBooking.php
public function provider() {
return $this->morphTo(null, 'map_type_id', 'map_id');
}
Venue.php
public function bookings() {
return $this->morphMany(TicketBooking::class, 'provider', 'venues');
}
Decors.php
public function bookings() {
return $this->morphMany(TicketBooking::class, 'provider', 'decors');
}
and register Relation::morphMap as
Relation::morphMap([
'vendors' => \Vendor::class,
'venues' => \Venue::class,
'decors' => \Decor::class
]);

Get incorrect table when tried to insert

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';

How to create self referential relationship in laravel?

I am new to Laravel. I Just want to create a self referential model. For example, I want to create a product category in which the field parent_id as same as product category id. How is this possible?
Model Shown below
class Product_category extends Eloquent
{
protected $guarded = array();
public static $rules = array(
'name' => 'required',
'parent_id' => 'required'
);
function product_category()
{
return $this->belongsto('Product_category','parent_id');
}
}
It results Maximum function nesting level of '100' reached, aborting! Error
You can add a relation to the model and set the custom key for the relation field.
class Post extends Eloquent {
function posts(){
return $this->hasMany('Post', 'parent_id');
}
}
EDIT
Try this construction
class Post extends Eloquent {
public function parent()
{
return $this->belongsTo('Post', 'parent_id');
}
public function children()
{
return $this->hasMany('Post', 'parent_id');
}
}
Your model is not at fault for producing the "maximum function nesting level of '100' reached" error. It's XDebug's configuration; increase your xdebug.max_nesting_level.
The following is from a 2015 post by #sitesense on laracasts.com:
This is not a bug in Laravel, Symfony or anything else. It only occurs when XDebug is installed.
It happens simply because 100 or more functions are called recursively. This is not a high figure as such and later versions of XDebug (>= 2.3.0) have raised this limit to 256. See here:
http://bugs.xdebug.org/bug_view_page.php?bug_id=00001100
EDIT: In fact the latest Homestead provisioning script already sets the limit to 250. See line 122 here:
https://github.com/laravel/settler/blob/master/scripts/provision.sh#L122
So the addition of xdebug.max_nesting_level = 250 to php.ini should do it.
I've added a little more to the code based on your comments trying to access the parent!
class Person extends \Eloquent {
protected $fillable = [];
var $mom, $kids;
function __construct() {
if($this->dependency_id<>0) {
$this->mother->with('mother');
}
}
public function children() {
$children = $this->hasMany('Person','dependency_id');
foreach($children as $child) {
$child->mom = $this;
}
return $children;
}
public function mother() {
$mother = $this->belongsTo('Person','dependency_id');
if(isset($mother->kids)) {
$mother->kids->merge($mother);
}
return $mother;
}
}
Then you can access the parent from the child with eager loading, see more here:
http://neonos.net/laravel-eloquent-model-parentchild-relationship-with-itself/

Resources