I am trying to validate a multiple select field that have jquery chosen applied.
Validation is working perfectly but only problem is that validation message is not showing below the input field.
Here is my files.
profile_edit.ctp
<?php echo $this->Form->create($user,['action' => '', 'role'=>"form",'novalidate'=>true,'method'=>'post','id'=>'ProfileForm','templates'=>['label'=>false,'inputContainer'=>'{{content}}']]); ?>
<?php echo $this->Form->control('user_grades[].grade_id',['multiple','hiddenField'=>false, 'escape'=>false, 'type'=>'select', 'id'=>'sp_grade', 'options'=>App\Model\Table\GradesTable::getGrades('list'),'class'=>'form-control chosen-select']); ?>
<button type="submit" class="btn footer_btns float-left">Save</button>
<?php echo $this->Form->end(); ?>
MyAccountController.php
<?php
public function profileEdit(){
$user = $this->Users->get($this->Auth->user('id'), ['contain'=>['UserGrades']]);
if($this->request->is(['put','post'])){
$data = $this->request->getData();
if(isset($data['user_grades']) && !empty($data['user_grades'])) {
$this->UserGrades->deleteAll(['user_id' => $this->Auth->user('id')]);
}
if(null == $this->request->getData('user_grades')){
$this->request = $this->request->withData('user_grades.0.grade_id','');
}
$user = $this->Users->patchEntity($user, $this->request->getData(), [
'validate' => 'editProfileSection',
'associated' => [
'UserGrades' => ['validate'=> 'editProfileSection']
]
]);
if(empty($user->getErrors())){
if ($this->Users->save($user)) {
$this->Flash->success(__('Succesfully updated <strong>'.$user->full_name .'</strong> Information||Success'));
return $this->redirect(['action' => '']);
}
}
$this->Flash->error(__('Please check your inputs and try again.||Action Failed!'));
}
$this->set(compact('user'));
}
UserGradesTable.php
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\ORM\Query;
use Cake\ORM\TableRegistry;
use Cake\Event\Event;
use Cake\ORM\RulesChecker;
use Cake\Validation\Validator;
class UserGradesTable extends Table {
public function initialize(array $config) {
$this->addBehavior('Timestamp');
$this->addBehavior('Trim');
}
public function validationEditProfileSection(Validator $validator) {
$validator
->notEmpty('grade_id',"Please select at least one grade.");
return $validator;
}
}
I have tried to get error message and got following:
Array
(
[user_grades] => Array
(
[0] => Array
(
[grade_id] => Array
(
[_empty] => Please select at least one grade.
)
)
)
)
But this error is not showing below the input field. Any help will be appreciated.
You are not using the correct naming scheme for the form control, you cannot use [], if you want the form helper magic to work, then you must supply the actual index, ie:
user_grades.0.grade_id
See also Cookbook > Views > Helpers > Form > Creating Inputs for Associated Data
Related
I have two models in Yii2 (masterTransaction and splitTransaction), where each masterTransactions can have multiple splitTransactions. Each splitTransaction has an attribute 'amount'. My problem is I need to validate if the sum over all 'amount' attributes is 0.
My first solution was to make another model called Transaction, in which I had an attribute where I saved an instance of the masterTransaction model and another attribute with an array of splitTransaction instances. I did the validation with a custom inline validatior, which work perfectly.
Transaction model
class Transaction extends Model
{
public $masterTransaction;
public $splitTransactions;
public function init()
{
$this->masterTransaction = new MasterTransaction();
$this->splitTransactions[] = new SplitTransaction();
}
public function rules()
{
return [
['splitTransactions', 'validateSplitTransactions'],
];
}
public function validateSplitTransactions($attribute, $params)
{
$sum = 0;
foreach ($this->$attribute as $transaction) {
$sum = bcadd($sum, $transaction->amount, 3);
}
if ($sum != 0) {
$this->addError($attribute, 'The sum of the entries has to be 0');
}
}
public function save()
{
$this->masterTransaction->save();
foreach ($this->splitTransactions as $splitTransaction) {
$splitTransaction->master_transaction_id = $this->masterTransaction->id;
$splitTransaction->save();
}
}
}
Controller function to create the model
public function actionCreate()
{
$transaction = new Transaction();
$count = count(Yii::$app->request->post('SplitTransaction', []));
for ($i = 1; $i < $count; $i++) {
$transaction->splitTransactions[] = new SplitTransaction();
}
if ($transaction->masterTransaction->load(Yii::$app->request->post()) && Model::loadMultiple($transaction->splitTransactions, Yii::$app->request->post())) {
$transaction->masterTransaction->user_id = Yii::$app->user->id;
foreach ($transaction->splitTransactions as $splitTransaction) {
$splitTransaction->user_id = Yii::$app->user->id;
}
if ($transaction->validate()) {
$transaction->save();
}
}
return $this->render('create', [
'transaction' => $transaction,
]);
}
But when I tried building a form to input the data, I ran into a problem with the Ajax validation. The validation would work, but Yii didn't know where to put the error message, so it just deleted it.
I suspect that this is just not the preferred way in Yii2 model my data, but I don't really have another idea. Maybe someone has some ideas for me.
Option 1.
It depends on your view file codes. Does your form contains "splitTransactions" variable? If not, you can put it like this
<?= $form->field($model, 'splitTransactions')->hiddenInput(['maxlength' => true])->label(false); ?>
The variable will be hidden, but still show errors. In some case validation will not be fired because of empty value of "splitTransactions" variable.
"splitTransactions" should contain some value to fire validation. You can put some value to if before pasting the form like this
$model->splitTransactions=1;
Option 2.
You can add error to other variable (which form contains) like this
public function validateSplitTransactions($attribute, $params)
{
$sum = 0;
foreach ($this->$attribute as $transaction) {
$sum = bcadd($sum, $transaction->amount, 3);
}
if ($sum != 0) {
$this->addError('transaction_number', 'The sum of the entries has to be 0');
}
}
Look, form should contain "transaction_number" variable. Error will be added to "transaction_number" input.
Option 3. In my experience.
It is better to separate ajax validation from form action url a.g. create another controller action for ajax validation and use it.
Example
Create model FeedbackForm
class FeedbackForm extends Model
{
public $name;
public $email;
public $text;
/**
* #inheritdoc
*/
public function rules()
{
return [
[['name', 'email', 'text'], 'required'],
[['name', 'email'], 'string', 'max' => 128],
[['email'], 'email'],
[['text'], 'string', 'max' => 512],
];
}
public function attributeLabels()
{
return [
'name' => \Yii::t('front', 'Name'),
'email' => \Yii::t('front', 'Email'),
'text' => \Yii::t('front', 'Message text'),
];
}
}
put actions to SiteSontroller
public function actionFeedback()
{
$model= new \frontend\models\FeedbackForm;
$model->load(Yii::$app->request->post());
if($model->validate()) {
$newFeed=new \frontend\models\Feedback;
$newFeed->create_time=new \yii\db\Expression('NOW()');
$newFeed->name=$model->name;
$newFeed->email=$model->email;
$newFeed->is_new=1;
$newFeed->text=$model->text;
if($newFeed->save()) {
\Yii::$app->session->setFlash('success', \Yii::t('front', 'Your message has accepted'));
} else {
\Yii::$app->session->setFlash('error', \Yii::t('front', 'Error on save'));
}
} else {
\Yii::$app->session->setFlash('error', \Yii::t('front', 'Data error'));
}
return $this->redirect(['/site/index']);
}
public function actionFeedbackvalidate()
{
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$model= new \frontend\models\FeedbackForm;
$model->load(Yii::$app->request->post());
return ActiveForm::validate($model);
}
And create form inside view
<?php $model=new \frontend\models\FeedbackForm; ?>
<?php $form = ActiveForm::begin([
'enableClientValidation' => true,
'enableAjaxValidation' => true,
'validationUrl'=>['/site/feedbackvalidate'],
'validateOnSubmit' => true,
'id' => 'form-feedback',
'action'=>['/site/feedback'],
'options'=>['class'=>'some class', 'autocomplete'=>'off']
]); ?>
<?= $form->field($model, 'name')->textInput(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('name'), 'autocomplete'=>'off'])->label(false); ?>
<?= $form->field($model, 'email')->textInput(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('email'), 'autocomplete'=>'off'])->label(false); ?>
<?= $form->field($model, 'text')->textarea(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('text'), 'autocomplete'=>'off'])->label(false); ?>
<div class="form-group">
<input type="submit" class="btn btn-default" value="<?php echo Yii::t('front', 'Send') ?>">
</div>
<?php ActiveForm::end(); ?>
That is it
I have a list of checkboxes, which aren't associated with the model itself like the rest of the form:
echo Html::checkboxList('options', $selected_options, $options, ['class' => 'checkbox']);
In the model I have a following rules:
public function rules() {
return [
....*/
[['options'], 'integer'],
['options', 'optValidation', 'on' => 'update'],
];
}
And the following validator:
public function optValidation($attribute, $params) {
foreach ($attribute as $attr){
if ($attr == 1) {
$return = true;
}
else {
$return = false;
}
}
if (!$return) {
$this->addError($attribute, 'At least one checkbox has to be selected!');
}
}
Unfortunately nothing happens when submitting the form as if there are no rules for validation of the field 'options'. Where's the catch?
You need to add options as a public attribute inside your model class. Then you need to set it as safe inside your rules:
public function rules() {
...
[['options'], 'integer'],
[['options'], 'optValidation', 'on' => 'update'],
[['options'], 'safe'],
...
Finally, you will have to generate the input just like other inputs related to your model, even if it doesn't exist in your DB table, you need it inside your model:
<?php echo $form->field($model, 'options')->checkboxList('options', $selected_options, $options, ['class' => 'checkbox']); ?>
I used to use Yii framework. I would like to make project using Phalcon. I could not find validation scenario on Phalcon. What is the best way to correctly implement it on Phalcon?
Thanks in advance.
Any data validation:
<?php
use Phalcon\Validation\Validator\PresenceOf,
Phalcon\Validation\Validator\Email;
$validation = new Phalcon\Validation();
$validation->add('name', new PresenceOf(array(
'message' => 'The name is required'
)));
$validation->add('email', new PresenceOf(array(
'message' => 'The e-mail is required'
)));
$validation->add('email', new Email(array(
'message' => 'The e-mail is not valid'
)));
$messages = $validation->validate($_POST);
if (count($messages)) {
foreach ($messages as $message) {
echo $message, '<br>';
}
}
http://docs.phalconphp.com/en/1.2.6/reference/validation.html
If you are working with models:
<?php
use Phalcon\Mvc\Model\Validator\InclusionIn,
Phalcon\Mvc\Model\Validator\Uniqueness;
class Robots extends \Phalcon\Mvc\Model
{
public function validation()
{
$this->validate(new InclusionIn(
array(
"field" => "type",
"domain" => array("Mechanical", "Virtual")
)
));
$this->validate(new Uniqueness(
array(
"field" => "name",
"message" => "The robot name must be unique"
)
));
return $this->validationHasFailed() != true;
}
}
http://docs.phalconphp.com/en/1.2.6/reference/models.html#validating-data-integrity
models also have events, so you can add any logic you need in these functions:
http://docs.phalconphp.com/en/1.2.6/reference/models.html#events-and-events-manager
I would like to use forms for CRUD as they are very dynamic and reusable.
You can achieve that in forms using options.
You can pass additional options to form and act like a scenario.
You can check Form constructor here
https://docs.phalconphp.com/en/latest/api/Phalcon_Forms_Form.html
In your controller you can pass $options
<?php
use Phalcon\Mvc\Controller;
class PostsController extends Controller
{
public function insertAction()
{
$options = array();
$options['scenario'] = 'insert';
$myForm = new MyForm(null, $options);
if($this->request->hasPost('insert')) {
// this will be our model
$profile = new Profile();
// we will bind model to form to copy all valid data and check validations of forms
if($myForm->isValid($_POST, $profile)) {
$profile->save();
}
else {
echo "<pre/>";print_r($myForm->getMessages());exit();
}
}
}
public function updateAction()
{
$options = array();
$options['scenario'] = 'update';
$myForm = new MyForm(null, $options);
}
}
And your form should look like something this
<?php
// elements
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
// validators
use Phalcon\Validation\Validator\PresenceOf;
class MyForm extends Form {
public function initialize($entity = null, $options = null) {
$name = new Text('first_name');
$this->add($name);
if($options['scenario'] == 'insert') {
// at the insertion time name is required
$name->addValidator(new PresenceOf(array('message' => 'Name is required.')));
}
else {
// at the update time name is not required
// as well you can add more additional validations
}
}
}
now you can add multiple scenarios and act based on scenarios.
Using PyroCMS 1.3.1 I've built a model that's pretty much a copy-paste version of the included contact model, but with a few tweaks. When all fields are inputted correctly everything works as expected. If a field is left out or incorrectly filled in, the form does not submit - just as expected.
However, I can't seem to get the form validation message to be outputted and this is driving me crazy. I'm sure I've just missed something very basic so if anyone could point it out I'd be grateful.
View file (form.php) contains this
<?php if (validation_errors()): ?>
<div class="error-box">
<?php echo validation_errors(); ?>
</div>
<?php elseif (isset($messages['error'])): ?>
<div class="error-box">
<p><?php echo $messages['error']; ?></p>
</div>
<?php endif; ?>
Controller (plugin.php) looks like this
class Plugin_mycustommodule extends Plugin {
private $rules = array(
array(
'field' => 'firstname',
'label' => 'lang:mycustommodule_firstname_label',
'rules' => 'required|trim|max_length[80]'
),
/* ... snip ... */
array(
'field' => 'license',
'label' => 'lang:mycustommodule_license_label',
'rules' => 'required'
)
);
public function __construct()
{
$this->lang->load('mycustommodule');
}
function form()
{
$this->load->library('form_validation');
$this->load->helper('form');
$this->form_validation->set_rules($this->rules);
// If the user has provided valid information
if ($this->form_validation->run())
{
/* ... Custom processing here ... */
// The try to send the email
if ($this->_send_email())
{
$message = $this->attribute('confirmation', lang('mycustommodule_sent_text'));
// Store this session to limit useage
$this->session->set_flashdata('success', $message);
redirect(current_url());
}
else
{
$message = $this->attribute('error', lang('mycustommodule_error_message'));
$data['messages']['error'] = $message;
}
}
// Set the values for the form inputs
foreach ($this->rules as $rule)
{
$form_values->{$rule['field']} = set_value($rule['field']);
}
$data['form_values'] = $form_values;
return $this->module_view('mycustommodule', 'form', $data, TRUE);
}
So it turns out that while I was working on customizing the CodeIgniters language files I must have messed up the upload of form_validation_lang.php because all entries was empty i.e. $lang['required'] = '';
So basically the validator looked for the error message, found an empty string, which was trimmed from being outputted. As suspected something silly, just not in the place I expected.
Let's hope this post will save someone else the trouble.
I have this code in my model in codeigniter:
<?php
class User_model extends Model {
function User_model()
{
parent::Model();
}
function get_data()
{
$pages = false;
// Get the pages from the database using adodb if needed
$this->adodb->connect();
$recordSet = $this->adodb->execute('SELECT id, genreID, artist, albumName FROM album' );
if ( ! $recordSet )
{
log_message( 'error', 'Error connecting to the database' );
log_message( 'debug', $this->adodb->getErrorMsg());
}
else
{
unset( $this->pages );
while (!$recordSet->EOF)
{
$pages[] = array(
'id' => $recordSet->fields[0],
'genreID' => $recordSet->fields[1],
'artist' => $recordSet->fields[2],
'albumName' => $recordSet->fields[3]
);
$recordSet->MoveNext();
}
$this->pages = $pages;
}
$this->adodb->disconnect();
}
}
?>
I have this in my controller:
<?php
class Welcome extends Controller {
function Welcome()
{
parent::Controller();
}
function index()
{
//
$this->load->model('User_model');
$data['query'] = $this->User_model->get_data();
$this->load->view('welcome_message',$data);
}
}
What I cannot do is get my model results into my view. There is no result() object because I used adodb so this:
<?php foreach($query->result() as $row): ?>
<p>
<?=$row->albumName;?>
</p>
<?php endforeach; ?>
gets me an error.
What do I put in my view to get the query results of my model. I know the model works because I can echo $recordSet->fields[3]; from the model and see the album name.
Thank you for any help.
edit: I don't understand why my get_data() call in my view returns nothing.
For one you are not returning anything from get_data so that will cause $query to be null. Also you shouldn't be executing the query in the view because view content should not be handling data layer operations, also you've already disconnected from the db.