I have model like below, where i have defined some static variables (which is not in DB table) then i am trying to fetch those variables but it returns those variables which is in DB table. I am trying to fetch both variables (static variables as well as variables which is in DB table).
Model
class Eforms extends CActiveRecord
{
public $emp_name;
public $current_status;
public $action_type;
public $action_type_extra;
public $common_value = array(
1 => 'Yes',
2 => 'No',
);
public $hr_only_value = array(
1 => 'IT',
2 => 'BOLD',
);
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return 'tbl_eforms';
}
public function rules()
{
return array(
array('form_id', 'required'),
array('form_id, user_id', 'numerical', 'integerOnly'=>true),
array('name_in_form', 'length', 'max'=>500),
array('pdf_name', 'length', 'max'=>1000),
array('emp_name, current_status, action_type, action_type_extra', 'required', 'on'=>'form1'),
array('emp_name, current_status, action_type, action_type_extra','safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, form_id, user_id, name_in_form, email_recipients, pdf_name, created_on', 'safe', 'on'=>'search'),
);
}
................
...............
Controller :
public function actionIndex()
{
$model=new Eforms;
var_dump($model->attributes);exit;
}
If i changes CActiveRecord with CFormModel the it returns the only static variables not the DB related one.
From yii1 doc http://www.yiiframework.com/doc/api/1.1/CActiveRecord#attributes-detail
$model->attributes
Returns all column attribute values. Note, related objects are not
returned.
So you can access to the (related/calculated) var using
$myVar = $model->emp_name;
or
$model->emp_name = 'my_emp_name_value';
Related
I am working on REST API under Yii2, however I have an issue with what the model should return per different actions.
For example in listing actions I need to for example to return 4 attributes and for the details action I need to return 10 attributes from the same model.
What is the best or standard way in Yii2 to implement this.
Example:
/articles
return [id, title, image, date]
/articles/7
return [id, title, image, date, author, likes, last_review]
Thank you
for /article/7 :
public function actionView($id)
{
return User::findOne($id);
}
or
public function actionView($id)
{
return User::find()->select([id, title, image, date, author, likes,last_review])->one();
}
for /articles :
public function actionIndex()
{
return User::find()->select([id, title, image, date])->all();
}
Just write methods in your model.
class MyModel extends ActiveRecord
{
private static $fieldset_1 = [
'id', 'title', 'image', 'date'
];
private static $fieldset_2 = [
'id', 'title', 'image', 'date', 'author', 'likes', 'last_review'
];
public static function get(int $id)
{
if($id > 0) {
return static::find()
->select(self::$fieldset_1)
->where(['id' => $id])
->asArray()
->one();
}
}
public static function getList()
{
return static::find()
->select(self::$fieldset_2)
->asArray()
->all();
}
}
In Controller
class MyController extends Controller{
public function actionListing(){
return $this->asJson(MyModel::getList());
}
public function actionDetails($id){
return $this->asJson(MyModel::get((int)$id));
}
}
in my site if email is registered in my database I would add a error
$this->addError('email' ,'This Email already registered');
but in Update form I do not want see this error
What is a simple way to solve my problem?
this is my users model:
<?php
/**
* This is the model class for table "users".
class Users extends CActiveRecord
{
// public $captcha;
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'users';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('username, email,password', 'required'),
array('roles_id', 'numerical', 'integerOnly'=>true),
array('username, password',
'length',
'max'=>255,
'min'=>4
),
array('email', 'comp_email'),
array('username', 'comp_username'),
array('DataCreated, LastUpdated', 'safe'),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, username, password, DataCreated, LastUpdated, roles_id', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'email'=>'Email',
'username' => 'Username',
'password' => 'Password',
'DataCreated' => 'Data Created',
'LastUpdated' => 'Last Updated',
'roles_id' => 'Roles',
);
}
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('username',$this->username,true);
$criteria->compare('password',$this->password,true);
$criteria->compare('DataCreated',$this->DataCreated,true);
$criteria->compare('LastUpdated',$this->LastUpdated,true);
$criteria->compare('roles_id',$this->roles_id);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Users the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function comp_username($attributes , $params)
{
$username = Yii::app()->db->createCommand()
->select('username')
->from('users')
->queryAll();
$y = (count($username));
for ($x=0;$x<$y;$x++)
{
$usernameE[$x] = $username[$x]['username'];
}
foreach ($usernameE as $u)
{
if($this->username == $u)
{
$this->addError('username' ,'This Username already registered');
break;
}
}
}
public function comp_email($attributes , $params)
{
$email = Yii::app()->db->createCommand()
->select('email')
->from('users')
->queryAll();
$y = (count($email));
for ($x=0;$x<$y;$x++)
{
$emailE[$x] = $email[$x]['email'];
}
foreach ($emailE as $u)
{
if($this->email == $u)
{
$this->addError('email' ,'This Email already registered');
break;
}
}
}
public function getUsernameEmail($id)
{
$emailUsername = Yii::app()->db->createCommand()
->select('*')
->from('users')
->where('id=:id', array(':id'=>$id))
->queryAll();
return $emailUsername;
}
}
and this is my action Update in my controller:
public function actionUpdate($id)
{
$model=$this->loadModel($id);
// Uncomment the following line if AJAX validation is needed
$this->performAjaxValidation($model);
if(isset($_POST['Users']))
{
$model->attributes=$_POST['Users'];
$id=$model->id;
$useremail = Users::model()->getUsernameEmail($id);
$useremailX= $useremail[0]['username'];
$model->username=$useremailX;
$useremailX= $useremail[0]['email'];
$model->email=$useremailX;
$model->password= crypt($model->password,'salt');
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('update',array(
'model'=>$model,
));
}
You can achieve this by applying specific scenarios to your rules.
The Yii WIKI topic on the subject is a good reference.
In your rules, you can specify which scenarios to apply the rule to.
array('email', 'unique','message'=>'Email already exists!', 'on'=>'insert')
Please note that Yii automatically injects specific scenarios, depending on how the object is created.
insert
update
search
You can specify your own custom scenario.
$model = Customer::model()->findByPK($customerID);
$model->scenario = 'purchase';
this is how to validate, you can set error message to be empty.
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
//First parameter is your field name of table which has email value
array('email', 'email','message'=>"The email isn't correct"),
array('email', 'unique','message'=>'Email already exists!'),
);
}
https://stackoverflow.com/a/12778419/1727357
or you can make your own validator:
public function uniqueEmail($attribute, $params)
{
// Set $emailExist variable true or false by using your custom query on checking in database table if email exist or not.
// You can user $this->{$attribute} to get attribute value.
$emailExist = true;
if($emailExist)
{
//do what your want
$this->addError('email','Email already exists');
}
}
User this validation method in rules:
array('email', 'uniqueEmail','message'=>'Email already exists!'),
I created 2 mysql views, and has generated from them 2 model.
MostPopularCoupon
class MostPopularCoupon extends CActiveRecord
{
public function tableName()
{
return 'most_popular_coupon';
}
public function rules()
{
return array(
array('coupon_id', 'required'),
array('coupon_id', 'numerical', 'integerOnly'=>true),
array('left_coupons', 'length', 'max'=>22),
array('stopped_at', 'safe'),
array('left_coupons, coupon_id, stopped_at', 'safe', 'on'=>'search'),
);
}
public function relations()
{
return array(
);
}
public function attributeLabels()
{
return array(
'left_coupons' => 'Left Coupons',
'coupon_id' => 'Coupon',
'stopped_at' => 'Stopped At',
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('left_coupons',$this->left_coupons,true);
$criteria->compare('coupon_id',$this->coupon_id);
$criteria->compare('stopped_at',$this->stopped_at,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
MostActiveCity
class MostActiveCity extends CActiveRecord
{
public function tableName()
{
return 'most_active_city';
}
public function rules()
{
return array(
array('mines', 'length', 'max'=>21),
array('city', 'length', 'max'=>255),
array('mines, city', 'safe', 'on'=>'search'),
);
}
public function relations()
{
return array();
}
public function attributeLabels()
{
return array(
'mines' => 'Mines',
'city' => 'City',
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('mines',$this->mines,true);
$criteria->compare('city',$this->city,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
But due to no experience, don't know how to use them correctly. I need to substitute company_id in the query to get the data of the company belongs to the current user...
Please relock at your design. You would be better off having model classes of City{} and Coupon{}, then have functions for example MostPopularCoupons inside the Coupon class. You could then call them as functions of the class. For example.
In your model
class Coupon extends CActiveRecord
{
// NOTE: This is important for your alias column.
public $couponCount;
public function tableName()
{
return 'coupon';
}
...
public function MostPopularCoupons()
{
$Criteria = new CDbCriteria();
$Criteria->select = ' count(*) as couponCount ';
$lstCoupons = Coupon::model()->findAll($Criteria);
return $lstCoupons;
}
}
Then, in your controller
$coupon_id = 10;
$model1 = Coupon::model()->findByPK((int)$coupon_id);
$lstCouponCount = Coupon::MostPopularCoupons();
Let's say I have a product which can have a colour. Depending on the product type, the colour field may or may not be required.
If colour is always required, I would have the following in the product model
public function rules()
{
return array(
array('colour', 'required')
);
}
However, I want this to be dynamic depending on the product type.
Should this be done in the controller? I would imagine having something like the following in the controller:
public function actionOrder() {
// ....
if ($product->HasColour) {
// set the colour validation to be required
} else {
// set the colour validation to be not required
}
}
What is the best way to approach this?
Thanks
You can use scenario. In the model:
class Model extends CActiveRecord {
// ....
public function rules() {
return array(
array('colour', 'required', 'on' => 'hasColour')
);
}
// ....
}
And in the controller:
public function actionOrder() {
// ....
$model = new Product();
if ($product->HasColour) {
$model->setScenario('hasColour');
}
}
So, required colour will be validated when the model's scenario is hasColour
class LoginForm extends CFormModel
{
public $username;
public $password;
}
$form = new LoginForm();
$form->validatorList->add(
CValidator::createValidator('required', $form, 'username, password')
);
Now $form has two required fields.
One approach is to use a custom validation rule. For example, the rule:
array('colour', 'requiredOnHasColour'),
And then the validator method in the same model class:
public function requiredOnHasColour($attribute, $params) {
if ($this->hasColour && $this->$attribute == null)
$this->addError($attribute, 'Colour is required.');
}
More info: Create your own validation rule
If you want to do more complicated logic, then scenarios might not satisfy your needs. Then you can override method init and do all the logic that define validation rules over there, adding results to $validationRules array. And the in rules() method you just return that array. Something like that:
class Person extends CActiveRecord
{
public function init(){
if( TRUE){
$this->validationRules[] = array('first_name','required');
$this->validationRules[] = array('last_name','required');
}
}
public $validationRules = array(
array('email', 'required'),
array('email, email1, email2, email3', 'email', 'message'=>'Email format is invalid'),
array('email, address, email1, email2, email3', 'length', 'max'=>255),
);
public function rules()
{
return $this->validationRules;
}
}
In your ActiveRecord you can add in any place dynamic validator. For example i overwrite parent method setAttributes and add $this->validatorList->add() depends on selected value in $this->type attribute. Official docs: https://www.yiiframework.com/doc/api/1.1/CValidator
public function setAttributes($values, $safeOnly = true)
{
$result = parent::setAttributes($values, $safeOnly);
if (self::TYPE_PHONE == $this->type) {
$this->validatorList->add(CValidator::createValidator('required', $this, ['phone', 'phonePrefix']));
} elseif (self::TYPE_EMAIL == $this->type) {
$this->validatorList->add(CValidator::createValidator('required', $this, ['email']));
}
return $result;
}
I wish to list some Categories name on my layout main.php page.
Since the layout doesn't have any associated controller or model, I wish to create a static method like this on Category model:
public static function getHeaderModels()
{
// get all models here
return $models;
}
and then in the main layout
<?php
$models = Category::getHeaderModels();
foreach($models as $model)
{
// ....
}
?>
My question is a very basic one:
How can I retrieve those category names from the model ?
Here is the full model:
class Category extends CActiveRecord {
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function tableName() {
return 'category';
}
public function rules() {
return array(
array('parent_id', 'numerical', 'integerOnly' => true),
array('name', 'length', 'max' => 255),
array('id, parent_id, name', 'safe', 'on' => 'search'),
);
}
public function relations() {
return array(
'users' => array(self::MANY_MANY, 'User', 'categories(category_id, user_id)'),
);
}
public function scopes()
{
return array(
'toplevel'=>array(
'condition' => 'parent_id IS NULL'
),
);
}
public function attributeLabels() {
$id = Yii::t('trans', 'ID');
$parentId = Yii::t('trans', 'Parent');
$name = Yii::t('trans', 'Name');
return array(
'id' => $id,
'parent_id' => $parentId,
'name' => $name,
);
}
public function search() {
$criteria = new CDbCriteria;
$criteria->compare('id', $this->id);
$criteria->compare('parent_id', $this->parent_id);
$criteria->compare('name', $this->name, true);
return new CActiveDataProvider(get_class($this), array(
'criteria' => $criteria,
));
}
public static function getHeaderModels() {
//what sintax should I use to retrieve the models here ?
return $models;
}
May be this answer can help you. First you must create a Widget so you can use it more effectively.
First Create a new widget. Let say the name is CategoryWidget. Put this widget under components directory protected/components.
class CategoryWidget extends CWidget {
public function run() {
$models = Category::model()->findAll();
$this->render('category', array(
'models'=>$models
));
}
}
Then create a view for this widget. The file name is category.php.
Put it under protected/components/views
category.php
<?php if($models != null): ?>
<ul>
<?php foreach($models as $model): ?>
<li><?php echo $model->name; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
Then call this widget from your main layout.
main.php
// your code ...
<?php $this->widget('CategoryWidget') ?>
...
If I'm not mistaken, you can also pass any variable available in a view, on to the layout.
You just do it from the view that has your variable.
This is the catch: you need to declare the variable which will receive your value, in the controller, like this:
<?php
class MyController extends Controller
{
public $myvariable;
After this, you will assign your model or whatever to this public variable inside your view,
like this:
$this->myvariable = $modeldata;
After you have assigned your model data to controller's public attribute,
you can easily display it inside your layout e.g.
echo $this->myvariable;
Yii already does this by assigning menu items to column2 sidebar menu, from view, like this:
$this->menu=array(
array('label'=>'List Item', 'url'=>array('index')),
array('label'=>'Manage Item', 'url'=>array('admin')),
);
You can see it in all create/update views that gii crud creates.