Laravel unique validation issue - php

I try to make a unique validation the settings of my website but this doesn't work :
In my controller :
$rules = array(
'username' => 'required|unique:User,username,10',
'email' => 'required|email|unique:User,email,10',
'language' => 'required|in:fr,en',
);
My model:
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
protected $primaryKey = 'id_user';
protected $table = 'user';
}
The problem is:
My Validator Validator::make(Input::all(), $rules, $messages); fails, it says that this username and email already exist.

Disagree with the answer to your own question:
"Laravel is not done to search in a custom column".
This is not true.
To be precise: There is nothing bad in using a Plugin...
See the important part of a migration file (app/database/migrations):
// creates a DB-table named 'users'
Schema::create('users', function (Blueprint $t) {
$t->increments('id');
$t->timestamps();
// ... Here a unique field
$t->string('user_email_one', 255)->unique();
// ...
});
And the relevant validation rules in the UserController:
$rules = array(
'user_email_one' => 'required|email|unique:users',
// ...
);
And Laravel is doing its job.
With unique: you have to call the DB-table name, not the model name.
BTW: the plugin you've chosen does this...
The Laravel docs about validation:
unique:table,column,except,idColumn
The field under validation must be unique on a given database table.
If the column option is not specified, the field name will be used.
Just as an interesting info about naming a mySQL table 'User', 'user' or 'users', which could have caused your error. Visit this question:
Is there a naming convention for MySQL? asked by StackOverflowNewbie, answered by Tom Mac (highest vote & accepted answer)

Laravel is not done to search in a custom column.
So I have installed this plugin https://github.com/felixkiss/uniquewith-validator who did the job very well:
$rules = array(
'username' => 'required|alpha_dash|unique_with:user,username,10 = id_user',
'email' => 'required|email|unique_with:user,email,10 = id_user',
'language' => 'required|in:fr,en',
);

Related

Can't get backpack to pass correct value when inserting/updating a many to many relationship

I have created a many to many relationship between two tables with a third pivot table.
The thing that makes the situation a little difficult is I am linking the Apps table based on name and not ID. It is because I update the App list from a third party and app name will always be consistent, where ID can possibly change if App is removed at some point, and then re-added, etc.
Apps
id
name // This is the name of the app, it will never change for a particular app and is short, all lowercase, no spaces, and unique
label // This is the user friendly name
Plans
id
name
etc
apps_plans pivot table
id
apps_name
plans_id
I've finally got everything working perfectly in Laravel itself, but I cannot figure out at all how to get this to work correctly in Backpack for my Admin portal. I've gotten it to the point where everything works perfect until I try to update or create a new plan. The Apps I select using the select2 type, it tries to insert them into the pivot table with an ID number and not with the name.
Randomizing some names, my mistake if things don't match perfectly. This aspect works fine from all tests I've done:
Plans Model:
{
use CrudTrait;
protected $table = 'plans';
protected $guarded = ['id'];
public function apps()
{
return $this->belongsToMany('App\Apps', 'apps_plans', 'plans_id', 'apps_name', 'id', 'name');
}
}
Apps Model:
class Apps extends Model
{
use CrudTrait;
protected $table = 'apps';
protected $guarded = ['id'];
protected $casts = [
'json' => 'array',
];
public function plans()
{
return $this->belongsToMany('App\Plan', 'apps_plans', 'apps_name', 'plans_id', 'name', 'id');
}
}
**Note I removed the fillable variable , I didn't want to expose all variables in my columns.
Backpack Plans CrudController:
public function setup()
{
CRUD::setModel(\App\Plan::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/plan');
CRUD::setEntityNameStrings('plan', 'plans');
$this->crud->addColumn([
'name' => 'apps',
'type' => 'relationship',
'label' => 'Apps',
'entity' => 'apps',
'attribute' => 'label',
'model' => \App\Apps::class,
]);
}
protected function setupCreateOperation()
{
CRUD::setValidation(PlanRequest::class);
CRUD::setFromDb(); // fields
$this->crud->addField('apps', [
'name' => 'apps',
'type' => 'select2_multiple',
'entity' => 'apps',
'attribute' => 'label',
'label' => 'Apps',
'pivot' => true,
]);
I removed quite a bit to keep my project details private, I hope it makes sense. I think all important details are still in. Anyone know if this is an issue with Backpack? Or did I miss an option somewhere, where you can set which column it uses for the relationship. It is clearly not taking it from the model because the models work just as intended on their own...
Thanks!
Edit: here is my migration I am using, it works flawlessly--even in phpmyadmin it gives me a drop down of items to select from
{
Schema::create('apps_plans', function (Blueprint $table) {
$table->id();
$table->string('apps_name');
$table->foreign('apps_name')->references('name')->on('apps');
$table->unsignedBigInteger('plans_id');
$table->foreign('plans_id')->references('id')->on('plans');
});
}
EDIT 2:
This is the error I am getting when trying to do a Create or Update:
{
"error": "There is a problem with your request",
"message": "SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`api`.`apps_plans`, CONSTRAINT `apps_plans_apps_name_foreign` FOREIGN KEY (`apps_name`) REFERENCES `apps` (`name`)) (SQL: insert into `apps_plans` (`apps_name`, `plans_id`) values (2, 4))"
}
Again I removed some details that were very specific to my project but I don't think I changed any of the logic in the error message. You can see everything looks great about the query except that at the very end, it is inserting the App ID instead of the App name as it should be.
I suspect that the current configuration will have the same result in Laravel directly. ie running something like $plan = Plan::find($somePlanId); $app = App::find($someAppId); $plan->apps()->attach($app); would result in the same error.
Since name is the key that matters for the apps table, consider dropping the autoincrementing id for that table and instead setting
In the migration for the apps table, do:
$table->string('name')->primary();
Then in your apps model, do:
protected $primaryKey = 'name';
public $incrementing = false;
protected $keyType = 'string';
Now, Laravel (and by proxy Backpack) should treat the relationship the way you expect.

how to save extra not required field in laravel default auth registration form

I am trying to customize the laravel auth registration. And I have added father name field in table and form. But father name field is not required.
I added this field in registercontroller.php and in User model also.
And then, if submit the form with all fields then data inserts successfully, But if I submit the form without father name field (which is not required), then error comes: f_name filed can not be null.
If I remove f_name from fillable then f_name is not saving.
Method in RegisterController.php is:
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'f_name' => $data['f_name'],
'password' => bcrypt($data['password']),
]);
}
User.php is:
protected $fillable = [
'name', 'email', 'f_name' , 'password',
];
This is because you did not make it nullable in the database.
The other thing is that you should not code like that. You should create a Request class (where you validate request) for users with php artisan make:request UserRequest in command line or terminal. See the following.
protected function create(UserRequest $userRequest)
{
$user = new User($userRequest->all());
$user->password => bcrypt($userRequest['password']);
$user->save();
// your rest of the code.
}
Case 1: You might have set field default value to not-NULL in DB. Check your migrations it shpuld be something like $table->string('f_name')->nullable(); or Check in DB/phpmuadmin and set to NULL by default.
Case 2: Check your validator function, can set it to sometimes.

Laravel Backpack - Show specific attribute from relationship function

I have the registered Comment model which has a User reference, like this:
public function user() {
return $this->belongsTo('App\User');
}
This function returns an instance of a User, and that's correct, but I don't know how to register the User column the get que user property using Backpack. Instead, I'm get a JSON representation of my model:
So, how do I get a specific field from my relationship function?
Sounds like the select column is a perfect match for you. Just use it in your EntityCrudController's setup() method, like so:
$this->crud->addColumn([
// 1-n relationship
'label' => "User", // Table column heading
'type' => "select",
'name' => 'user_id', // the column that contains the ID of that connected entity;
'entity' => 'user', // the method that defines the relationship in your Model
'attribute' => "user", // foreign key attribute that is shown to user
'model' => "App\Models\User", // foreign key model
]);
The "attribute" tells CRUD what to show in the table cell (the name, the id, etc).
If you do:
$user = $comment->user->user;
You'll get 'test'; (from your example)
It may seem confusing because your User model has a user attribute. Maybe you can call it 'name' instead of 'user'. That way you'll call it:
$username = $comment->user->name;
Remember to check if the relationship exists before calling a property on the related model.
if(!is_null($comment->user)) {
$username = $comment->user->user;
}
Or:
$username = !is_null($comment->user) ? $comment->user->user : 'No user';
If you need to get some field from deeper relation, you can use closure column type:
$this->crud->addColumn([
'label' => trans('backend.column_names.agency_linked_service'),
'name' => 'agency_service_id',
'type' => 'closure',
'function' => function (AgencyLinkedServices $entry) {
return $entry->agencyService->agencyCategory->title;
}
]);

Laravel Model Factories ID not set

I have a regular User model. The system works fine when I use it. But now I am trying to create unit tests in the PHPUnit that integrated with Laravel.
I have a factory that creates a user:
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'id' => $faker->randomNumber(9),
'email' => $faker->safeEmail,
'first_name' => $faker->firstNameMale,
'last_name' => $faker->lastName,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
I changed the User to have integer ID as the primary key but it not defined as auto-increment.
So the factory create random number for the ID.
Also I have created the simple test:
public function test_id_is_visible() {
$user = factory(App\User::class)->create();
$this->actingAs($user);
$this->visit('/userprofile');
$this->see($user->id);
}
That test always fails, but it seems to be OK when I navigate to the page manually.
I have noticed that in the test the $user->id is always 0. Even it can't be 0 in the factory. I checked and Laravel insert the user correctly to the database and it have correct ID, but in the code I always get 0.
What can I do to get the correct value of the ID?
EDIT
Now I see that if I changes $user = factory(App\User::class)->create(); to $user = factory(App\User::class)->make(); the user instance holds a correct ID. But why create clears the ID?
Update for Laravel 5.8+ Make sure to set
public $incrementing = false;
on your model.
The problem happened because the ID is not defined as auto-increment.
More information you can found in:
https://stackoverflow.com/a/31350800/1725836
Even the question is for Laravel 4 it is still relevant for Laravel 5.2.
You can write your tests like this:
$users = factory(User::class, 5)->make();
$users->each(function ($item, $key) {
$item->id = ++$key;
});
Now each user will have an id, without the need to persist the models to database (using create() instead of make()).
public function test_id_is_visible() {
$user = factory(App\User::class)->make();
$user->id = 7;
$this->actingAs($user);
$this->visit('/userprofile');
$this->see($user->id);
}

shared pivot table for inherited table

I have 3 tables, people, instructors, and trainees. instructor and trainees inherit from people. both three table have relation to fee_instructor table. here is all the models.
// Person.php
class Person extends \Eloquent {
// Add your validation rules here
public static $rules = [
// 'title' => 'required'
'name'=>'required',
'institution_id'=>'required',
'pob'=>'required',
'dob'=>'required'
];
// Don't forget to fill this array
protected $fillable = [
'name',
'title',
'position',
'institution_id',
'pob',
'dob',
'photo',
'last_education',
'nip',
'role_id'
];
public function fee(){
return $this->belongsToMany('Fee', 'fee_instructor', 'person_id');
}
}
// Instructor.php
class Instructor extends \Eloquent {
// Add your validation rules here
public static $rules = [
// 'title' => 'required'
];
// Don't forget to fill this array
protected $fillable = [
'name',
'title',
'position',
'institution_id',
'pob',
'dob',
'photo',
'email',
'last_education',
'nip'
];
public function fee(){
return $this->belongsToMany('Fee', 'fee_instructor', 'person_id');
}
}
// Trainee.php
class Trainee extends \Eloquent {
// Add your validation rules here
public static $rules = [
// 'title' => 'required'
];
// Don't forget to fill this array
protected $fillable = [
'name',
'title',
'position',
'institution_id',
'pob',
'dob',
'photo',
'last_education',
'nip',
'reg_date',
'company_name',
'marital_status',
'email'
];
public function fee(){
return $this->belongsToMany('Fee', 'fee_instructor', 'person_id');
}
}
// Fee.php
class Fee extends \Eloquent {
// Add your validation rules here
public static $rules = [
// 'title' => 'required'
];
// Don't forget to fill this array
protected $fillable = ['name', 'tarif', 'unit_id'];
public function unit(){
return $this->belongsTo('Unit');
}
public function instructor(){
return $this->belongsToMany('Instructor', 'fee_instructor');
}
public function person(){
return $this->belongsToMany('Person', 'fee_instructor');
}
public function trainee(){
return $this->belongsToMany('Trainee', 'fee_instructor');
}
}
when i try to update an entry that is not belongs to instructor (in both person or trainee), laravel throw the following error.
SQLSTATE[23503]: Foreign key violation: 7 ERROR: insert or update on table "fee_instructor" violates foreign key constraint "fee_instructor_instructor_id_foreign" DETAIL: Key (person_id)=(5) is not present in table "instructors".
how is the correct way to use the pivot table for these scenario?
Ah so your using postgresql. That' why I thought it was weird that you were talking about table inheritance. Take note that based on the docs http://www.postgresql.org/docs/9.0/static/ddl-inherit.html
Inheritance does not automatically propagate data from INSERT or COPY commands to other tables in the inheritance hierarchy.
INSERT always inserts into exactly the table specified.
...
In some cases it is possible to redirect the insertion using a rule (see Chapter 37).
So if you're not in the bounds of the rule, you may be incorrectly assuming that a row that exists in instructor also exists in the super-table person and vice-versa. You're update/insert on fee_instructor is failing simply because a row with person_id = 5 does not exist in the instructor table. It may exist in the person table but that is irrelevant. If it does not exist in instructor it wont work.
If you scroll through the docs about inheritance, you will also come up with the caveats of using inheritance:
A serious limitation of the inheritance feature is that indexes (including unique constraints)
and foreign key constraints only apply to single tables, not to their inheritance children.
So if you really want FK relationships with fee_instructor for both instructor and trainee then separate FKs have to exist for each table which I'm assuming you already have in place.
Please also take not that eloquent's regular relationship does not work well with the idea of inheritance. However, you may be able to achieve an inheritance type of behavior using polymorphic relations: http://laravel.com/docs/4.2/eloquent#polymorphic-relations

Categories