I'm new to Yii Framwork, I have used the steps from Multiple-database support in Yii to connect different database , its helped me lot.
but Css is not loaded, normal HTML content is displaying in browser when I'm opening the index.php
What changes is require to load the CSS after changing the GetDbConnection() in modules.
my Ad.php code from models
<?php
class Ad extends MyActiveRecord
{
public $password;
public $repassword;
public function getDbConnection()
{
return self::getCCDbConnection();
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
....
}
Thanks in Advance
This does not solve your css problem, however, this is the right way to use multiple dbs in yii.
This is the right way to use multiple db's in yii mvc:
Let's say that i have multiple db's and I use them to store urls.
From time to time I need to change the db.
So, I have the model generated by using gii and on top of that I have class that extends and overwrites some of methods/functions.
UrlSlaveM extends UrlSlave wich extends CActiveRecord
as default, in UrlSlave I will connect to my first db
I always use UrlSlaveM when I insert new data, so that I can overwrite the following function:
public function getDbConnection() {
return Yii::app()->db1;
}
here is a full SlaveUrl model:
<?php
/**
* This is the model class for table "url".
*
* The followings are the available columns in table 'url':
* #property string $id
* #property integer $instance_id
* #property integer $website_id
* #property string $link
* #property string $title
* #property integer $created
* #property integer $updated
* #property integer $status
*/
class UrlSlave extends CActiveRecord {
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return UrlSlave the static model class
*/
public static function model($className = __CLASS__) {
return parent::model($className);
}
/**
* #return CDbConnection database connection
*/
public function getDbConnection() {
return Yii::app()->db1;
}
/**
* #return string the associated database table name
*/
public function tableName() {
return 'url';
}
/**
* #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('instance_id, website_id, link, title, created, updated, status', 'required'),
array('instance_id, website_id, created, updated, status', 'numerical', 'integerOnly' => true),
array('link, title', 'length', 'max' => 255),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, instance_id, website_id, link, title, created, updated, status', 'safe', 'on' => 'search'),
);
}
/**
* #return array relational rules.
*/
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(
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels() {
return array(
'id' => 'ID',
'instance_id' => 'Instance',
'website_id' => 'Website',
'link' => 'Link',
'title' => 'Title',
'created' => 'Created',
'updated' => 'Updated',
'status' => 'Status',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search() {
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria = new CDbCriteria;
$criteria->compare('id', $this->id, true);
$criteria->compare('instance_id', $this->instance_id);
$criteria->compare('website_id', $this->website_id);
$criteria->compare('link', $this->link, true);
$criteria->compare('title', $this->title, true);
$criteria->compare('created', $this->created);
$criteria->compare('updated', $this->updated);
$criteria->compare('status', $this->status);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
));
}
}
and here is the full UrlSlaveM model:
<?php
class UrlSlaveM extends UrlSlave {
const ACTIVE = 1;
const INACTIVE = 0;
const BANNED = -1;
public static function model($className = __CLASS__) {
return parent::model($className);
}
public function rules() {
$parent_rules = parent::rules();
$rules = array_merge(
$parent_rules, array(
array('link', 'unique'),
));
return $rules;
}
public static $server_id = 1;
public static $master_db;
public function getDbConnection() {
//echo __FUNCTION__;
//die;
//echo 111;
self::$master_db = Yii::app()->{"db" . self::$server_id};
if (self::$master_db instanceof CDbConnection) {
self::$master_db->setActive(true);
return self::$master_db;
}
else
throw new CDbException(Yii::t('yii', 'Active Record requires a "db" CDbConnection application component.'));
}
}
now, by setting $server_id to 1 or 2 or 3 ... you are able to connect to another db
please set the value of $server_id as UrlSlaveM::$server_id = 2; before you add data!
public static $server_id = 1;
public static $master_db;
also, in the main config file, set like this:
'db' => array(
'connectionString' => 'mysql:host=localhost;dbname=dvc',
'emulatePrepare' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8',
),
'db2' => array(
'connectionString' => 'mysql:host=localhost;dbname=dvc2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'tablePrefix' => '',
'class' => 'CDbConnection' // DO NOT FORGET THIS!
),
'db1' => array(
'connectionString' => 'mysql:host=localhost;dbname=dvc1',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'tablePrefix' => '',
'class' => 'CDbConnection' // DO NOT FORGET THIS!
),
Related
I am newbie in YII framework. I have installed correctly and created a Test Controller & Test Model using GII extension of YII. I have created a method in Model and want to access in Controller but unable to access.
Test controller
<?php
namespace app\controllers\api;
use Yii;
use app\models\api\Test;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class TestController extends \yii\web\Controller
{
public $modelClass = 'app\models\api\Test';
private $model;
public function filters(){
return array(
'accessControl', // perform access control for CRUD operations
array(
'RestfullYii.filters.ERestFilter +
REST.GET, REST.PUT, REST.POST, REST.DELETE, REST.OPTIONS'
),
);
}
public function actions(){
return array(
'REST.'=>'RestfullYii.actions.ERestActionProvider',
);
}
public function accessRules(){
return array(
array('allow', 'actions'=>array('REST.GET', 'REST.PUT', 'REST.POST', 'REST.DELETE', 'REST.OPTIONS'),
'users'=>array('*'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
protected function loadModel( $id = null )
{
if($this->model===null)
{
if($id!==null)
$this->model=TestModel::model()->findByPk($id);
}
return $this->model;
}
public function actionIndex()
{
//return $this->render('index');
//$array = $modelClass::model()->listUserData();
//$array = Yii::app()->model()->listUserData();
//$array = $modelClass->listUserData();
// echo TestModel()->listUserData();
print "<pre>";print_r($this->model->listUserData());
exit;
}
}
Test Model
<?php
namespace app\models\api;
use Yii;
/**
* This is the model class for table "users".
*
* #property integer $id
* #property string $username
* #property string $password
* #property string $email
* #property string $activkey
* #property integer $createtime
* #property integer $lastvisit
* #property integer $superuser
* #property integer $status
*/
class Test extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'users';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['username', 'password', 'email'], 'required'],
[['createtime', 'lastvisit', 'superuser', 'status'], 'integer'],
[['username'], 'string', 'max' => 50],
[['password', 'email', 'activkey'], 'string', 'max' => 128],
[['username'], 'unique'],
[['email'], 'unique'],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'username' => 'Username',
'password' => 'Password',
'email' => 'Email',
'activkey' => 'Activkey',
'createtime' => 'Createtime',
'lastvisit' => 'Lastvisit',
'superuser' => 'Superuser',
'status' => 'Status',
];
}
public static function listUserData(){
$UserData = Test::model()->findAll('status = "0"');
return $UserData;
}
}
i tried to search on forum but not able to resolve, please can you help me to resolve ?
Thanks in advance.
In the controller.
use pathtotestmodel/Test
public function actionIndex()
{
$model = new Test();
$userdata = $model->listUserData();
}
OR
public function actionIndex()
{
$userdata = Test::listUserData();
}
Its simple create a instance of Model and then call the required function
like
public function actionIndex()
{
$model = new Test();
print "<pre>";print_r($model->listUserData());
exit;
}
Try this
public static function listUserData(){
$UserData = Test::findAll(['status' =>0]);//in Yii2
//$UserData = Test::model()->findByAttributes(array( 'status' => 0 )); in yii 1.1
return $UserData;
}
Can implement dynamic validation on element level? I used this example to implement validation of one element dependent on the value of the other element. But for this purpose I'll need to implement this for every single form where I use this element (comment) with this validation. I have many forms like that. Is there way to do the following:
to take this filter/validation logic to the element level using some kind of "data-comment-for" attribute and retrieving the value of the element on which it depends from the parent form.
This is my current code (but I need to have it for every form now. It does not look elegant at all) :
class CompetencyAdvanceHumanRightsAndJusticeFormFilter extends InputFilter
{
public function isValid($context = null)
{
$figradeCommentName = 'applJusticeFIGrade'.'Comment';
$forGrade = $this->get('applJusticeFIGrade');
$gradeComment = $this->get($figradeCommentName);
$applJusticeFIGradeRawValue = $forGrade->getRawValue('applJusticeFIGrade');
if(is_numeric($applJusticeFIGradeRawValue)){
$gradeValue = intval($applJusticeFIGradeRawValue);
}else{
$gradeValue = $applJusticeFIGradeRawValue;
}
if ($gradeValue != 'na' && $gradeValue > 0) {
$gradeComment->setRequired(true);
$validatorChain = new Validator\ValidatorChain();
$validatorChain->attach(
new Validator\NotEmpty(),
true
);
$gradeComment->setValidatorChain($validatorChain);
}
return parent::isValid($context);
}
public function __construct(){
$this->add(array(
'name' => 'id',
'required' => true,
'filters' => array(
array('name' => 'Int'),
),
));
$this->add(array(
'name' => 'studEvalId',
'required' => true,
'filters' => array(
array('name' => 'Int'),
),
));
}
}
EDIT:
I added code for the custom element to the question. There are some "leftovers" of my attempts to place this logic to the element level.
Comment Element
class Comment extends Element implements InputProviderInterface
{
/**
* #var ValidatorInterface
*/
protected $validator;
// set its type
protected $attributes = array(
'type' => 'comment'
);
public function init()
{
if (null === $this->validator) {
$validator = new StringLength();
$validator->setMax(10);
$validator->setMessage('The comment should not exceed 1000 letters!', StringLength::INVALID);
$this->validator = $validator;
}
}
/**
* Get a validator if none has been set.
*
* #return ValidatorInterface
*/
public function getValidator()
{
return $this->validator;
}
/**
* #param ValidatorInterface $validator
* #return $this
*/
public function setValidator(ValidatorInterface $validator)
{
$this->validator = $validator;
return $this;
}
/**
* remove require and validator defaults because we have none
*
* #return array
*/
public function getInputSpecification()
{
// return array(
// 'name' => $this->getName(),
// 'required' => false,
// 'validators' => array(
// $this->getValidator(),
// ),
// 'filters' => array(
// new FIGradeCommentDynamicBufferFilter()
// ),
// );
return array(
'name' => $this->getName(),
'required' => false,
'filters' => array(
array('name' => 'Zend\Filter\StringTrim'),
),
'validators' => array(
$this->getValidator(),
),
);
}
// tell it where to find its view helper, so formRow and the like work correctly
public function getViewHelperConfig()
{
return array('type' => '\OnlineFieldEvaluation\View\Helper\FormComment');
}
}
You could make a base abstract input-filter class and an interface and make all your form filters extend the base class that implements the interface with the methods you expect inside your form classes to make the thing work correctly.
Make an interface with the methods:
interface GradeCommentFormFilterInterface()
{
protected function getGradeInput();
protected function getCommentInput();
}
Then you move the common code to your base class:
abstract class BaseGradeCommentFormFilter extends InputFilter implements GradeCommentFormFilterInterface
{
protected function getGradeInput()
{
return $this->get(static::GRADE_NAME);
}
protected function getCommentInput()
{
return $this->get(static::GRADE_NAME . 'Comment');
}
public function isValid($context = null)
{
$gradeInput = $this->getGradeInput();
$commentInput = $this->getCommentInput();
$rawValue = $this->getRawValue($gradeInput);
if(is_numeric($rawValue))
{
$gradeValue = intval($rawValue);
}
else
$gradeValue = $rawValue;
if ($gradeValue != 'na' && $gradeValue > 0) {
$commentInput->setRequired(true);
$validatorChain = new Validator\ValidatorChain();
$validatorChain->attach(
new Validator\NotEmpty(),
true
);
$commentInput->setValidatorChain($validatorChain);
}
return parent::isValid($context);
}
}
Now you can use your abstract class like this:
class CompetencyAdvanceHumanRightsAndJusticeFormFilter extends BaseGradeCommentFormFilter
{
const GRADE_NAME = 'applJusticeFIGrade';
//... other code
}
I quickly tried to make it work for your case, but this isn't tested, and probably there are ways to optimize this, but it gives you an idea of what you can do.
I am trying to get information from two models that are related, displayed in one view.
So what I am trying to accomplish is have the index view to show the list of people, if I then go into detail view of that particular person I want a list of attributes relevant to that person to appear.
I have the database setup so that when I create a new person a default row gets inserted into the attributes table with the id of the person under the column called person_id.
See my two model classes
People:
class People extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'people';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['dob', 'CURDATE'], 'safe'],
[['age'], 'integer'],
[['firstname', 'surname'], 'string', 'max' => 50]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'firstname' => 'Firstname',
'surname' => 'Surname',
'dob' => 'Dob',
'age' => 'Age',
'CURDATE' => 'Curdate',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getId0()
{
return $this->hasOne(Attributes::className(), ['person_id' => 'id']);
}
}
Attributes:
class Attributes extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'attributes';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['haircolor', 'eyecolor', 'weight', 'height', 'person_id'], 'required'],
[['weight', 'height', 'person_id'], 'integer'],
[['haircolor', 'eyecolor'], 'string', 'max' => 50]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'haircolor' => 'Haircolor',
'eyecolor' => 'Eyecolor',
'weight' => 'Weight',
'height' => 'Height',
'person_id' => 'Person ID',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getPeople()
{
return $this->hasOne(People::className(), ['id' => 'person_id']);
}
}
I have generated CRUD through Gii for both of these models.
What I would like to know is how to setup my people controller and people view so that this may work properly.
Just to recap, my index.php view will just show the list of people, if a record exists, you can view that specific record, if you view the record - which will be the view.php file, I want to show the attributes(These will be the default values) of that particular person where the id of the person is the same as the person_id in the attributes table
The user will then be able to update the attributes relating to that person.
Kind Regards.
Here an example :
public function actionCreate()
{
$user = new User;
$profile = new Profile;
if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post()) && Model::validateMultiple([$user, $profile])) {
$user->save(false); // skip validation as model is already validated
$profile->user_id = $user->id; // no need for validation rule on user_id as you set it yourself
$profile-save(false);
return $this->redirect(['view', 'id' => $user->id]);
} else {
return $this->render('create', [
'user' => $user,
'profile' => $profile,
]);
}
}
More informations :
http://www.yiiframework.com/forum/index.php/topic/53935-solved-subforms/page__p__248184
http://www.yiiframework.com/doc-2.0/guide-input-tabular-input.html
To display related information in a view, you get the best performance with eager loading. I'll provide an example:
public function actionView($id)
{
$model = Person::find()
->where(['id' => $id])
->with('id0')
->one();
return $this->render('view', [
'model' => $model,
]);
}
Now i see that your relation in Person Model is called getId0, you can for readability change that to getAttribs(), and change to ->with('attribs') but that is just a digression :)
EDIT: as #soju commented, attributes is not possible to use as a relation name, and that is why gii has given it the name getId0. Attribs or something more informative can be helpful on readability.
If you want to show the results in a widget, like GridView or ListView, you can follow the guide here:
http://www.ramirezcobos.com/2014/04/16/displaying-sorting-and-filtering-model-relations-on-a-gridview-yii2/
EDIT2: as #soju commented, guide is possibly outdated. Read official documents aswell.
http://www.yiiframework.com/doc-2.0/guide-output-data-widgets.html#working-with-model-relations
If you want to create your own view, you can access the values with $model->id0->haircolor or, if you rename the relation, $model->attribs->haircolor just like you would any other attribute.
Remember: using GridView / ListView requires the table name from the db when displaying, like 'attributes.eyecolor', but the $model->id0 requires the relation name from the model, without the 'get' in front, and with lower case.
I was figuring out how to insert a hasMany entry using Laravel 4
Author.php module
class Author extends Eloquent\LaravelBook\Ardent\Ardent
{
public static $rules = array(
'title' => 'required',
'last_name' => 'required',
'first_name' => 'required',
);
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'authors';
public function abstraction()
{
return $this->belongsTo('Book','book_id');
}
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getRegId()
{
return $this->getKey();
}
}
Book.php Module
class Book extends Eloquent\LaravelBook\Ardent\Ardent
{
public static $rules = array(
'title' => 'required',
'authors' => 'required',
);
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'abstracts';
public function author()
{
return $this->hasMany('Author');
}
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getRegId()
{
return $this->getKey();
}
}
My controller
$r = new Book();
$r->title = Input::get('title');
$r->authors = Input::get('authors');
$r->affiliation = Input::get('affiliation');
$r->keywords = Input::get('keywords');
$r->summary = Input::get('summary');
$r->save();
$authors = new Author();
$authors_array = array(
array('name' => 'Arun1', 'affiliation' => 'aff_arun'),
array('name' => 'Arun2', 'affiliation' => 'aff_arun'),
array('name' => 'Arun3', 'affiliation' => 'aff_arun3'),
array('name' => 'Arun4', 'affiliation' => 'aff_arun'),
);
$authors->book()->associate($r);
$authors->save($authors_array);
I'm getting one null record on authors table which pointed to the book and other 3 record that I inserted here without any pointing to the book.
First off I believe this is wrong schema, since probably one author could write more than a single book.
So I suggest you define many-to-many (belongsToMany) relation for this instead.
Anyway here is solution to your problem:
// I wonder why you call the book $r ?
$r = new Book;
...
$r->save();
$authors_array = array(...);
foreach ($authors_array as $author)
{
$r->author()->save(new Author($author));
// you need $fillable/$guarded on Author model or it will throw MassAssignementException
}
Another suggestion: rename the relation to authors so it is meaningful and you won't catch yourself trying to treat it like a single model (while it always returns the Collection)
I have an Account Model which has some properties and relations, and i have an Reseller model.
The point is that a reseller is actually an account only it has the possibility to have accounts beneath it.
What is the best approach to implement this,
at first i had a special Reseller class with relations between them, but actually i just want an accounts class which if the account is a reseller uses the reseller class.
Account model
<?php
/**
* This is the model class for table "account".
*
* The followings are the available columns in table 'account':
* #property string $id
* #property string $reseller_id
* #property string $name
* #property string $invoice_id
* #property boolean $is_reseller
*
* The followings are the available model relations:
* #property Reseller $reseller
* #property Contact[] $contacts
* #property Domain[] $domains
* #property HostingAccount[] $hostingAccounts
* #property User[] $users
*/
class Account extends CActiveRecord {
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return Account the static model class
*/
public static function model($className = __CLASS__) {
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName() {
return 'account';
}
/**
* #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('name', 'required'),
array('id, reseller_id', 'length', 'max' => 40),
array('name', 'length', 'max' => 45),
array('invoice_id', 'length', 'max' => 10),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, reseller_id, name, invoice_id', 'safe', 'on' => 'search'),
);
}
/**
* #return array relational rules.
*/
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(
'reseller' => array(self::BELONGS_TO, 'Reseller', 'reseller_id'),
'contacts' => array(self::HAS_MANY, 'Contact', 'account_id'),
'domains' => array(self::HAS_MANY, 'Domain', 'account_id'),
'hostingAccounts' => array(self::HAS_MANY, 'HostingAccount', 'account_id'),
'users' => array(self::HAS_MANY, 'User', 'account_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels() {
return array(
'id' => 'ID',
'reseller_id' => 'Reseller',
'name' => 'Name',
'invoice_id' => 'Invoice',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search() {
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria = new CDbCriteria;
$criteria->compare('id', $this->id, true);
$criteria->compare('reseller_id', $this->reseller_id, true);
$criteria->compare('name', $this->name, true);
$criteria->compare('invoice_id', $this->invoice_id, true);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
));
}
/**
* Adds UUID before the item is saved
*
*/
public function beforeSave() {
if ($this->isNewRecord)
$this->id = new CDbExpression('UUID()');
return parent::beforeSave();
}
}
Reseller Model
<?php
class Reseller extends Account
{
/**
* #return array relational rules.
*/
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(
'reseller' => array(self::BELONGS_TO, 'Reseller', 'reseller_id'),
'contacts' => array(self::HAS_MANY, 'Contact', 'account_id'),
'domains' => array(self::HAS_MANY, 'Domain', 'account_id'),
'hostingAccounts' => array(self::HAS_MANY, 'HostingAccount', 'account_id'),
'users' => array(self::HAS_MANY, 'User', 'account_id'),
'accounts' => array(self::HAS_MANY, 'Account', 'reseller_id'),
'account' => array(self::BELONGS_TO, 'Account', 'account_id'),
);
}
}
First keep in mind that ActiveRecord != models its easy to get confused, beware!
Also check this post
Ok now, you can have some factory method that gives you the class you need, Account or Reseller, depending on your logic, if not all acounts can be resellers you may also need some way to determine this. like a "is_reseller" column or similar.
In the end i made a relation from accounts to itself and solved it.
/**
* #return array relational rules.
*/
public function relations() {
return array(
'reseller' => array(self::BELONGS_TO, 'Account', 'account_id'),
'users' => array(self::HAS_MANY, 'User', 'account_id'),
'accounts' => array(self::HAS_MANY, 'Account', 'account_id'),
);
}
I used a extended classes to a models to implemented a diferents methos and a unique prerequisite is add this function in a new class:
public static function model($className=__CLASS__){
return parent::model($className);
}