Laravel create function insert only some of the fields in DB - mysql

I have socialite login for facebook and google. I'm trying to store values in db. Some of them are stored and some no. I think I have tried everything, but can't find problem and solution.
I have function:
public function CreateUser($user, $provider)
{
$authUser = User::where('social_id', $user->id)->first();
if($authUser)
{
return $authUser;
}
$token = $this->generateRandomString();
return User::create([
'name' => $user->name,
'email' => $user->email,
'social' => $provider,
'social_id' => $user->id,
'username' => $this->user_slug($user->name),
'user_token' => $token,
'earnings' => 0,
'user_type' => 'vendor',
'verified' => 1,
]);
}
All Values except social and social_id are stored in database. I tried to store different values in different fields.
For example, if I store $provider value in 'name' field it works. if I try to store $provider value or any other value in 'social' field. DB dosn't store it. Same for 'social_id' field.
I tried saving same value in different fields - It works
I tried to save different values in fields 'social' and 'social_id' - It dosn't work.
I tried to rename these 2 fields - Still dosn't work
If I edit these fields from "phpmyadmin" then it works.
I tried to set fields with different options - It dosn't change anything
DB Photo

you should define which model attributes you want to make mass assignable. You may do this using the $fillable property on the model. For example, let's make the name attribute of our User model mass assignable:
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['social', 'social_id'];
}

Related

Create record with id

I need to import the data from a different database and transfer it to the new database. but the ID information of the members is required for the relationship. I have to carry them too.
Therefore, I have to fill in the ID column which is increased as AUTOINCREMENT.
My Migrate Controller
public function migrate(BackupUser $buser, User $user)
{
$backup_user = $buser->get();
foreach ($backup_user as $bulk) {
$user->create([
'id' => $bulk->uye_id,
'name' => $bulk->uye_nick,
'email' => $bulk->uye_mail,
'password' => $bulk->uye_sifre,
'created_at' => $bulk->uye_tarih
]);
}
}
when I do this, the AUTOINCREMENT increases normally and I can not get the ID information of the previous members.
What is the best way to do this?
By default, the id field for User is not fillable by mass assignment like you're doing. If you want to assign it, you must add 'id' to the array of fillable fields in the user class.
app/User.php
...
class User extends Authenticatable
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'id', 'name', 'email', 'password',
];
...
I think you are trying to take database from joomla or wordpress to laravel.
If I need to do this . my approach would be to store first all base tables without id and then with stored id generated after insertion would be in related tables. So the steps would be
S1: store new `user` and get `id`
S2: relate with other table like `role` with `user_id`
Loop again till last row

Yii2: how to perfect separate validate model and save model?

In which case is it better to use the Validate model? Example: I have two model
AgreementForm
Agreement
When I create data - I use
$model = new AgreementForm();
if ( $model->load( \Yii::$app->request->post() ) && $model->save() ) {
....
}
Code of AgreemtnForm
AgreementForm extemds Model {
......
public function save() {
if(!$this->validate()) {
return null;
}
$model = new Agreement();
$model->content = $this->content;
if( $model->save() ) {
return true;
}
}
But when I update data, I use only that code:
public function actionUpdate( $id ) {
$model = Agreement::findOne( $id );
if( $model->load( \Yii::$app->request->post() ) && $model->save() ){
$this->refresh();
}
else {
return $this->render('update', [
'model' => $model,
]);
}
}
What is the validation model in this case, if I duplicate the validation in another model? Can I only use 1 model?
I will try to explain why you should almost always use a Form model to validate your data, providing some cases:
1) Doing
if( $model->load( \Yii::$app->request->post() ) && $model->save() )
could be dangerous, the user can send post data that he was not supposed to.
eg. Agreement has a userid column that gets id of the user that created it. If a user, sends this field in the post request, he could potentially change its value.
Your form model should define the properties that you expect to be sent.
2) You want to define additional validation for your model based on eg. the user role, the time the Agreement is valid etc.
Lets say you have 2 user roles:
Retailer
Merchant
Retailer can create an Agreement that is 300 characters long and max price 1000, opposed to 700 and 10000 for the merchant.
How do you cope with that?
You create 2 different forms:
$user = Yii::$app->user;
if ($user->can('retailer')) {
$model = new RetailerAgreementForm();
}
else {
$model = new MerchantAgreementForm();
}
if ( $model->load( \Yii::$app->request->post() ) && $model->save() ) {
....
}
In the form models, you can add the additional validation for your fields:
public function rules()
{
return [
['body', 'string', 'max' => 300],
['price', 'integer', 'max'=> 1000],
];
}
Using different forms for this I believe is the best option.
3) Your form model fields do not correspond to Database model columns 1 to 1.
Consider this example:
Your want to save the address of the agreement, street, state and city. You have a list of cities, states and streets.
The only thing you want to do with the address is save it and load it, eg. nobody is going to search per city.
So you just define a column address(type text) in your table and save the data as a JSON.
Your AgreementForm defines the address as separate fields and validates them accordingly and your Agreement model just validates address to be a string.
Do not duplicate your validation between AgreementForm and Agreement models. They should define different validation rules.
Note: Even if you do not render the form in a view and just post some data, it is good to use a form model to get exactly the fields you want to change and if needed, validate them with additional rules. The only case that I could think to just use the DB model directly is when you want to provide just some basic crud operations for your model.

Yii2: Kartik Select2: Initial Value from Model Attribute

I have a Model who has a column (attribute) that stored a comma separated value of IDs.
For Example,
Movie has a column "Genre" that includes more than one genre, e.g.: 40,20,1,3
How can I use Select2 widget to show these values separated when 'multiple' => true
And how can I save them back into comma-separated value as a string. I want a solution that will allow for quick flexibility. I know you can implode and explode the string but seems too much.
Any help appreciated
If I remember correctly pass the default option as part of the $options configuration for the widget:
echo $form->field($model, 'model_attribute_name')->widget(Select2::className(), [
'data' => $data
'options' => [
'class' => 'form-control',
'placeholder' => 'Choose Option...',
'selected' => 40
],
'pluginOptions' => [
'allowClear' => true,
],
])->label('Select2 Form Field');
This is from memory for grain fo salt here. The documentation at http://demos.krajee.com/widget-details/select2 is not very specific about how to do this.
I don't believe you can do that. Select2 sends the data in post as an array, so you would still need to use implode before saving. What i would do instead is in your model class:
class MyModel extends \yii\db\ActiveRecord {
$public myArrayAttribute;
...
public function beforeSave($insert) {
if (parent::beforeSave($insert)) {
$this->myAttribute = implode(',', $this->myArrayAttribute);
return true;
}
return false;
}
public function afterFind() {
parent::afterFind();
$this->myArrayAttribute = explode(',', $this->myAttribute);
}
}
This way myArrayAttribute will hold the values from the comma separated field as an array. Of course you will need to add validation rules for it and use it instead of your other attribute in create and update forms.
if you're displaying a form with already populated fields, maybe you want to update an already existing object, and you want to display the already saved value for the Select2 field, use 'data' => [ 1 => 'Some value' ], where 1 is the value, associated to the value displayed in the form. You can retrieve stuff to put in data from DB beforehand.
Source: https://github.com/kartik-v/yii2-widget-select2/issues/37

Ignore validation on soft deleted models

I have user table. I created a form with 3 fields:
Username
phonenumber
status
The first two fields are unique. Model rules for those fields look like this:
[['Username', 'phonenumber'], 'required'],
[['Username', 'phonenumber'], 'unique'],
I use soft deletion, so when record is deleted, it actually stays in database but status value will change to 0.
The problem is, if I add a record with existing username it shows an error message like "already added". I need to ignore validation if username have a status with value 0.
Use filter property of UniqueValidator
public function rules()
{
return [
...
['username', 'unique', 'filter' => ['<>', 'status', 0]];
...
];
}
It's better to declare constant instead of 0 (something like const STATUS_DELETED = 0) and user it as self::STATUS_DELETED inside of User class. Also you can use != instead of <>.
The last recommendation will be to use username instead of Username to follow convention of naming database table columns.
Read more about ways of declaring filter in official docs.
The ways of setting filter condition as array is described here.
You can use your own function to decide the given username already exists in active status or not. Use this function in "when" property of your unique validation rule.
Have a look :
public function rules()
{
$check = function($model) {
$existActiveUser = User::model()->findByAttributes(array("username"=>$model->username,"status"=>1));
if($existActiveUser)
return true;
else
return false;
};
return [
['Username', 'phonenumber'], 'required'],
[['Username','phonenumber'],'unique','when'=>$check],
}

Yii Query optimization MySQL

I am not very good with DB queries. And with Yii it's more complicated, since I am not very used to it.
I need to optimize a simple query
$userCalendar = UserCalendar::model()->findByAttributes(array('user_id'=>$user->id));
$unplannedEvents = CalendarEvent::model()->findAllByAttributes(array('calendar_id'=> $userCalendar->calendar_id,'planned'=>0));
CalendarEvent table, i.e the second table from which I need records does not have an user_id but a calendar_id from which I could get user_id from UserCalendar, i.e. the first table hence I created a UserCalendar object which is not a very good way as far as I understand.
Q1. What could I do to make it into one.
Q2. Yii does this all internally but I want to know what query it built to try it seperately in MySQL(phpMyAdmin), is there a way to do that?
Thanks.
Q1: You need to have the relation between UserCalendar and CalendarEvent defined in both of your active record models (in the method "relations").
Based on your comments, it seems like you have the Calendar model that has CalendarEvent models and UserCalendar models.
Lets assume your relations in Calendar are:
relations() {
return array(
'userCalendar' => array(self::HAS_MANY, 'UserCalendar', 'calendar_id'),
'calendarEvent' => array(self::HAS_MANY, 'CalendarEvent', 'calendar_id'),
}
In CalendarEvent:
relations() {
return array( 'calendar' => array(self::BELONGS_TO, 'Calendar', 'calendar_id'), );
}
And in UserCalendar:
relations() {
return array( 'calendar' => array(self::BELONGS_TO, 'Calendar', 'calendar_id'), );
}
So to make the link between UserCalendar and CalendarEvent you'll need to use Calendar
$criteria = new CDbCriteria;
$criteria->with = array(
"calendarEvent"=>array('condition'=>'planned = 0'),
"userCalendar"=>array('condition'=> 'user_id =' . $user->id),
);
$calendar = Calendar::model()->find($criteria);
and $calendar->calendarEvent will return an array of calendarEvent belonging to the user
Q2: you can enable web logging so all the db request (and others stuffs) will appear at the end of your page:
Logging in Yii (see CWebLogging)
In your application configuration put
'components'=>array(
......
'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CWebLogRoute',
),
),
),
),