Yii custom CRUD. Extending of common model for different tables - yii

I have project with 20 tables.
Managing of data in all tables will be the same.
Only columns in tables will be different.
So I want to to make common model, common Controller and common view folder for all tables
And after that only extend all this classes for each table
models/Crud.php
<?php
class Crud extends CActiveRecord
{
public $crudTable = '';
public $crudColumns = array();
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return '{{'.$this->crudTable.'}}';
}
public function rules()
{
$rules = array();
foreach ($this->crudColumns as $k=>$v) {
foreach ($v ['rules'] as $vv) {
$rules[] = array_merge(array($k), $vv);
}
if($v['search']) $rules[] = array_merge(array($k), array('safe', 'on'=>'search'));
}
return $rules;
}
public function relations()
{
return array(
);
}
public function attributeLabels()
{
$attributeLabels = array();
foreach ($this->crudColumns as $k=>$v)
{
$attributeLabels[$k] = $v['attributeLabel'];
}
return $attributeLabels;
}
public function search()
{
$criteria=new CDbCriteria;
foreach ($this->crudColumns as $k=>$v)
{
if($v['search'])
{
$criteria->compare($k,$this->$k,(($v['search'] == 'partial') ? 'partial' : false));
}
}
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
models/Country.php
class Country extends Crud
{
public $crudTable = 'country';
public $crudColumns = array(
'id' => array(
'atributeLabel' =>'ID',
'rules' => array (
array('numerical', 'integerOnly'=>true)
),
'search'=>true,
'grid'=>true,
'view'=>true,
'form'=>true,
),
'title' => array(
'atributeLabel' =>'Title',
'rules' => array (
array('required'),
array('length', 'max'=>128)
),
'search'=>'partial',
'grid'=>true,
'view'=>true,
'form'=>true,
),
'code' => array(
'atributeLabel' =>'Code',
'rules' => array (
array('required'),
array('length', 'max'=>2)
),
'search'=>'partial',
'grid'=>true,
'view'=>true,
'form'=>true,
),
'description' => array(
'atributeLabel' =>'Description',
'rules' => array (
array('safe'),
),
'search'=>'partial',
'view'=>true,
'form'=>true,
),
'onoff' => array(
'atributeLabel' =>'Onoff',
'rules' => array (
array('numerical', 'integerOnly'=>true),
),
'search'=>true,
'grid'=>true,
'view'=>true,
'form'=>true,
)
);
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'providers' => array(self::HAS_MANY, 'Provider', 'country_id'),
);
}
}
components/CrudController.php
class CrudController extends CController
{
public $crudModel='';
public $crudModelString='';
public $menu=array();
public $breadcrumbs=array();
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
);
}
public function accessRules()
{
return array(
array('allow', // allow all users to perform 'list' and 'show' actions
'actions'=>array('index', 'view'),
'users'=>array('*'),
),
array('allow', // allow authenticated users to perform any action
'users'=>array('#'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
public function actionIndex()
{
$model=new $this->crudModel('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET[$this->crudModel]))
$model->attributes=$_GET[$this->crudModel];
$this->render('/crud/index',array(
'model'=>$model,
));
}
public function actionView($id)
{
$this->render('/crud/view',array(
'model'=>$this->loadModel($id),
));
}
...
Some code
...
public function loadModel($id)
{
$model=Crud::model()->findByPk($id);
if($model===null)
throw new CHttpException(404,'The requested page does not exist.');
return $model;
}
...
Some code
...}
controllers/CountryController.php
class CountryController extends CrudController
{
public $crudModel='Country';
public $crudModelString='country';
}
It works properly in index action, but ?r=country/view&id=278 send me error
The table "Crud" for active record class "Crud" cannot be found in the database.
How to send table name to static method and make this code to work properly?

Change the loadModel like this:
public function loadModel($id)
{
$model=Crud::model($this->crudModel)->findByPk($id);
if($model===null)
throw new CHttpException(404,'The requested page does not exist.');
return $model;
}
This will load the model of the appropriate table.

Related

How validate parameters in yii2?

How validate parameters in yii2?
I try, but not work validate:
I want validate in BaseData parameters - $key_active = '0', $login = '0'
class MyController extends Controller
{
public function actionMy($key_active = '0', $login = '0')
{
$model = new Mymodel();
if($model->validate()){
return $this->render('yes');
}
return $this->render('no');
}
}
class Mymodel extends Model
{
public $login;
public function rules()
{
return [
[['login'], 'unique', 'targetClass' => '\app\models\Account', 'message'=>'Этот email уже существует.'],
];
}
}
Maybe it's the wrong thing to be validated?
If you want to validate custom data, you need to add custom properties to model and add it rules.
public function actionMy($key_active = '0', $login = '0')
{
$model = new Mymodel();
$model->key_active = $key_active;
$modle->login = $login;
if($model->validate()){
return $this->render('yes');
}
return $this->render('no');
}
then in model
class Mymodel extends Model
{
public $login;
public $key_active;
public function rules()
{
return [
['login', 'unique', 'targetClass' => '\app\models\Account', 'message'=>'Этот email уже существует.'],
['key_active', 'YOUR_VALIDATION_RULES_HERE'],
];
}
}
$model = new Mymodel();
$model->key_active = $key_active;
$model->login = $login;

Yii2 Login from DB (Setting unknown property: app\models\User::password_hash)

I want the user authentication in Yii to be based on user table in my database. This is my User model:
<?php
namespace app\models;
use Yii;
use yii\base\NotSupportedException;
use yii\db\ActiveRecord;
use yii\helpers\Security;
use yii\web\IdentityInterface;
/**
* This is the model class for table "user".
*
* #property integer $id
* #property string $username
* #property string $password
* #property string $title
*/
class User extends \yii\db\ActiveRecord implements IdentityInterface
{
public static function tableName()
{
return 'user';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['username', 'password'], 'required'],
[['username', 'password'], 'string', 'max' => 100]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'UserID',
'username' => 'Username',
'password' => 'Password',
];
}
public static function findIdentity($id) {
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null) {
return static::findOne(['access_token' => $token]);
}
public static function findByUsername ($username){
return static::findOne(['username' => $username]);
}
public static function findbyPasswordResetToken($token)
{
$expire= \Yii::$app->params['user.passwordResetTokenExpire'];
$parts = explode('_', $token);
$timestamp = (int) end($parts);
if ($timestamp + $expire < time()) {
//token expired
return null;
}
return static::findOne(['password_reset_token' => $token ]);
}
public function getId() {
return $this->getPrimaryKey();
}
public function getAuthKey() {
return $this->auth_key;
}
public function validateAuthKey($authKey) {
return $this->getAuthKey() === $authKey;
}
public function validatePassword($password){
$this->password_hash= Yii::$app->security->generatePasswordHash ($password);
}
public function generateAuthKey()
{
$this->auth_key = Yii::$app->security->generateRandomKey();
}
/**
* Generates new password reset token
*/
public function generatePasswordResetToken()
{
$this->password_reset_token = Yii::$app->security->generateRandomKey() . '_' . time();
}
/**
* Removes password reset token
*/
public function removePasswordResetToken()
{
$this->password_reset_token = null;
}
}
But it is giving me this error when I try to login:
Setting unknown property: app\models\User::password_hash
This is actionLogin in siteController:
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->goBack();
} else {
return $this->render('login', [
'model' => $model,
]);
}
}
And this is the code in LoginForm.php:
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
$this->addError($attribute, 'Incorrect username or password.');
}
}
}
/**
* Logs in a user using the provided username and password.
* #return boolean whether the user is logged in successfully
*/
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
} else {
return false;
}
}
I don't know what is wrong, could you please help me fix this?
This is because the column "password_hash" assigned in the function "validatePassword()" doesn't exist in database or is not declared in the User model.
If the password hash is stored in the database in "password" field, then change "validatePassword()" to,
public function validatePassword($password)
{
return $this->password === Yii::$app->security->generatePasswordHash ($password);
}
Here is the solution
1: Declare it in the user controller
* #property string $password_hash
class User extends ActiveRecord implements IdentityInterface
{
public $password;
/**
* #inheritdoc
*/
public static function tableName()
{
return '{{%user}}';
}
public function rules()
{
return [
[['username','email','first_name','last_name','address','password','contact_no','role'], 'safe'],
[['email'], 'unique'],
[['email'], 'email'],
];
}
.
.
....
public function validatePassword($password)
{
return Yii::$app->security->validatePassword($password, $this->password_hash);
}
2: In your LoginForm model rule function add this
['password', 'validatePassword'],
everything else looks okay. Hope this helps you

yii1 Fatal error: Call to a member function photo() on a non-object in modules\announcement\views\default\info.php on line 4

<pre>
<div id="information">
<div id="photo" <?php echo $this->isAdmin() ? 'href="'.$this->settingsUrl().'"':'onclick="window.reload();"';?>>
<?php echo $this->model()->photo('middle');?>
</div>
<div id="more-information">
<?php if($this->isAdmin()):?>
<div id="case-update">
<?php
$caseURL = $this->model()->case ? '/case/record?id='.$this->model()->case_id : $this->settingsUrl();
echo Yii::app()->getModule('external')->icon('pencil',$htmlOptions=array('href'=>$caseURL,'alt'=>'Update case information'),'Edit case');?>
</div>
<?php endif;?>
<table>
<?php if($this->model()->case):?>
<?php foreach($this->model()->case->data as $key => $data):?>
<tr>
<td><?php echo $data->attribute->name;?></td>
<td><?php echo $data->value;?></td>
</tr>
<?php endforeach;?>
<?php endif;?>
</table>
</div>
</div>
</pre>
this is Model
<?php
class Announcement extends CActiveRecord
{
public function tableName()
{
return '{{announcements}}';
}
public function rules()
{
return array(
array('user_id, name, category_id, description, location_id, address, createdate', 'required'),
array('user_id, case_id, category_id, location_id', 'numerical', 'integerOnly'=>true),
array('name, address', 'length', 'max'=>255),
array('id, user_id, case_id, name, category_id, description, location_id, address, createdate', 'safe', 'on'=>'search'),
);
}
public function relations()
{
return array(
'category'=>array(self::BELONGS_TO, 'AnnouncementCategories', 'category_id'),
'case'=>array(self::BELONGS_TO, 'Cases', 'case_id'),
);
}
public function attributeLabels()
{
return array(
'id' => 'ID',
'user_id' => 'User',
'case_id' => 'Case',
'name' => 'Name',
'category_id' => 'Category',
'description' => 'Description',
'location_id' => 'Location',
'address' => 'Address',
'createdate' => 'Createdate',
);
}
public function getUrl(){
return '/announcement?id='.$this->id;
}
public function photo($type='small',$htmlOptions=array()){
$photo = Yii::app()->getModule('files')->image(
$src=array(
'id'=>$this->photoid
),
$size=array(
'type'=>$type,
'method'=>'crop'
),
$htmlOptions,
$this->name
);
return $photo;
}
public function getPhotoId(){
Yii::import('application.modules.files.models.Files');
$model = Files::model()->findByAttributes(array('model'=>get_class($this),'item_id'=>$this->id,'name'=>'generalPhoto'),array('order'=>'id DESC'));
return $model->id;
}
public function photos($count = 6){
Yii::import('application.modules.files.models.Files');
$criteria=new CDbCriteria;
$criteria->compare('model',get_class($this));
$criteria->compare('item_id',$this->id);
$criteria->compare('name','photos');
$criteria->order = 'id DESC';
return new CActiveDataProvider('Files', array(
'criteria'=>$criteria,
'pagination'=>array(
'pageSize'=>$count,
),
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
this is my Controller
class DefaultController extends Controller
{
public function accessRules()
{
return array(
//array('dany',
//'expression'=> "{$this->validate()}",
//),
);
}
public function validate(){
if($this->id()) return false;
return true;
}
public static function id(){
return Yii::app()->getRequest()->getParam('id');
}
public function model(){
return Announcement::model()->findByPk($this->id());
}
public function isAdmin(){
if($this->model()->user_id ==Yii::app()->user->id) return true;
}
public function settingsUrl(){
return '/announcement/record?id='.$this->id();
}
public function actionIndex()
{
$file = CUploadedFile::getInstanceByName('photo');
if($this->isAdmin() && !empty($file)){
Yii::app()->getModule('files')->upload($file,'Announcement',$this->id(),'photos');
$this->redirect($this->model()->url);
}
$this->render('index');
}
}
It seems to be that model() function does not return an object. (Not sure whether you are using it as a function by mistake.) Modify it as below.
public function model($id) {
$model = Announcement::model()->findByPk($this->id());
if ($model === null)
$model = new Announcement();
return $model;
}
Note: In your view you have used the functions in the Controller. This makes tight coupling between Controller and the View. Ideally Views should be created to use the data sent from the Controller.
In this sort of a situation what we do is create a model object in the Controller and pass it to the View. Check following for an example.
In Controller:
public function actionUpdate($id) {
$data=$this->loadModel($id);
$this->render('update',array('model'=>$data));
}
/**
* Returns the data model based on the primary key given in the GET variable.
* If the data model is not found, a new model is returned.
* #param integer $id the ID of the model to be loaded
* #return MyExampleModel the loaded model
*/
public function loadModel($id) {
$model = MyExampleModel::model()->findByPk($id);
if ($model === null)
$model = new MyExampleModel();
return $model;
}
View:
<?php $model->photo('middle');?>

Creating dynamic attributes and properties in model class

I used code
$sql="SELECT 'Name' FROM XXX";
$names =$connection->createCommand($sql)->query()->readAll();
$myDynamicObject = new DynamicModel($names);
class DynamicModel extends CModel
{
protected $_members = array();
public function __construct($nameFields)
{
foreach ($nameFields as $member) {
$this->_members[$member] = null;
}
parent::__construct();
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
$allMembers = implode(', ', array_keys($this->_members));
return array(
array($allMembers, 'required'),
);
}
public function __get($attribute)
{
if (in_array($attribute, array_keys($this->_members))) {
return $this->_members[$attribute];
} else {
return parent::__get($attribute);
}
}
public function __set($attribute, $value)
{
if (in_array($attribute, array_keys($this->_members))) {
return $this->_members[$attribute] = $value;
} else {
return parent::__set($attribute, $value);
}
}
public function getAttributes()
{
return $this->_members;
}
public function setAttributes($attributes)
{
$this->_members = $attributes;
}
}
i print this model in controller but
not nothing coming..server error came..
" More
An unexpected condition was encountered while the server was attempting to fulfill the request.
Error code: 500"
CModel is an abstract class and you need to at least implement the attributeNames() function.
In your case I guess the following should suffice:
public function attributeNames()
{
return array_keys($this->_members);
}

Create AccessRules in modules Yii Framework

in modules\administrator\components\AdminController:
class AdminController extends CController
{
public function filters()
{
return array('accessControl');
}
public function accessRules()
{
return array(
array('deny', 'users' => array('*')),
);
}
}
in modules\administrator\controllers\Sitecontroller:
class SiteController extends AdminController
{
public function actionIndex()
{
$this->render('index');
}
public function actionLogin()
{
$this->render('login');
}
}
but when visit mydomain.site/administrator/site/index, it does not redirect to mydomain.site/administrator/site/login which redirects to mydomain.site/site/login (default login), I want it redirects to mydomain.site/administrator/site/login
can someone help me?
Set CWebUser::$loginUrl before filters are invoked:
class AdminModule extends CWebModule
{
public function init()
{
$this->setImport(array(
'admin.models.*',
//'application.models.*',
'admin.components.*',
));
}
public function beforeControllerAction($controller, $action)
{
if(parent::beforeControllerAction($controller, $action))
{
// this method is called before any module controller action is performed
// you may place customized code here
if ( !Yii::app()->user->checkAccess('admin') ) {
if(Yii::app()->user->isGuest){
$url = Yii::app()->createUrl(Yii::app()->user->loginUrl);
Yii::app()->user->returnUrl = Yii::app()->createUrl('/admin/');
Yii::app()->request->redirect($url);
}
else {
throw new CHttpException(403,'Have no permission');
}
}
return true;
}
else
return false;
}
}
Try this:
array('allow', // allow authenticated user to perform below actions
'actions'=>array('index'),
'users'=>array('#'),
),
array('deny', // deny all users
'users'=>array('*'),
),
This way, when the url is requested for site/index and as we have set index to be allowed only for authenticated users, the request will be redirected to site/login (or default login).
I hope it helps.