I am having a model class in my Yii2-advanced application which was having some attributes.
public function rules()
{
return [
[['SESSION_TITLE', 'SESSION_DESCRIPTION', 'TRAINER_ID'], 'required'],
[['TRAINER_ID','IS_ACTIVE', 'IS_DELETED'], 'integer'],
];
}
Now, I need to add an attribute TNI_NUMBER in model which I already have added in database table with similar spellings. After adding in model.
public function rules()
{
return [
[['SESSION_TITLE', 'SESSION_DESCRIPTION', 'TRAINER_ID'], 'required'],
[['TRAINER_ID','TNI_NUMBER' ,'IS_ACTIVE', 'IS_DELETED'], 'integer'],
];
}
The form is showing Getting Unknown Property on that specific attribute, on loading the form right after adding this attribute. Note that the data type of attribute in model and in database is not an issue. And the database connection array has set 'enableSchemaCache' => true in it and it can't be set to false.
Yii::$app->cache->flush();
This worked for me, added it before calling model class in controller action.
NOTE: this is for one-time usage only, once page refreshed after adding this line, do remember to comment or remove it.
you need to refresh database schema
Yii::$app->db->schema->refresh();
You only need to run this once
or
you can set 'enableSchemaCache' to false
Related
So I just started a Laravel Project with Breeze, and I wanted to change the default table users , the problem is it didn't work, I did my research for days and I didn't get any successful result
I will try to explain what is the problem and what have I tried so far.
First, I created a new table called users_data, and this table, is completely different than the users table.
The fields that users_data has, are for example: name_value, password_value, age_value, email_value, etc. (I have to mention too that for the table users_data, it doesn't use a migration, because I already have an sql file, and added it directly to the db (I already have tables created, with primary keys, and foreign key, so i couldn't do the migration because it would take me a lot of time), and without the migration I can still get the data, so I don't think it could be this the problem).
Actually I'am using Breeze, however, I used Auth scaffolding (PHP artisan make: Auth) too
What have I tried:
After several days of search, first I have created a new Model, called UsersModel, the content of this is the same as User Model however what I change is:
protected $table = 'users_data';
protected $fillable = [
*name_value*,
*password_value*,
];
and an extra function to override the default password of breeze or Auth (I guess):
public function getAuthPassword()
{
return $this->password_value;
}
next I went to conf/auth.php
there I specified the Model:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\UsersModel::class,
],
and the table to use:
/*
|--------------------------------------------------------------------------
| Authentication Table
|--------------------------------------------------------------------------
|
| When using the "Database" authentication driver, we need to know which
| table should be used to retrieve your users. We have chosen a basic
| default value but you may easily change it to any table you like.
|
*/
'table' => 'users_data',
after this I went to the view login.blade.php, and changed only the email input (for what I read on different pages, changing the password input will cause different problems, because I would need to make a lot of changes to make it work so the best idea is to override it with getAuthPassword, specified in the model):
new name input:
x-input id="email" class="block mt-1 w-full" type="text" name="name_value" :value="old('name_value')" required autofocus />
After all this I went to LoginRequest (the validation for the login), where I replaced email for name_value
I tried to debug this:
dd(Auth::attempt($this->only('name_value', 'password'), $this->boolean('remember')));
and returns false
I noticed that there's a function in vendor/laravel/ui/auth-back/AuthenticatesUsers
called username(), that returns 'email'
when I saw that I remembered a page that said that this function could override too, so I changed the return value to name_value, and it doesn't do nothing
last, just to clarify,
I don't need the Register site I only need the login page, so for that in the $fillable I didn't add all the columns of the database, just the ones that I need to log in (name_value, password_value)
If anyone could help me and guide me it will be great, because I'am running out of ideas (I could do it with PHP alone, however, I need the ->middleware ['Auth], is there a way to activate the middlware if the user exists?)
So you might have a model named users_data.php. Go inside it and change the code to something like that.
STEP:1
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\users_data as Authenticatable; //Add this line for Auth.
class users_data extends Authenticatable //Extends child from Authenticatable parent class obj.
{
use HasFactory;
protected $fillable = ['column1', 'column2', 'column3', .....];
}
STEP:2
Go to config/auth.php. You may found something like this below.
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
Change the 'model' => App\Models\User::class, to 'model' => App\Models\users_data::class,
This is the main character in this drama that putting your application to users table by default.
STEP:3
Comment off the User.php so that no future conflict create.
Now your application has been diverted to your desired table and ready to login.
I don't think it's good practice to be editing vendor files. We don't push them to version control so other developers won't have your changes. Also, Laravel already has a way to override the username value without editing the vendor files.
Just use the trait in your auth controller like this:
public class MyLoginController {
use AuthenticatesUsers; // or you can also use ThrottlesLogins trait
// then override the username function here
public function username() {
return 'name_value';
}
}
To override the password you can define this on your User model:
public function getPasswordAttribute() {
return $this->attributes['password_value'];
}
public function getAuthPassword() {
return $this->password_value;
}
I haven't tested this but based on the docs this is how you should do it. Also make sure to read this Laravel doc.
I have configured Sluggable behavior on my model as follows:
public function behaviors() {
return [
[
'class' => SluggableBehavior::className(),
'attribute' => 'title',
'ensureUnique' => true,
]
];
}
I need to do:
If the user fills a form field called "URL", this should be used instead of the automatic generated slug.
If user changes the title, they will mark a checkbox if they want the slug updated.
I have found that Sluggable Behaviour has an attribute "immutable" but I do not see a method to manipulate it.
Also I do not see a way to stop automatic generation if value is given.
Any ideas?
For such unusual requirements you should probably extend SluggableBehavior and overwrite getValue() and isNewSlugNeeded() methods to feat your needs.
You may also play with $value property and/or change some behavior settings in beforeValidate() of model:
public function beforeValidate() {
$this->getBahavior('my-behavior-name')->immutable = !$this->changeSlugCheckbox;
return parent::beforeValidate();
}
But custom behavior is much more clean solution.
Here's the code from my AuthController:
public function postRegister(Request $request)
{
$this->validate($request, [
'name' => 'required|min:3',
'email' => 'required|email|unique:users',
'password' => 'required|min:5|max:15',
]);
}
If the validation fails I'm getting redirected to the previous page. Is there a way to pass additional data along with the input and the errors (which are handled by the trait)?
Edit: Actually, the trait does exactly what I want, except the additional data I want to pass. As #CDF suggested in the answers I should modify the buildFailedValidationResponse method which is protected.
Should I create a new custom trait, which will have the same functionality as the ValidatesRequests trait (that comes with Laravel) and edit the buildFailedValidationResponse method to accept one more argument or traits can be easily modified following another approach (if any exists)?
Sure you can, check the example in the documentation:
http://laravel.com/docs/5.1/validation#other-validation-approaches1
Using the fails(); method, you can flash the errors and inputs values in the session and get them back with after redirect. To pass other datas just flash them with the with(); method.
if ($validator->fails()) {
return back()->withErrors($validator)
->withInput()
->with($foo);
}
There are 2 needed functions: set password when registering and change password, if user forgot it. When user signs up, password length must be at least 4 chars; when changes pass - at least 5 chars.
View is common for registration and changing pass. Obviously, also 2 actions exist, in which either scenario 'signup', either 'change' used.
Code snippet in model:
public function rules() {
return [
['password', 'string', 'min' => 4, 'on' => 'signup'],
['password', 'string', 'min' => 5, 'on' => 'change'],
];
}
But I want to do do it via scenarios(). How to do it? I'm a beginner in Yii, so did not understand, when and how to use scenarios(). Thanks.
UPD. I need to use scenarios() for ONE field with ONE rule, but DIFFERENT arguments to this one rule. how to define a scenario in Yii2? - it is NOT my case.
As documentation about scenarios() says: The default implementation of this method will return all scenarios found in the rules() declaration. So generally you do not need to override this method, because it will look for on array keys to set active attributes for current scenario an validate them properly.
So in your case 'on' => 'some scenario' for different validations of the same attribute is exactly what you need.
I've been playing around with Laravel 5's out-of-the-box authentication. When I add fields to the schema and migrate, and then I make them fillable - those added fields don't get inserted into the database, the default fields get inserted but the new ones are blank. The form has been updated to include those new fields.
The console also shows that the form data is being sent correctly.
Am I missing something?
If you look at the file app/Services/Registrar.php, you will find a create function in there:
public function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
You need to modify this function to include your form fields. They will be passed in the $data array.
There is also a validator function in that file to apply validation rules to your fields.
Also, there is a protected $fillable array in the app/User.php model file. You will need to add your custom field names to this array so that they are mass-assignable.
protected $fillable = ['name', 'email', 'password'];
Edited July 9, 2015
This is applicable to v5.0.1. The folder structure has changed going forward. The settings found in the app/Services/Registrar.php file have been moved to app/Http/Controllers/Auth/AuthController.php