I have these classes:
Model:
namespace app\models;
use \yii\db\ActiveRecord;
class MyModel extends ActiveRecord {
public function rules() {
return [
[['name'], 'required'],
[['id'], 'default', 'value' => null]
];
}
}
Controller:
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\MyModel;
class MymodelController extends Controller{
public function actionEdit($id = null){
$model = new MyModel();
if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->save()) {
Yii::$app->session->setFlash('msg', 'Model has been saved with ID ' . $model->id);
}
return $this->render('edit', [
'model' => $model
]);
}
}
View:
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php if(Yii::$app->session->hasFlash('msg')): ?>
<div class="alert alert-success"><?= Yii::$app->session->getFlash('msg'); ?></div>
<?php endif; ?>
<?php $form = ActiveForm::begin(); ?>
<?= Html::activeHiddenInput($model, 'id'); ?>
<?= $form->field($model, 'name') ?>
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end(); ?>
I want to use this view for editing and for inserting. Editing does not work as it is, because I am creating a new object instead of changing an existing one in the Controller. I am unsure what is the best practice here or if I am missing some already existing built in function?
Should I create my own model class and implement the logic model <-> active record in the controller
or
Should I just re query the database with the $model->id in the controller and copy all properties if needed?
you should use two actions for edit and insertion
for edit first find the model
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('edit', [
'model' => $model,
]);
}
protected function findModel($id)
{
if (($model = MyModel::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
if you use CRUD for generating your controller you don't have to write these actions.
For CRUD (Create, Read/View, Update and delete) you can use gii. This power tool generate automatically all you need for an ActiveRecord, Controller with the basic action (index, view, create, update, delete, find) and related view.
In gii you first genearate model class and then generate CRUD for this class.
But the most informant things all this information are coerently related each other
see this doc is very useful and the best pratice for Yii2 is embetted in the tool
http://www.yiiframework.com/doc-2.0/guide-start-gii.html
In Your Create action:
public function actionCreate()
{
$model = new Yourmodel();
if ($model->load(Yii::$app->request->post())) {
if($model->save()){
return $this->redirect(['view']);
}
}
return $this->render('create', [
'model' => $model,
]);
}
In your Update action:
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post())) {
if($model->save()){
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('update', [
'model' => $model,
]);
}
Related
I can't insert data in the database. I'm using yii2 advanced.
I have 3 tables: the default user table, post, and category. Each post has one category, and one category can have many posts.
But when I click on 'Save' in my create form - nothing happens, the page just refreshes. The post table is still empty.
Here's PostController
namespace frontend\controllers;
use Yii;
use yii\web\Controller;
use frontend\models\CreateForm;
use frontend\models\Category;
use yii\helpers\ArrayHelper;
class PostController extends Controller
{
public function actionCreate()
{
if(Yii::$app->user->isGuest)
{
return $this->redirect(['/site/login']);
}
$model = new CreateForm();
$category = Category::find()->all();
$items = ArrayHelper::map($category, 'id', 'name');
if ($model->load(Yii::$app->request->post()))
{
if ($model->save())
{
Yii::$app->session->setFlash(
'success',
true
);
return $this->refresh();
} else
{
Yii::$app->session->setFlash(
'success',
false
);
}
}
return $this->render('create', [
'model' => $model,
'items' => $items
]);
}
This is CreateForm model
namespace frontend\models;
use yii\base\Model;
use frontend\models\Post;
use Yii;
class CreateForm extends Model
{
public $category;
public $title;
public $content;
public function attributeLabels()
{
return [
'category' => 'Category',
'title' => 'Title',
'content' => 'Content',
];
}
public function save()
{
$post = new Post();
$post->user_id = Yii::$app->user->id;
$post->category_id = $this->category;
$post->title = $this->title;
$post->content = $this->content;
$post->created_at = time();
}
}
And this the view
use yii\bootstrap\ActiveForm;
use yii\bootstrap\Html;
$form = ActiveForm::begin();
echo $form->field($model, 'category')->dropDownList($items);
echo $form->field($model, 'title')->textInput();
echo $form->field($model, 'content')->textInput();
echo Html::submitButton('Save', ['class' => 'btn btn-primary']);
ActiveForm::end();
What am I doing wrong, I can't understand
Ok. All I had to do is to add $post->save() in the end of my save method in CreateForm.
Yii2 how to implementation Optimistic Locks.
I'm trying to follow this official doc.
I thought I carefully follow the step.
but still error :
Here my procedure.
Create a column in the DB "version defualt velue = '0'
2.Model.php
use yii\behaviors\OptimisticLockBehavior;
class OptimisticTest extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'optimistictest';
}
public function rules()
{
return [
[['version'], 'required'],
[['created_by', 'updated_by','version'], 'integer'],
];
}
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'value' => new Expression('NOW()'),
],
[
'class' => BlameableBehavior::className(),
],
[
'class' => OptimisticLockBehavior::className(), //'getLockAttribute' =>$this->version
],
];
}
}
myController.php
public function actionUpdate($id)
{
$model = $this->findModel($id);
$tempDocs = $model->docs;
$modelRunning = $this->findModelRunning($model->running_id);
$model->scenario = 'update';
try {
if ($model->load(Yii::$app->request->post()) &&
$modelRunning->load(Yii::$app->request->post()) &&
Model::validateMultiple([$model,$modelRunning]))
{
if($modelRunning->save())
{
$this->CreateDir($model->ref);
$model->docs = $this->uploadMultipleFile($model,$tempDocs);
$model->save();
}
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
'modelRunning' => $modelRunning,
]);
}
} catch (StaleObjectException $e) {
// logic to resolve the conflict
Yii::$app->session->setFlash('danger',Yii::t('app', 'Record can not be updated, there is a user associated with it'));
return $this->redirect(['index']);
}}
Error is From Model.php in public function behaviors()
in step 1. Override this method to return the name of this column.
how to override this method.
what i'm missing.
Overriding optimisticLock() method means, that you have to implement the method in your model so it can be used instead of default implementation.
Your model should look like this
class OptimisticTest extends \yii\db\ActiveRecord
{
//... your other methods in model
public function optimisticLock()
{
//this method should return the name of version attribute
return 'version';
}
}
I am new to Yii so i decided to write a simple login script just to put to test what i have learnt so far.
For some reasons my code doesn't work as it should.
Ideally if username and password exist, it ought to redirect to the index view and also and if it doesn't exist it ought to redirect to the login view.
If username and password exist it redirects as it ought to and it also shows the right session value but if username and password doesn't exist i also get the same result.
Any idea what i am doing wrong?
Here is my controller code:
<?php
namespace app\controllers;
use app\models\Users;
use Yii;
class UsersController extends \yii\web\Controller
{
public function actionIndex()
{
$model = new users();
return $this->render('login', [
'model' => $model,
]);
}
public function actionLogin()
{
$model = new Users();
if ($model->load(Yii::$app->request->post())) {
// form inputs are valid, do something here
$request = Yii::$app->request;
$form_values = $request->post('Users');
//var_dump($form_values['email']); exit;
//echo $form_values['email'];
if($model !==NULL){
$model = $model->doLogin($form_values['email'],$form_values['password']);
$session = Yii::$app->session;
$session->setFlash('login', 'Login succesful.');
return $this->render('index', [
'model' => $model,
]);
}
elseif($model === NULL){
$session = Yii::$app->session;
$session->setFlash('login', 'Invalid Login.');
return $this->render('login', [
'model' => $model,
]);
}
}
}
}
This is because your condition does not make sense and your else branch is a dead code.
First you're initializing $model variable:
$model = new Users();
Then your testing if it is not null:
if($model !==NULL){
Which will always return true since you already initialized this variable to contain Users model, there is no chance it will be null. You should probably have something like this:
class UsersController extends \yii\web\Controller {
public function actionIndex() {
$model = Users::findOne(Yii::$app->user->id);
return $this->render('index', [
'model' => $model,
]);
}
public function actionLogin() {
$model = new Users();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
Yii::$app->session->setFlash('login', 'Login successful.');
return $this->redirect(['index']);
}
return $this->render('login', [
'model' => $model,
]);
}
}
And handle login (validating username and password) in Users::login() method. See example in basic application template.
I have tried different approach for create action.
Usually i have one action which renders, validates and saves data.
Now i want two separate actions. One for rendering view and second for validation and data storage.
View
$form = ActiveForm::begin([
'action' => ['ew/eshop-create'],
'method' => 'post',
]);
echo $form->field($model, 'input')->textarea([
'rows' => '20'
]);
echo Html::submitButton(
'<i class="glyphicon glyphicon-send"></i> OdoslaƄ',
[
'class' => 'btn btn-success',
'name' => 'create-button'
]
);
ActiveForm::end();
Model
class EshopCreate extends Model
{
public $input;
public function attributeLabels()
{
return [
'input' => 'JSON vstup'
];
}
public function rules()
{
return [
['input', 'required'],
['input', 'validateInput'],
];
}
public function validateInput()
{
// validate json
$this->addError('input', 'Something is wrong');
}
}
Controller
class EwController extends Controller
{
public function actionEshopCreateForm()
{
$model = new EshopCreate();
return $this->render('eshop-create-form', [
'model' => $model
]);
}
public function actionEshopCreate()
{
$model = new EshopCreate();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
exit('create');
}
return $this->redirect(['ew/eshop-create-form']);
}
}
Edit:
So i had problem with validation. I switched model->load and model->validate in actionEshopCreate.
So it works fine, but message from validateInput is not displayed. Also when i turn off clientvalidation, there are no error messages at all. So my question is how to pass errors from one action to another.
Thanks.
You are redirecting to a different action when the form is submitted and fail to pass the validation
return $this->redirect(['ew/eshop-create-form']);
the EshopCreate model will lose all validation messages when the redirection happens
Probably you want to do something like this
class EwController extends Controller
{
public function actionEshopCreateForm()
{
$model = new EshopCreate();
return $this->render('eshop-create-form', [
'model' => $model
]);
}
public function actionEshopCreate()
{
$model = new EshopCreate();
if ($model->load(Yii::$app->request->post()) && $model->validate())
{
//store the model data in session or somewhere for example where you can retrieve it later in the actionEshopCreateForm() action
return $this->redirect(['ew/eshop-create-form']);
}
return $this->render('eshop-create-form', [
'model' => $model
]);
}
}
What I meet is almost like this:
I have a create form, and the form contains two model's attribute;
I pass them from controller to view, and add rules to validate attribute in both model;
But the form validation did not work well - a model's validation is
not work.
I have no idea about how to resolve this, thanks for help!
And I find a reference article - Complex Forms with Multiple Models, but it is TBD.
Here is my sample code.
Controller - SiteController.php:
namespace task\controllers;
use yii\web\Controller;
use task\models\Task;
use task\models\Customer;
class Task extends Controller
{
public function actionCreate()
{
$model = new Task;
$customerModel = new Customer;
// load, validate, save ...
return $this->render('create', [
'model' => $model,
'customerModel' => $customerModel
]);
}
}
Model - Task.php, Customer.php:
namespace task\models;
use yii\db\ActiveRecord;
class Task extends AcitveRecord
{
public $title, $published_at;
public function rules()
{
return [
[['title', 'published_at'], 'required'],
['published_at', 'match', 'pattern' => '/patten for time/']
];
}
}
namespace task\models;
use yii\db\ActiveRecord;
class Customer extends ActiveRecord
{
public $name;
public function rules()
{
return [
['name', 'required'],
];
}
}
View - create.php:
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'title')->textInput() ?>
<?= $form->field($model, 'publish_at')->textInput() ?>
<?= $form->field($customerModel, 'name')->textInput() ?>
<?= Html::submitButton('submit')?>
<?php ActiveForm::end(); ?>
This can be an option. You can try it by creating an custom model, like ContactForm something like this:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
/**
* CustomModel is the model behind the contact form.
*/
class CustomModel extends Model
{
public $attributeFromModel1;
public $attributeFromModel2;
/**
* #return array the validation rules.
*/
public function rules()
{
return [
// attributeFromModel1, attributeFromModel2 are required
[['attributeFromModel1', 'attributeFromModel2'], 'required'],
// ['email', 'email'],
['attributeFromModel1','YourRule']
// verifyCode needs to be entered correctly
['verifyCode', 'captcha'],
];
}
/**
* #return array customized attribute labels
*/
public function attributeLabels()
{
return [
'atttributeFromModel1' => 'Your Label',
'atttributeFromModel2' => 'Your Label ',
];
}
public function actionUpdate($id)
{
$model = $this->findModel($id);
$customerModel = Customer::findOne($id);
if (!isset($model, $customerModel)) {
throw new NotFoundHttpException("The user was not found.");
}
$model->scenario = 'update';
$customerModel->scenario = 'update';
if ($model->load(Yii::$app->request->post()) && $customerModel->load(Yii::$app->request->post())) {
$isValid = $model->validate();
$isValid = $customerModel->validate() && $isValid;
if ($isValid) {
$model->save(false);
$customerModel->save(false);
return $this->redirect(['view', 'id' => $id]);
}
}
return $this->render('update', [
'model' => $model,
'customerModel' => $customerModel,
]);
}