Laravel 4 eloquent create doesn't work and fill does - php

I want to create an instance of model called Property using method create with Input::all() as parameter. Input contains only fillable fields. When using create method laravel raise this exception:
alpha.ERROR: exception 'Illuminate\Database\QueryException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`propathai`.`properties`, CONSTRAINT `properties_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE) (SQL: insert into `properties` (`slug`, `updated_at`, `created_at`) values (, 2014-07-30 10:21:42, 2014-07-30 10:21:42))' in /home/ricardo/CHH/propathai/vendor/laravel/framework/src/Illuminate/Database/Connection.php:555
This exception is happening because insert query is not populated with all input params.
{"bedrooms":"4","title":"ricardo","room_type":"apartment","type":"rent","furnished":"fully_furnished","aging":"new","user_id":"3"}
I tried creating new Property object and using fill() method and it does work.
Code not working
public function store()
{
$input = Input::all();
$input['user_id'] = Auth::user()->id;
$property = Property::create($input);
return Response::json(array('success' => true, 'redirect' => '/dashboard/properties/'.$property->id.'/edit-details'));
}
Code working
public function store()
{
$input = Input::all();
$input['user_id'] = Auth::user()->id;
$property = new Property;
$property->fill($input);
$property->save();
return Response::json(array('success' => true, 'redirect' => '/dashboard/properties/'.$property->id.'/edit-details'));
}
Model
protected $guarded = array('id','services');
protected $fillable = array('user_id','bedrooms','title','room_type','type','furnished','aging');
If anyone knows why it's happening let me know please.
Thanks.

Your slug is not being filled.
SQL: insert into `properties`
(`slug`, `updated_at`, `created_at`) values (, 2014-07-30 10:21:42, 2014-07-30 10:21:42)
It may be one of those:
1- Your slug has a different name attribute on your input form.
2- It's not on your fillable array.
3- It's either empty, null or being filtered.
ex: to filter empty inputs I do:
$input = array_filter(Input::all(),'strlen');
By the way, the way you are doing this is not the nicest of ways. Check this out:
http://laravel.com/docs/eloquent
Click on "one to many"
What it would look like on your app?
Your model User
public function properties(){
return $this->hasMany('Property');
}
Your model Property
public function user(){
return $this->belongsTo('User');
}
On your controller:
$user = Auth::user();
$input = Input::all();
$input['user_id'] = $user->id;
$user->properties()->create($input);
That would be a more 'Laravel' way to approach it.
Also, if you really wanna go PRO watch Laracasts by Jeffrey Way.
It's the best online resource for Laravel4 I've seen online.

Related

Laravel error on save pivot table in transaction mode

I am trying to create a new record in during transaction by creating the model instance and then decorate all properties.
Post model
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function authors()
{
return $this->belongsToMany(
User::class, 'blog_post_authors', 'post_id', 'author_id'
);
}
Saving model
// start transaction mode
DB::beginTransaction();
$postModel = new Post(
['title' => 'Hello world!']
);
// relate authors
$postModel->authors()->attach(7);
\DB::commit();
However, its throwing an exception even before transaction being committed.
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'post_id' cannot be null (SQL: insert into `blog_post_authors` (`author_id`, `post_id`) values (7, ?))
you should save the Post Model , maybe you missed that:
DB::beginTransaction();
$postModel = new Post(
['title' => 'Hello world!']
);
$postModel->save();
// relate authors
$postModel->authors()->attach(7);
\DB::commit();
You are creating a $postModel in terms that it is created in php, but it is not saved to the database yet, and therefore does not yet have an id since the id it's probably an auto-incrementing value determined by the database.
So first save your postModel, than apply the author relation.
Either do:
$postModel = Post::create([...]);
or add:
$postModel->save();

Failing test that record saves to pivot table in laravel

I have a Board model and a Pin model, and they are many to many. I am testing to make sure that when a pin gets created and assigned a board, it saves to the pivot table. I am having trouble figuring this out since I am new to testing.
Here is my Test:
/** #test */
public function a_pin_can_belong_to_a_board()
{
$board = create('App\Board');
$pin = make('App\Pin');
$response = $this->post('/pins/create', $pin->toArray());
$pin->boards()->sync($board);
$this->assertDatabaseHas('board_pin', [
'board_id' => $board->id,
'pin_id' => $pin->id
]);
}
Here is my Error:
1) Tests\Unit\PinTest::a_pin_can_belong_to_a_board
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity
constraint violation: 19 NOT NULL constraint failed: board_pin.pin_id
(SQL: insert into "board_pin" ("board_id", "pin_id") values (1, ))
Caused by
PDOException: SQLSTATE[23000]: Integrity constraint violation: 19 NOT
NULL constraint failed: board_pin.pin_id
Here is my Controller:
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required|max:200',
'link' => 'required|max:255'
]);
$pin = new Pin();
$pin->title = $request->title;
$pin->link = $request->link;
$pin->user_id = auth()->id();
$pin->save();
$pin->boards()->sync($request->boards);
return redirect("/pins/{$pin->id}");
}
Any help would be greatly appreciated! Thank you!
Here is the answer! Instead of just using the make method on the pin instance, I used the create method and persisted it to the database, then just removed the post action. See below:
/** #test */
public function a_pin_can_belong_to_a_board()
{
$board = create('App\Board');
$pin = create('App\Pin');
$pin->boards()->sync($board);
$this->assertDatabaseHas('board_pin', [
'board_id' => $board->id,
'pin_id' => $pin->id
]);
}
You should be careful about using sync. I would advise against using it and instead opt for attach. The reason being the following:
You may also use the sync method to construct many-to-many
associations. The sync method accepts an array of IDs to place on the
intermediate table. Any IDs that are not in the given array will be
removed from the intermediate table. So, after this operation is
complete, only the IDs in the given array will exist in the
intermediate table
Documentation see "Syncing associations".
$pin->boards()->attach([$board->id])
Alternatively, although I'm not sure why you would choose this route you can use syncWithoutDetaching which does what one would expect:
If you do not want to detach existing IDs, you may use the
syncWithoutDetaching method
The main issue seems to be that you are using make on your pin but then you do not save it. You are creating an instance by also posting to that endpoint but it is not the same as the instance you have created locally. In your case $pin does not have an ID because it was never saved. There is a separate pin that was created with the same attributes when you did the following:
$this->post('/pins/create', $pin->toArray());
If your response contains the pin's id, you could do something like follows:
$pin_id = $response->getContent()->id;
$pin = Pin::find($pin_id);
$pin->boards()->attach([$board->id]);

Newly created Eloquent object won't return attribute in separate create Eloquent call

The code below shows a method in my Eloquent Link class. After creating a new Link I want to create a related object LinkContact then associate() it with the new Link.
When creating LinkContact I experience an issue in accessing the Link's id attribute. The Link id value appears inaccessible only when performing the create method for the new related object (LinkContact).
Using Laravel Debugbar a line before the create method is called I've logged the Link id and I can see it just fine! Any ideas why this is happening and why I can't access the value?! Is it to do with scope?
Please take note of where the comments are
public function createActiveLink($students)
{
$links = [];
foreach ($students as $student) {
$newLink = $this->create([
'token' => $student->saudi_nid,
'status' => 'active',
'course_title' => $student->course_title,
'university_id' => $student->university_id,
'student_id' => $student->id,
'institution_id' => $student->institution_id,
'course_id' => $student->course_id,
]);
$studentContacts = $student->institutionContacts;
if ($studentContacts) {
foreach ($studentContacts as $studentContact) {
/* I get the value here, no problems */
\Debugbar::info($newLink->id);
$linkContact = $this->contacts()->create([
'type' => $studentContact->pivot->type,
'institution_contact_id' => $studentContact->pivot->institution_contact_id,
/* $newLink->id returns nothing here */
'link_id' => $newLink->id, here!!
]);
$newLink->contacts()->associate($linkContact);
$newLink->save();
}
}
$links[] = $newLink;
}
return $links;
}
The errors I receive when attempting the above code:
SQLSTATE[23000]: Integrity constraint violation: 1048
Column 'link_id' cannot be null
(SQL: insert into `link_contacts`
(`type`, `institution_contact_id`, `link_id`, `updated_at`, `created_at`)
values (1, 1, , 2015-11-24 10:26:32, 2015-11-24 10:26:32))
C:\...\vendor\laravel\framework\src\Illuminate\Database\Connection.php#631
SQLSTATE[23000]: Integrity constraint violation: 1048
Column 'link_id' cannot be null
C:\...\vendor\laravel\framework\src\Illuminate\Database\Connection.php#380
To reiterate I do get the value in Laravel Debugbar but not in the method call after it!
Edit:
In my LinkContact class link_id is in my fillable attributes:
class LinkContact extends Model
{
protected $fillable = ['type', 'link_id', 'institution_contact_id'];
// rest of the class
}
It's worth noting that:
$newLink->contacts()->associate($linkContact);
Would in this instance, run a query like:
UPDATE `link_contacts` SET `link_id` = 1 WHERE `id` = 4;
So if you're setting the link_id in the create, there's no need to run associate. If memory serves you may be able to run $newLink->contacts()->create([...]) instead of both the create() and associate().
Because of the way Eloquent works, a foreign key will always be updated/inserted from running any helper method designed to automatically insert this data but you're manually specifying the key, meaning that it's subject to $fillable so I would take a look at that, and if you don't currently have it in there, add link_id to that array.
Try
$newLink->save();
before calling
$newLink->id
The id is generated only after the data was saved in the database so there's no way of knowing it before that.

Unable to associate models without manually assigning the foreign key in Laravel 5

I'm running into an issue when trying to associate a child model to a parent in Laravel 5.
I see in the documentation under the Inserting Related Models's "Associating Models (Belongs To)" section that I should be able to:
Create a child model instance: $comment = new Comment(['message' => 'A new comment.']);
Get the parent record: $post = Post::find(1);
Use the parent record's association method to save the child which should automatically relate it to the parent: $comment = $post->comments()->save($comment);
This makes sense to me conceptually, the problem I'm having is creating the child record without manually assigning the parent's id as a foreign key.
In my project, I have have a parent table Accounts and a child table Events. The Events schema has a foreign key constraint assigned for the Accounts id:
Schema::create('events', function(Blueprint $table)
{
$table->increments('id');
$table->integer('account_id')->unsigned();
$table->foreign('account_id')->references('id')->on('accounts');
$table->timestamp('date_of_donation');
$table->timestamp('date_last_donation_letter_sent');
$table->timestamps();
});
So when I go to create the Events instance that I'm planning on associating to the parent Accounts I get an exception thrown:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'account_id' cannot be null (SQL: insert into events (date_of_donation, date_last_donation_letter_sent, account_id, updated_at, created_at) values (2015-05-16, , , 2015-05-16 17:35:36, 2015-05-16 17:35:36))
I understand why the error is thrown because I'm not giving the Events instance a foreign key value.
I can get around it by getting the Accounts record first and creating the Events instance like so:
$account = $accounts->findOrFail($id);
$event = $events->create(['account_id' => $account->id, ...]);
But it seems like the whole point of the "Associating Models (Belongs To)" section is so that you don't have to do this.
Am I missing or misunderstanding something about how the associating functionality is supposed to work?
Update
Here's my Account model:
<?php namespace Hub;
use Illuminate\Database\Eloquent\Model;
class Account extends Model {
protected $fillable =[
'first_name',
'last_name',
'display_name',
'email',
'zipcode',
'phone_number'
];
public function donationEvents(){
return $this->hasMany('Hub\donationEvent');
}
}
And my Event model:
<?php namespace Hub;
use Illuminate\Database\Eloquent\Model;
class Event extends Model {
protected $fillable = [
'account_id',
'date_of_donation',
'date_last_donation_letter_sent'
];
public function donationItems(){
return $this->hasMany('Hub\DonationItem');
}
public function account(){
return $this->belongsTo('Hub\Account');
}
}
Also, here's the code that triggers the error:
Route::get('dev2', function ( Hub\Account $accounts, Hub\Event $events){
$account = $accounts->findOrFail(1);
// This is where I'm trying to create the child record but I get the exception
$event = $events->create(['date_of_donation' => '2015-05-16', 'date_of_last_donation_letter_sent' => '']);
$event = $account->events()->save($event);
return [$account, $event];
});
The thing is, create() instantiates a new model and directly saves it. So you actually save it twice. However the first time there is no foreign key set.
Instead of create() use fill() to set all the values without saving:
$event = $events->fill(['date_of_donation' => '2015-05-16', 'date_of_last_donation_letter_sent' => '']);
Or you can use the constructor as well (I personally prefer this solution)
$event = new Event(['date_of_donation' => '2015-05-16', 'date_of_last_donation_letter_sent' => '']);

What prevents me from adding a row with foreign key value?

1452 Cannot add or update a child row: a foreign key constraint fails (`bpr`.`trips`, CONSTRAINT `trips_driver_user_id_foreign` FOREIGN KEY (`driver_user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE)
is the error.
Adding a row, manually, through MySQL works fine. If I do it through my application - nope.
The id that I am trying to insert is correct (it exists and is an integer). I checked the foreign keys and stuff, everything looks fine. I don't know what the problem might be...
Some code:
$input = Input::all();
Trip::create([
'route_from' => $input['route_from'],
'route_to' => $input['route_to'],
... adding other stuff ...
'driver_user_id' => Auth::user()->id
]);
When I var_dump(Auth::user()->id) I do get correct int number, which is the correctly corresponding ID of the certain user.
in the Trip model:
protected $hidden = [
'id'
];
protected $fillable = [
'route_from',
'route_to',
...
'driver_user_id'
];
public function Trip()
{
return $this->belongsTo('User', 'driver_user_id', 'id');
}
in the User model:
public function Trips()
{
return $this->hasMany('Trip');
}
I have the gut feeling the attributes are guarded. Your code seems correct, however the error you receive originates from the database. Could you try it like this and see if it works:
$trip = new Trip;
$trip->unguard();
$trip->fill([
'route_from' => $input['route_from'],
'route_to' => $input['route_to'],
... adding other stuff ...
'driver_user_id' => Auth::user()->id
]);
$trip->save();
Using the create method on the model makes it difficult to debug what is happening.

Categories