Simple mutator screwing with SQL Query? - Laravel - php

I want to be able to set the user_id via the setUserIdAttribute mutator but it won't work. The code works fine when I comment out the mutator. Below is my code and the resulting QueryException error. Please help!
// EventController.php
public function store(Request $request)
{
Event::create([
'name'=>'myName',
'user_id'=>'1'
]);
return 'Success!';
}
// Event.php
class Event extends Model
{
protected $fillable = ['name', 'user_id'];
// It works as expected if I comment this out.
public function setUserIdAttribute($value)
{
// I know this code will run. If i do echo 'foo' it works.
return '1';
}
}
// The migration file
public function up()
{
Schema::create('events', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
// The error I get
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into `events` (`name`, `updated_at`, `created_at`) values (myName, 2017-04-23 22:28:31, 2017-04-23 22:28:31))

I think $this->attributes['attribute_name'] is the correct way to mutate.
// Event.php
class Event extends Model
{
protected $fillable = ['name', 'user_id'];
// It works as expected if I comment this out.
public function setUserIdAttribute($value)
{
// Set Attribute's value.
$this->attributes['user_id'] = Auth::id();
}
}

Related

Laravel : Doesn't have a default value - KeyProduct with Faker

I can't add a keyproduct when i'm creating a new product.
I get the error SQLSTATE[HY000]: General error: 1364 Field 'category_id' doesn't have a default value (SQL: insert into `products` (`activation_key`, `updated_at`, `created_at`) values (57394cd3-54f8-3e95-a951-e11f029fa0f5, 2020-05-27 17:09:08, 2020-05-27 17:09:08))
I don't know why, it asks me that.
What I tried :
category_id is my first column that i'm adding in my table. If I put ->nullable() to category_id , I get the same error with name that is the next column in my table.
This is imy code :
ProductController
public function store(Request $request)
{
$inputs = $request->except('_token');
$quantity = $inputs['quantity'];
factory(KeyProduct::class, $quantity)->create();
foreach ($inputs as $key => $value) {
$home->$key = $value;
}
$home->image=$path;
$home->save();
return redirect('admin/gamelist');
}
Product_table
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->string('name');
$table->string('image')->nullable();
$table->string('activation_key')->nullable();
$table->timestamps();
});
KeyProduct_table.php
Schema::create('key_products', function (Blueprint $table) {
$table->increments('id');
$table->string('activation_key');
$table->timestamps();
});
Keyproduct.php
public function products()
{
return $this->HasOne('App\Product')->withPivot('quantity');
}
Product.php
class Product extends Model
{
public function categories()
{
return $this->belongsTo('App\Category', 'category_id');
}
public function keyProduct()
{
return $this->HasOne('App\KeyProduct');
}
protected $fillable = ['quantity'];
}
KeyProductFactory.php
use App\KeyProduct;
use App\Product;
$factory->define(KeyProduct::class, function (Faker $faker) {
$product = factory(Product::class)->create();
return [
'activation_key' => $product->activation_key,
];
});
ProductFactory.php
use App\Product;
use Faker\Generator as Faker;
$factory->define(Product::class, function (Faker $faker) {
return [
'activation_key' => $faker->uuid
];
});
CategoryFactory
use App\Category;
use Faker\Generator as Faker;
$factory->define(Category::class, function (Faker $faker) {
return [
'activation_key' => $faker->uuid
];
});
Thanks for your help.
It fails because the product is created without you setting that category_id or name at the time of creation. Make them nullable() or change your creation method accordingly.
In your SQL you provided values for "activation_key", "updated_at" and "created_at" columns only, so other fields must satisfy at least one statement:
have an AUTO_INCREMENT option;
have a DEFAULT value;
allow NULL values.
You haven't provided enough data to complete the query.
Add more $fillables to your Product.php Model. By looking at your migrations it should look like this:
protected $fillable = [
'category_id', 'name', 'image', 'activation_key', 'quantity'
];

Laravel - Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

I am currently learning Laravel through a personal project.
Context
In a blog like application, I need to link an article to its author. When I save the article, I get the error below.
Error
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (parabolica-dev.articles, CONSTRAINT articles_user_id_foreign FOREIGN KEY (user_id) REFERENCES users (id)) (SQL: insert into articles (title, content, excerpt, updated_at, created_at) values (rgergregerg, regergergregerg, regregregregreg, 2020-04-29 09:55:12, 2020-04-29 09:55:12))
Models
Article
class Article extends Model
{
protected $fillable = ['title', 'content', 'excerpt', 'user_id'];
public function user() {
return $this->belongsTo('App\User');
}
}
User
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
public function article()
{
return $this->hasMany('App\Article');
}
}
Migrations
Users
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
Articles
class CreateArticlesTable extends Migration
{
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title');
$table->text('excerpt');
$table->text('content');
$table->string('type');
$table->string('status');
// Relationship between article and user
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
}
public function down()
{
Schema::dropIfExists('articles');
}
}
Controller
ArticleController
class ArticleController extends Controller
{
public function store(StoreArticle $request)
{
$validatedData = $request->validated();
$user = Auth::user()->id;
$article = Article::create($validatedData);
$article->user_id = $user;
$request->session()->flash('status', 'Article was created!');
return redirect()->route('articles.show', ['article' => $article->id]);
}
}
Solutions tried
Adding user_id to the $fillable array in my Article model, I still get the error.
Adding the nullable() method to user_id in my migration. Saving the article goes through without the error message but the user_id is recorded as null in my table afterwards.
Those are the 2 most proposed solutions across SO / LaravelCasts from what I found. Any suggestions on what I did wrong ?
Thanks for helping me !
The create method creates and saves a new instance of your model. Since the model does not include the users id at that point, it fails.
You could fix that by adding user_id to the fillables array of your model and also add the user id to the $validatedData array before creating the model.
Alternatively, you can also create a new instance of your model with the new keyword, set all data and explicitely save it once you're done:
$article = new Article($validatedData);
$article->user()->associate( Auth::user() );
$article->save();
You have to change this three lines. You insert a row but at the time user_id is null. That's why it shows the error because you assigned the user_id field not nullable.
$article = new Article;
$article->fill($validatedData);
$article->user_id = Auth::user()->id;
$article->save();

cascade user deletion laravel

I'm trying to delete a user but there is ForeignKey constraints that I also need to delete.
In my User model, I have
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
public $incrementing = false;
protected $fillable = [
'name',
'email',
'password',
'timezone',
'profile_picture',
'notification_key'
];
protected $hidden = [
'password',
'pivot',
'admin'
];
public static function boot()
{
parent::boot();
static::creating(function ($instance) {
$instance->id = Uuid::uuid4();
});
}
public function groups()
{
return $this->belongsToMany(Group::class)
->withPivot('user_role')
->withTimestamps();
}
public function events()
{
return $this->belongsToMany(Event::class);
}
}
migrations for relation are
class CreateEventUserTable extends Migration
{
public function up()
{
Schema::create('event_user', function (Blueprint $table) {
$table->uuid('event_id');
$table->uuid('user_id');
$table->primary(['event_id', 'user_id']);
$table->foreign('event_id')->references('id')->on('events');
$table->foreign('user_id')->references('id')->on('users');
});
}
public function down()
{
Schema::dropIfExists('event_user');
}
}
and
class CreateGroupUserTable extends Migration
{
{
Schema::create('group_user', function (Blueprint $table) {
$table->uuid('group_id');
$table->uuid('user_id');
$table->string('user_role')->nullable();
$table->timestamps();
$table->boolean('owner');
$table->primary(['group_id', 'user_id']);
$table->foreign('group_id')->references('id')->on('groups');
$table->foreign('user_id')->references('id')->on('users');
});
}
public function down()
{
Schema::dropIfExists('group_user');
}
}
so I was trying to delete user like this
public function delete($user)
{
$user = User::findOrfail('id', $user->id);
$res = $user->groups()->events()->delete();
if ($res) {
return response('Success, user was deleted', 204);
} else {
return response()->json(error);
}
}
but still, I'm receiving
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`event_activities`, CONSTRAINT `event_activities_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)) (SQL: delete from `users` where `id` = someID) in file /home/server/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 664
I was hoping to do deletion in the manner by relationship in the User model, but I'm still receiving an Integrity error, so what is the proper way of doing this?
There are 3 ways to achieve this:
Using detach
$user->groups()->events()->detach();
$user->groups()->detach();
Utilise the deleting event on related models like in this answer
Migrations.
// in user_roles
$table->integer('group_id');
$table->foreign('group_id')->references("id")->on("groups")->onDelete("cascade");
This translates into:
When group 'id' is deleted on 'groups', delete this row.
Apply same thing to groups for events.
Edit:
Looking at your migrations, you implemented 3rd solution, but you seem to forget
->onDelete('cascade');

Laravel 5.1 Foreign Key Trouble

I have some trouble getting the foreign key.
My Migrations looks like this (shortened them):
<?php
class CreateProductsTable extends Migration
{
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('email');
$table->string('title');
$table->string('filename');
$table->integer('number_of_chapters');
$table->text('input_mpg');
$table->timestamps();
});
}
public function down()
{
Schema::drop('products');
}
}
<?php
class CreateChaptersTable extends Migration
{
public function up()
{
Schema::create('chapters', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->time('input-chapter-start1');
$table->time('input-chapter-end1');
$table->timestamps();
});
Schema::table('chapters', function($table) {
$table->foreign('product_id')->references('id')->on('products');
});
}
public function down()
{
Schema::drop('chapters');
}
}
And my 2 Model like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Chapters extends Model
{
protected $table = 'chapters';
protected $fillable = ['input-chapter-start1', 'input-chapter-end1'];
public function product()
{
return $this->belongsTo('App\Product');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $table = 'products';
protected $fillable = ['email', 'title', 'filename', 'inputMpg', 'number_of_chapters'];
public static $rules = [
'email' => 'required|email|max:50',
'title' => 'required|max:50',
'filename' => 'required|max:50',
'input_mpg' => 'required'
];
public function Chapters()
{
return $this->hasMany('App\Chapters');
}
}
And just save it like this in my Controller
$product->save();
$Chapters->save();
And get following error:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails
(generator.chapters, CONSTRAINT chapters_product_id_foreign
FOREIGN KEY (product_id) REFERENCES products (id)) (SQL: insert
into chapters (input-chapter-start1, input-chapter-end1,
updated_at, created_at) values (12:12:12, 12:12:12, 2016-04-25
11:41:31, 2016-04-25 11:41:31))
EDIT
Controller looks like this:
namespace App\Http\Controllers;
class ProductController extends Controller
{
protected $request;
public function request(Request $request)
{
$this->request = $request;
}
public function createProduct(Request $request)
{
$product = new Product;
$Chapters = new Chapters($request->all());
$data = $request->all();
$projectEmail = $request->input('email');
$projectTitle = $request->input('title');
$projectFile = $request->input('filename');
$projectChapters = $request->input('number_of_chapters');
$validator = Validator::make($request->all(), Product::$rules);
if($validator->fails())
{
return Redirect::back()->withInput()->withErrors($validator);
}
$product->fill($data);
if($product->save())
{
$Chapters->product()->associate($product);
$Chapters->save();
return redirect()->route('root')->with('message', 'success')->withInput();
}
else
{
return redirect()->route('newProduct')->with('message', 'Error')->withInput();
}
}
}
Edit I tried Samsquanch suggestion:
And added this in my controller:
$product->save();
$Chapters->product()->associate($product);
$Chapters->save();
but still get this error message:
BadMethodCallException in Builder.php line 2093: Call to undefined
method Illuminate\Database\Query\Builder::products()
The problem is that you're not telling Laravel or MySQL what the foreign key should be.
You have two options here (both from the documentation: https://laravel.com/docs/5.1/eloquent-relationships#inserting-related-models)
The first option would be to save chapters through product:
$chapters = $product->chapters()->saveMany($Chapters); // or just->save() if it's only one
The second (and how I generally do it) would be to use associate() which relies on the belongsTo relationship in your Chapters model:
$product->save();
$Chapters->product()->associate($product);
$Chapters->save();
There's also a third, but not recommended, option of just setting the foreign key yourself manually.
Edit:
$product->chapters()->associate($Chapters);
$product->save();

Laravel Eloquent after save id becomes 0

It's a table migrated from https://github.com/lucadegasperi/oauth2-server-laravel
In the table oauth_clients, the field data type of id is varchar(40), not int.
$name = Input::get('name');
$id = str_random(40);
$secret = str_random(40);
$client = new oauthClient;
$client->name = $name;
$client->id = $id;
$client->secret = $secret;
$client->save();
After save(); the $client->id become '0', not the string I assigned.
That makes the following relation table save fail.
$endpoint = new OauthClientEndpoint(array('redirect_uri' => Input::get('redirect_uri));
$client->OauthClientEndpoint()->save($endpoint);
I checked the $client->id: after save, it becomes 0 and I get an error including this one:
(SQL: insert into `oauth_client_endpoints` (`redirect_uri`, `client_id`, `updated_at`, `created_at`) values (http://www.xxxxx.com, 0, 2014-09-01 11:10:16, 2014-09-01 11:10:16))
I manually saved an endpoint to prevent this error for now. But how do I resolve this issue?
Here's my model:
class OauthClient extends Eloquent {
protected $table = 'oauth_clients';
public function OauthClientEndpoint(){
return $this->hasOne('OauthClientEndpoint', 'client_id', 'id');
}
}
class OauthClientEndpoint extends Eloquent {
protected $table = 'oauth_client_endpoints';
protected $fillable = array('redirect_uri');
public function OauthClient(){
return $this->belongsTo('OauthClient', 'client_id', 'id');
}
}
class CreateOauthClientsTable extends Migration {
public function up() {
Schema::create('oauth_clients', function (Blueprint $table) {
$table->string('id', 40);
$table->string('secret', 40);
$table->string('name');
$table->timestamps();
$table->unique('id');
$table->unique(array('id', 'secret'));
});
}
public function down() {
Schema::drop('oauth_clients');
}
}
class CreateOauthClientEndpointsTable extends Migration {
public function up() {
Schema::create('oauth_client_endpoints', function (Blueprint $table) {
$table->increments('id');
$table->string('client_id', 40);
$table->string('redirect_uri');
$table->timestamps();
$table->foreign('client_id')
->references('id')->on('oauth_clients')
->onDelete('cascade')
->onUpdate('cascade');
});
}
public function down() {
Schema::table('oauth_client_endpoints', function ($table) {
$table->dropForeign('oauth_client_endpoints_client_id_foreign');
});
Schema::drop('oauth_client_endpoints');
}
}
When you are setting your own ID and not using auto_increment be sure to add public $incrementing = false; to that model. In your case you want:
class OauthClient extends Eloquent {
public $incrementing = false;
protected $table = 'oauth_clients';
public function OauthClientEndpoint(){
return $this->hasOne('OauthClientEndpoint', 'client_id', 'id');
}
}
This is a tiny red block in the huge Laravel documentation:
Note: Typically, your Eloquent models will have auto-incrementing keys. However, if you wish to specify your own keys, set the incrementing property on your model to false.

Categories