I am not sure how to call it other then "persistence". It took me quit a while to figure out why my code was not working on adding an item in my array...
Lets say I have a class with a protected array variable:
protected $fields = array(
'Features', 'Id'
);
I my class i can use this in a method by using: $this->fields
First time all is well.
Now i do change some stuff and i need another field, so I update me $fields to:
protected $fields = array(
'Features', 'Id', 'Title'
);
Strangely, if I now want to use $this->fields, they are "gone". On var_dump it returns NULL. Only if I change the name, the protected var can be used again. But I do not want to change the name of course.
I did empty all cache and reloaded browser etc, but nothing does work. Anyone an idea?
Update: I should add it is in a scheduler class that extends tx_scheduler_Task.
Related
I am having an issue inserting a record into the database. I am a beginner with the Yii framework, so I may have made some stupid mistakes.
This is from the SiteController
public function actionCreatePost(){
$model = new PostForm();
$post = new Post();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$post->body = $model->body;
$post->title = $model->title;
$post->save();
return $this->redirect('index');
}else {
return $this->render('createPost', ['model' => $model]);
}
}
This is from the Post class
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' => new Expression('NOW()'),
],
[
'class' => BlameableBehavior::className(),
'createdByAttribute' => 'id_author',
]
];
}
The issue is that you have created a PostForm class for the form (which is correct) but you are then trying to load the response into the Post class - a completely different class. This won’t work without modification.
If you have a look at the response:
var_dump(Yii:$app->request->post());
You will see the form data is located within the PostForm key. Yii will therefore only load the data into the PostForm class.
The correct solution is therefore to create a savePost() function within the PostForm eg:
public function savePost(){
$model = new Post();
$model->propertyABC = $this->propertyABC
...etc...
$model->save();
So the action would appear as follows:
$model = new PostForm();
If($model->load(Yii::$app->request->post()) && $model->validate()){
$model->savePost();
The other option is to rename the key from PostForm to Post. Yii will then load the data but this is not the best approach as it is a bit obscure.
Hope that helps
I would guess the issue is with the validation.
I can see several issues I will point out. First, I cannot figure out why are you creating a new PostForm, loading the data in it and verifying it, just to dump some values in a new Post and save it. Are there some functions, you are running in the PostForm model, that are triggered by load or verify? If that is not the case, I would suggest dropping one of the models, and using only the other. Usually, that is the Form model. It serves as a link between the ActiveForm and the model handling everything. You can do everything in the createPost() function in the Form model, and then in the controller it will look like
if ($model->load(Yii::$app->request->post())) {
$model->save();
return $this->redirect('index');
}
Second of all, you can dump post->getErrors() before the save to see if there are any errors with the validation. What you can also do, is call $post->save(false) instead. If you pass false to it, it will not trigger $post->validate(), and some errors can be neglected. Please, let me know if there is anything unclear.
I read a lot of things of things in the cookbook or on stackoverflow but I can't find something adapted and clearly explained about how to solve my problem.
I have an SQL request that allows me to find schools that teaches a specific subject. I need to set this SQL request so that when I load the page containing my form, the request is done and I see the result (a list of school) in a multi select form. My best guess is that I need to set it inside my controller, but then again, I'm not even sure of that since it's the first time that I need to do that
I don't know if I should show you any code, so ask if you need to see something!
Thank you in advance
edit Here is my formType
<?php
namespace MissionBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use SocieteBundle\Entity\Societe;
class PublicType extends AbstractType{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('public')
->add('ecolesDispo')
// My goal is to replace 'ecolesDispo' (that is currently a one-to-many)
// by my SQL request.
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MissionBundle\Entity\Mission'
));
}
}
Surely not in the controller. You need to use the "query_builder" attribute when you add the field to the form. Take a look at this example, from the Symfony cookbook : http://symfony.com/doc/current/reference/forms/types/entity.html#using-a-custom-query-for-the-entities
And you should translate your raw SQL query into DQL, so it's database-agnostic.
UPDATE about using a query builder with native SQL : http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/native-sql.html#the-nativequery-class
So something like this following piece of code should work (you'll have to edit some property names and fill the query though)
$builder->add('ecolesDispo', EntityType::class, array(
'class' => 'AppBundle:Ecole',
'query_builder' => function (EntityRepository $er) {
return $er->createNativeQuery('SELECT * FROM ecoles WHERE [...]');
},
'choice_label' => 'title',
));
I'm using the Yii-dynamic-active-record model class to get and put data to various database tables. Now I'd like to use cgridview to quickly build some views of this data, but I'm getting hung-up on writing a search function for this class.
I know that I could always do a foreach loop within the view and make my own html table, but if I could get the Yii way working that would be great for DRY.
*All the db tables have a ID column and this is the only column that really needs to be displayed... if you could get all the columns that would just be bonus points.
Thanks :)
Model
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('ID',$this->ID);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
View
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'entry-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'ID',
),
));
Controller
$tablename=$_GET['tname'];
$table=Entry::forTable($tablename);
$model=$table->findAll();
if(isset($_GET['Entry']))
$model->attributes=$_GET['Entry'];
$this->render('all',array(
'model'=>$model,
));
I am a little confused by what you have done here, however I think I have a solution. First off, in line 3 of your controller code, you call $model = $table->findAll(); this is likely not what you intended, as it will provide you with an ActiveRecord[]. What you want to do is to pass your $table into the gridview. So your controller code would look like this:
$tablename=$_GET['tname'];
$model=Entry::forTable($tablename);
if(isset($_GET['Entry']))
$model->attributes=$_GET['Entry'];
$this->render('all',array(
'model'=>$model,
));
you then need to pass in the table name to the CActiveDataProvider in your model:
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('ID',$this->ID);
return new CActiveDataProvider($this->tableName(), array(
'criteria'=>$criteria,
));
}
now for the "yucky" part, you need to edit the static model method of CActiveRecord to this:
if(isset(self::$_models[$className]))
return self::$_models[$className];
else
{
if(class_exists($className)){
$model=self::$_models[$className]=new $className(null);
$model->_md=new CActiveRecordMetaData($model);
$model->attachBehaviors($model->behaviors());
}
else{
$model = Entry::forTable($className);
}
return $model;
}
This tells it to load from the Entry table when a class of that name does not exist. This practice is discouraged, however its the only way I see of getting around your issue.
How to filter the search results as a combination of checkboxes and dropdown in Yii? I have some categories as checkboxes and budget as dropdown that is listing from database. WIth multiple checkboxes checked and selecting a value from dropdown, how can I filter out the search results.. Is there any better way ?? (My requirement is like in this link. http://www.ebay.in/sch/i.html?_from=R40&_sacat=0&_nkw=pendrives&rt=nc&LH_FS=1 )
I recommend to use a search model. This could look like this:
class SearchProducts extends CFormModel
{
public $minPrice;
public $maxPrice;
public $categories;
// Add a public property for each search form element here
public function rules()
{
return array(
// You should validate your search parameters here
array('minPrice,maxPrice,categories', 'safe'),
);
}
public function search()
{
$criteria = new CDbCriteria;
if(!empty($this->minPrice))
$criteria->addCondition('price > '.(int)$this->minPrice);
if(!empty($this->maxPrice))
$criteria->addCondition('price < '.(int)$this->maxPrice);
if(!empty($this->categories))
$criteria->addInCondition('category_id', $this->categories);
// Add more conditions for each property here
return new CActiveDataProvider('Product', array(
'criteria' => $criteria,
// more options here, e.g. sorting, pagination, ...
));
}
}
In your controller you create a new instance of the search form and assign search variables as usual:
public function actionProducts()
{
$searchModel = new ProductSearch();
if(isset($_POST['ProductSearch']))
$searchModel->attributes = $_POST['ProductSearch'];
$this->render('products', array(
'searchModel' => $searchModel,
));
}
Finally in your view you can now render
A regular Yii form for $searchModel properties which will be your search filter form
A CListView or a CGridView where you set the provider to $searchModel->search() which will be your search results.
For the checkboxes you'd use a checkBoxList:
<?php $this->formCheckBoxList($model, 'categories[]', Category::opts()) ?>
Note the [] which indicates that this should be posted as array. For convenience i usually also implement a static opts() method in some models, which returns a list of id=>name that you can use for dropDownList or checkBoxList options.
This is only the basic pattern. You can easily extend it to create really powerful search forms and result list. Just always keep in mind that you should keep all search related data in another model.
try this extension: ddautofilter
https://bitbucket.org/jwerner/yii-ddautofilter/overview
I want password repeat field in my web-application based on Yii when create and update user. When create I want both fields to be required and when update, user can left these fields empty(password will be the same) or enter new password and confirm it. How can I dot it?
First up, you need to create a new attribute in your model (in this example we call it repeatpassword):
class MyModel extends CActiveRecord{
public $repeatpassword;
...
Next, you need to define a rule to ensure it matches your existing password attribute :
public function rules() {
return array(
array('password', 'length', 'max'=>250),
array('repeatpassword', 'compare', 'compareAttribute'=>'password', 'message'=>"Passwords don't match"),
...
);
}
Now, when a new model is created, the model will not validate unless the password and repeatpassword attributes match. As you mentioned, this is fine for creating a new record, but you don't want to validate the matched password on the update. To create this functionality, we can use model scenarios
We simply change the repeatpassword rule as seen above to have an additional parmanter:
...
array('repeatpassword', 'compare', 'compareAttribute'=>'password', 'message'=>"Passwords don't match",'on'=>'create'),
...
All that is left to do now, is when declaring your model on for the create function, use:
$model = new MyModel('create');
Instead of the normal:
$model = new MyModel;