HasOne create not updating foreign field - php

I'm using Laravel and I'm trying to create a related record from an array using the method HasOne::create. It inserts the related record, but does not add a new id to main model's foreign field. What am I doing wrong?
Thx
$contact = new Contact();
$contact->company = $data['company'] ?? '';
$contact->comment = $data['comment'] ?? '';
$contact->save();
$contact->address()->create($data['address']);
...
var_dump($contact->address_id); exit();
The relations work fine, all fields specified. By ->get() methods they're returning correct models
var_dump result - null
Also, the $data['address'] contains valid data, specified as fillable at Address model and address_id is fillable for Contact model
UPD:
Contact class:
public function address()
{
return $this->hasOne(Address::class, 'id', 'address_id');
}
Address class:
public function contact()
{
return $this->belongsTo(Contact::class, 'id', 'address_id');
}
$data['address'] contains an array with ['raw' => 'someaddress'], raw field is in $fillable

There's a nice guide on Eloquent Relationships here.
Based on that I just tested the code below and it works fine (using Laravel 5.8)
Migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class Cars extends Migration
{
public function up()
{
Schema::create('owners', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('cars', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
$table->integer('owner_id')->unsigned()->index()->nullable();
$table->foreign('owner_id')->references('id')->on('owners');
});
}
public function down()
{
Schema::drop('cars');
Schema::drop('owners');
}
}
Models
//App/Owner.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Owner extends Model
{
protected $fillable = ['name'];
public function car()
{
return $this->hasOne(Car::class);
}
}
//App/Car.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Car extends Model
{
protected $fillable = ['name'];
public function owner()
{
return $this->belongsTo(Owner::class);
}
}
Test
<?php
namespace Tests\Feature;
use App\Owner;
use Tests\TestCase;
class TestCars extends TestCase
{
/**
* A basic feature test example.
*
* #return void
*/
public function testExample()
{
$owner = new Owner(['name' => 'Jack']);
$owner->save();
$owner->car()->create(['name' => 'Nice Car']);
}
}
SQL
select * from cars;
------------
# id, name, created_at, updated_at, owner_id
'1', 'Nice Car', '2019-06-21 13:08:58', '2019-06-21 13:08:58', '1'
select * from owners
-------------
# id, name, created_at, updated_at
'1', 'Jack', '2019-06-21 13:08:58', '2019-06-21 13:08:58'

Related

Laravel Model relationship "Page have many Attachments"

I have models:
Page:
id
slug
Image
id
file
Video
id
file
I need the Page model to have a relation with several Image and Video models through one relationship, like
foreach($page->attachments as $attachment)
{
// $attachment can be Image or Video
}
And inserts like
$attachments = [$image, $video];
$page->attachments()->saveMany($attachments);
I tried to make a morph relationship, but nothing comes of it, please help.
Create an Attachment Model and attachments Table with the following columns/properties:
id
file
page_id
type (video/image)
then you could add hasmany relationship to your page model
public function attachments()
{
return $this->hasMany(Attachment::class);
}
Then you can fetch the attachment like you tried
In order to achieve this you have to make table for relations. This table should be defined like this:
page_image_video
id
page_id
image_id
video_id
And fields page_id, image_id and video_id should be a foreign keys. This is a table where you will save you attachments for your page. After that, you can define method attachments() in you Page Model with hasMany().
Create Migration :
Page Table :
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string("slug");
$table->timestamps();
});
Image Table :
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string("file");
$table->timestamps();
});
Videos Table :
Schema::create('video', function (Blueprint $table) {
$table->increments('id');
$table->string("file");
$table->timestamps();
});
Pageables Table :
Schema::create('pageables', function (Blueprint $table) {
$table->integer("pages_id");
$table->integer("pageable_id");
$table->string("pageable_type");
});
Create Model :
Now, we will create Pages, Images and Video model. we will also use morphToMany() and morphedByMany() for relationship of both model.
Video Model :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
use HasFactory;
protected $table='video';
protected $primaryKey='id';
protected $guarded = [];
public function pages()
{
return $this->morphToMany(Pages::class, 'pageable');
}
}
Images Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Images extends Model
{
use HasFactory;
protected $table='image';
protected $primaryKey='id';
protected $guarded = [];
public $timestamps = false;
public function pages()
{
return $this->morphToMany(Pages::class, 'pageable');
}
}
Pages Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
class Pages extends Model
{
use HasFactory;
protected $table='page';
protected $primaryKey='id';
protected $guarded = [];
public $timestamps = false;
public function posts()
{
return $this->morphedByMany(Images::class, 'pageable');
}
/**
* Get all of the videos that are assigned this tag.
*/
public function videos()
{
return $this->morphedByMany(Video::class, 'pageable');
}
}
Retrieve Records :
$pages = Pages::find(1);
foreach ($pages->posts as $post) {
var_dump($post);
}
foreach ($pages->videos as $video) {
print_r('<br>');
//var_dump($video);
}
Create Records :
$page = Pages::find(1);
$img = new Images();
$img->file = "test insert";
$page->posts()->save($img);
All done.

Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::type()

I'm trying to make a api that will return the type of a word (noun, pronoun, verb, etc.) after creating that word in the database. But for some reason I am getting a "Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::type()" error when the type method is clearly defined in my vocabulary model. I am not using a many to many relationship but a one to many (that's why I am using hasMany() and belongsTo). Type has many Vocabulary but Vocabulary has only one Type and many VocabularyContents and VocabularyContent has only one vocabulary it is related to. So clearly no many to many relationship. So clearly my question is not a duplicate of Call to undefined method (laravel 5.2)
. Here are parts of the code for the application.
The first model is the type model it allows me to get the "contents" of a type (model not listed here) and the vocabularies that belongs to a specific type.
model-code-listing 1: VocType.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class VocType extends Model
{
public function contents()
{
return $this->hasMany('App\VocTypeContent');
}
public function vocabularies()
{
return $this->hasMany('App\VocVocabulary');
}
}
this second model allows me to create a word in the vocabulary table access its "contents", type and category. This is where the issue lies.
model-code-listing 2: VocVocabulary.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class VocVocabulary extends Model
{
protected $fillable = ['voc_category_id','type_id', 'name', 'context', 'picture'];
public $timestamps = false;
public function contents()
{
return $this->hasMany('App\VocVocabularyContent');
}
public function type()
{
return $this->belongsTo('App\VocType');
}
public function category()
{
return $this->belongsTo('App\VocCategory');
}
}
The third model allows me to create the content of a vocabulary and access it parent vocabulary.
model-code-listing 3: VocVocabularyContent.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class VocVocabularyContent extends Model
{
protected $fillable = ['voc_vocabulary_id','lang_id', 'content', 'context', 'romanization', 'pronunciation', 'audio'];
public $timestamps = false;
public function vocabulary()
{
return $this->belongsTo('App\VocVocabulary');
}
}
below are the three migrations used for the models listed above.
migration-code-listing 1: create_voc_types_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateVocTypesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('voc_types', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('abbreviation');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('voc_types');
}
}
migration-code-listing 2: create_voc_vocabularies_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateVocVocabulariesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('voc_vocabularies', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('cat_id');
$table->unsignedInteger('type_id');
$table->foreign('cat_id')->references('id')->on('voc_categories')->onDelete('cascade');
$table->foreign('type_id')->references('id')->on('voc_types')->onDelete('cascade');
$table->string('name');
$table->string('context');
$table->string('picture');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('voc_vocabularies');
}
}
migration-code-listing 3: create_voc_vocabulary_contents_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateVocVocabularyContentsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('voc_vocabulary_contents', function (Blueprint $table) {
$table->primary(['voc_id', 'lang_id']);
$table->unsignedInteger('voc_id');
$table->unsignedInteger('lang_id');
$table->foreign('voc_id')->references('id')->on('voc_vocabularies')->onDelete('cascade');
$table->foreign('lang_id')->references('id')->on('languages')->onDelete('cascade');
$table->string('content');
$table->string('context');
$table->string('romanization');
$table->string('pronunciation');
$table->string('audio');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('voc_vocabulary_contents');
}
}
This is the controller where I am calling the type() method of vocabulary. basically I have an html form that sends a post request to this controller's method (postVocabularyAPI) if no id is provided in the request a vocabulary will be created (if the language is english). Then whether or not an id is provided with the request the method will create a vocabulary "content" for the given id (if no id is provided the given id will be the id of the previously created vocabulary). Then the postVocabularyAPI method will return a json response containing the id of the type of the vocabulary.
controller-code-listing 1: Vocabulearn.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Language;
use App\VocTheme;
use App\VocCategory;
use App\VocCategoryContent;
use App\VocVocabulary;
use App\VocVocabularyContent;
use App\VocType;
class Vocabulearn extends Controller
{
//other methods above
public function postVocabularyAPI(Request $request, $language, $theme, $category){
$vocabulary_id = $request->vocabulary_id;
if($vocabulary_id === NULL){
if($language == "english"){
$vocabulary = VocVocabulary::create([
'voc_category_id' => VocCategory::where("slug", $category)->get()->first()->id,
'type_id' => VocType::where("abbreviation", $request->type)->get()->first()->id,
'name' => ucfirst(addslashes($request->translation)),
'context' => $request->context,
'picture' => ''
]);
$vocabulary_id = $vocabulary->id;
} else {
echo '{"success":false, "message":"Create first the English Vocabulary"}';
}
}
$vocabularyContent = VocVocabularyContent::where('lang_id', '=', Language::where("slug", $language)->get()->first()->id)
->where('voc_vocabulary_id', '=', $vocabulary_id)
->first();
if($vocabularyContent !== NULL){
$vocabularies = DB::table('voc_vocabulary_contents')
->where('lang_id', '=', Language::where("slug", $language)->get()->first()->id)
->where('voc_vocabulary_id', '=', $vocabulary_id)
->delete();
}
$vocabularyContent = VocVocabularyContent::create([
'voc_vocabulary_id' => $vocabulary_id,
'lang_id' => Language::where("slug", $language)->get()->first()->id,
'content' => ucfirst(addslashes($translation)),
'context' => addslashes($context),
'romanization' => strtolower(addslashes($romanization)),
'pronunciation' => $pronunciation,
'audio' => $request->audio
]);
echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->type()->id)).'"}';
}
}
doing this gives me a
"Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::type()"
even when I change
echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->type()->id)).'"}';
by
echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->get()->first()->type()->id)).'"}';
I get an error stating
"Call to a member function type() on null"
which isn't right because the database was properly populated so I shouldn't be getting a null vocabulary.
There is a quick solution for that.
First add a foreign key in VocVocabulary model type function
public function type()
{
return $this->belongsTo('App\VocType', 'type_id');
}
And then remove paranthesis
echo $vocabularyContent->type->id;
But it is not the standard way to do that. You need to setup your relations in standard ways to help Laravel to understand your relations.
First you need to change the function name as camelCase of the model name. For example as your type model name is VocType so your type function should be changed as
public function type()
To
public function vocType()
{
return $this->belongsTo('App\VocType'); //you don't need a foreign key here
}
In this case you are telling laravel that the function vocType is targeting VocType model. Furthermore you need to change the foreign key in the table of VocVocabulary from type_id to voc_type_id. In this way Laravel clearly understands your relationship otherwise you need to put extra efforts to teach laravel about your relationships.

SQLSTATE[HY000]: General error: 1364 Field 'uID' doesn't have a default value

just started with Laravel. I have attached my user and profile models along with the profile controller. My goal is to assign the foreign key uID in the profile table automatically. Any help will be appreciated.
user model file
namespace App;
use Illuminate\Database\Eloquent\Model;
class user extends Model
{
// specify which attributes can be filled out during registration
public $timestamps = false;
protected $fillable=['firstname','lastname','email','password',];
public function profile(){
return $this->hasOne(profile::class,'pID','uID');
}
}
profile model file
namespace App;
use Illuminate\Database\Eloquent\Model;
class profile extends Model
{
//
public $timestamps = false;
protected $fillable = ['summary','uID'];
public function user(){
return $this->belongsTo(user::class,'uID','pID');
}
}
profile migration file
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProfilesTable extends Migration
{
public function up()
{
// create profile table
Schema::create('profiles', function (Blueprint $table) {
$table->increments('pID');
$table->timestamp('created_at')->useCurrent();
$table->string('summary')->default('');
$table->integer('uID')->unsigned();
$table->foreign('uID')->references('uID')->on('users')->onDelete('cascade');
});
}
}
profile controller file
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\profile;
class ProfileController extends Controller
{
public function store(Request $request)
{
// used to store user profile after validation
$this->validate($request,[
'summary' => 'required'
]);
$profile = new profile([
'summary' => $request->get('summary'),
]);
$profile->save();
return redirect()->route('profile.create')->with('success','Profile created');
}
}
Change your migration file,
As you wanted to define your relationship later, So your foreign id field should be nullable.
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProfilesTable extends Migration
{
public function up()
{
// create profile table
Schema::create('profiles', function (Blueprint $table) {
$table->increments('pID');
$table->timestamp('created_at')->useCurrent();
$table->string('summary')->default('');
$table->integer('uID')->nullable()->unsigned();
$table->foreign('uID')
->references('uID')
->on('users')
->onDelete('cascade');
});
}
}
And If you wanted to assign Logged in user after create profile,
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\profile;
class ProfileController extends Controller
{
public function store(Request $request)
{
// used to store user profile after validation
$this->validate($request,[
'summary' => 'required'
]);
$profile = new profile([
'summary' => $request->get('summary'),
'uID' => auth()->user()->id,
]);
$profile->save();
return redirect()->route('profile.create')->with('success','Profile created');
}
}
If you aren't providing value in your program, you need to provide default value on table definition level.
According to your description it seems you are missing to create a profile after creating a user record.

Laravel 5.1 create not working

I am new to Laravel 5.1. I'm watching a tutorial video and in video teacher is using this code to insert data in database :
<?php
namespace App\Http\Controllers;
use App\comments;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class CommentController extends Controller
{
public function getCommentNew()
{
$data = array(
'commenter' => 'soheil' ,
'comment ' => 'Test content' ,
'email' => 'soheil#gmail.com' ,
'post_id' => 1 ,
) ;
comments::create( $data );
}
}
I am doing the steps like him but I have a problem , all fields ecept created_at and updated_at will be empty like this :
this is my comments model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class comments extends Model
{
protected $fillable = ['commenter,email,post_id,comment,approved'];
public function post(){
return $this->belongsTo('App\posts');
}
}
and this is migration :
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCommentsTable extends Migration
{
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->unsignedinteger('post_id');
$table->string('commenter') ;
$table->string('email') ;
$table->text('comment') ;
$table->boolean('approved');
$table->timestamps();
});
}
public function down()
{
Schema::drop('comments');
}
}
You haven't properly set the $fillable attribute in your Model, try with :
// in your model
protected $fillable = [
'commenter','email','post_id','comment','approved'
];
You have to define column names saperately on fillable array as shempignon described on above answer
Ex: ['column1', 'column2'...]
not in a single string. Each column name needs to be an array element
Try this and it'll be fine :) , you just forgot protected $table = 'comments';
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class comments extends Model
{
protected $table = 'comments';
protected $fillable = ['commenter','email','post_id','comment','approved'];
public function post(){
return $this->belongsTo('App\posts');
}
}

Laravel Create Eloquent Instance from ManyToOne Relationship Error SQLSTATE[23000]

I want to create instance using Laravel 5 Eloquent Relationship.
I have 2 Migrations and 2 Eloquent Model.
Companies Migration:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCompaniesTable extends Migration {
public function up()
{
Schema::create('Companies', function(Blueprint $table)
{
$table->string('CompanyCode', 15);
$table->string('Name', 200);
$table->string('Type', 100);
$table->tinyInteger('IsActive')->default(1);
$table->timestamps();
$table->primary('CompanyCode');
});
}
public function down()
{
Schema::drop('Companies');
}
}
Company Model:
namespace App\Models\Setting\Organization;
use Illuminate\Database\Eloquent\Model;
class Company extends Model {
protected $fillable = ['CompanyCode', 'Name', 'Type'];
public function organizationUnits(){
return $this->hasMany('App\Models\Setting\Organization\OrganizationUnit', 'CompanyCode');
}
}
OrganizationUnits Migration:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateOrganizationUnitsTable extends Migration {
public function up()
{
Schema::create('OrganizationUnits', function(Blueprint $table)
{
$table->string('OrganizationUnitCode', 15); //PK
$table->string('CompanyCode', 15); //FK
$table->string('Name', 200);
$table->tinyInteger('IsActive')->default(1);
$table->timestamps();
$table->primary('OrganizationUnitCode');
$table->foreign('CompanyCode', 'OrgUnits_Company_FK')
->references('CompanyCode')
->on('Companies')
->onDelete('cascade');
});
}
public function down()
{
Schema::drop('OrganizationUnits');
}
}
OrganizationUnit Model:
namespace App\Models\Setting\Organization;
use Illuminate\Database\Eloquent\Model;
class OrganizationUnit extends Model {
protected $table = "OrganizationUnits";
protected $fillable = ['OrganizationUnitCode', 'CompanyCode', 'Name'];
public function company(){
return $this->belongsTo('App\Models\Setting\Organization\Company', 'CompanyCode');
}
}
The relationship is one Company may have one or more OrganizationUnit, one OrganizationUnit must have one and only one Company.
I tried to create new instance of OrganizationUnit in php artisan tinker using this code:
$company = \App\Models\Setting\Organization\Company::first();
$orgunit = $company->organizationUnits()->create(['OrganizationUnitCode' => 'abcdef']);
But Laravel gives the following error:
Illuminate\Database\QueryException with message 'SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'CompanyCode' cannot be null (SQL: insert into `OrganizationUnits` (`Org
anizationUnitCode`, `CompanyCode`, `updated_at`, `created_at`) values (abcdef, , 2015-12-17 00:17:33, 2015-12-17 00:17:33))'
Where did I go wrong? Please help. I'm new to Laravel.
It clearly says that CompanyCode cannot be null. You can define it by hand or you can use the increments method on the Blueprint instance while creating your migration.

Categories