find('first') within a Model custom validate rule - validation

I want to validate a field to be within a range of numbers dependant on another field selection.
eg.
'rating' => array(
'within class range' => array(
'rule' => 'withinClassRange',
'message' => 'number not in range'
)
),
and withinClassRange
public function withinClassRange($data) {
// get class range
$classRange = $this->Edition->Aclass->find('first', array('conditions' => array('Aclass.id' => $this->data['Edition']['aclass_id'])));
if($data['rating'] < $classRange->minRange) {
return false;
}
if($data['rating'] > $classRange->maxRange) {
return false;
}
return true;
}
but this find is only do-able within the controller. How do I implement this?

You shouldn't really assign data to the request object. Either assign the request object to another array such as $data and do your updates there or find a way to pass the range to your validation function.
Also, the find statement from your question would return an array, not an object. So your syntax isn't valid there. That's probably the cause of your original problem.
Something like this should work:
public function withinClassRange($data) {
// get class range
$classRange = $this->Edition->Aclass->find('first', array('conditions' => array('Aclass.id' => $this->data['Edition']['aclass_id'])));
if($data['rating'] > $classRange['Aclass']['minRange'] && $data['rating'] < $classRange['Aclass']['maxRange']) {
return true;
}
return false;
}

I got it!
What I did was retrieve the data and set the range limits as extra vars in the request object in the Controller just before the 'save' call. Then the comparison can be done in the Model.
//controller
$classRange = $this->Edition->Aclass->find('first', array('conditions' => array('Aclass.id' => $this->request->data['Edition']['aclass_id'])));
$this->request->data['Edition']['minRange'] = $classRange['Aclass']['minRange'];
$this->request->data['Edition']['maxRange'] = $classRange['Aclass']['maxRange'];
//model
public function withinClassRange($data) {
if($data['rating'] < $this->data['Edition']['minRange']) {
return false;
}
if($data['rating'] > $this->data['Edition']['maxRange']) {
return false;
}
return true;
}

Related

Post method in REST API using codeigniter

when i use following method and pass body key as fail (non defined key) and some value getting pass message in return and empty row gets inserted in table, How do I validate?
Function that I use in REST API,
function categories_POST() {
$title = $this->post('title');
$no = $this->post('no');
$id= $this->post('id');
$this->load->model('model_check');
$msg = $this->model_check->addDetails($title , $no , $id);
$this->response($msg);
}
My model,
function addDetails($x, $y, $z) {
$check = "INSERT INTO categories (title,no,id) VALUES ('$x','$y','$z')";
$query = $this->db->query($check);
if($this->db->affected_rows() > 0) {
return "pass";
} else {
return "fail";
}
}
quite honestly, you'd be better off using the query builder and (depending on what style you follow(fat/skinny controllers/models)) letting the model deal with $this->post() for processing.
Is this Phil Sturgeons/Chris A's rest server?
Something like:
function categories_post() { // doesn't need to be POST()
$this->load->model('model_check');
$msg = $this->model_check->addDetails()
if ($msg)
{
$this->response([
'status' => TRUE,
'message' => 'pass'
], REST_Controller::OK);
}
// default to fail
$this->response([
'status' => FALSE,
'message' => 'fail'
], REST_Controller::HTTP_BAD_REQUEST);
}
Your model,
function addDetails() {
// this only checks to see if they exist
if (!$this->post() || !$this->post('x') || !$this->post('y') || !$this->post('z')) {
return false;
};
$insert = array(
'x' => $this->post('x'),
'y' => $this->post('y'),
'z' => $this->post('z'),
);
if($this->db->insert('categories', $insert))
{
return true;
}
return false; // defaults to false should the db be down
}
IF you mean form_validation you can use this instead of the above.
function addDetails() {
$this->load->library('form_validation');
$this->form_validation->set_rules('x', 'X', 'required');
$this->form_validation->set_rules('y', 'Y', 'required');
$this->form_validation->set_rules('z', 'Z', 'required');
if ($this->form_validation->run() == true)
{
$insert = array(
'x' => $this->post('x'),
'y' => $this->post('y'),
'z' => $this->post('z'),
);
if($this->db->insert('categories', $insert))
{
return true;
}
}
return false; // defaults to false should the db be down
}
This is quite verbose, there's shorter ways to do it, but I'd rather make it easy to figure out.
Two ways of get post values in CodeIgniter
$title = $this->input->post('title');
$no = $this->input->post('no');
$id= $this->input->post('id');
$this->load->model('model_check');
$msg = $this->model_check->addDetails($title , $no , $id);
$this->response($msg);
or
extract($_POST);
Then direct access post name
$this->load->model('model_check');
$msg = $this->model_check->addDetails($title , $no , $id);
$this->response($msg);
Best way is directly access post values in model files (not in controller)
Don't need the pass the POST values in model function.
If you have more queries, then ask to me

Yii2 relation with parameter

Is it possible and what would be the best way to define a relation with a parameter in Yii2.
Situation is simple. I have table texts and texts_regional. texts_regional of course has foreign keys text_id and lang_id.
Gii generated a method to get all regional texts but I dont need that on the frontend. I just need in the current language.
Generated method is:
public function getTextsRegionals()
{
return $this->hasMany(TextRegional::className(), ['text_id' => 'id']);
}
Tried this but it's probably not right:
public function getReg($langId=null)
{
if($langId === null && Yii::$app->session->has('langId')) {
$langId = Yii::$app->session->get('langId');
}
return $this->hasOne(TextRegional::className(), ['text_id' => 'id', 'lang_id'=>$langId]);
}
I need data from both tables so I'd like to eager load this.
Is it just better to use separate method and manually construct the query?
Read in documentation that it's possible to do ->onCondition so wrote a method like this:
public function getReg($langId=1)
{
if(Yii::$app->session->has('langId')) {
$langId = Yii::$app->session->get('langId');
}
return $this->hasOne(TextRegional::className(), ['text_id' => 'id'])->onCondition(['lang_id' => $langId]);
}
$langId is set in main controller.
But I ended up using TextRegional model and joined with Text model to set condition.
Made a TextRegionalQuery class and added a new method:
public function byCode($code)
{
if(Yii::$app->session->has('langId')) {
$langId = Yii::$app->session->get('langId');
} else {
$langId = 1;
}
$this->joinWith('text0')
->andWhere("lang_id = '".$langId."'")
->andWhere("texts.code = '".$code."'");
return $this;
}
Using it like this:
$ft = TextRegional::find()->byCode("footer_text")->one();
Or
$news = TextRegional::find()->byType(2)->visible()->all();
/**
* relation with current LangContractTemplate
*/
public function getCurLangContractTemplate()
{
if(isset(Yii::$app->user->identity->u_lang) && !empty(Yii::$app->user->identity->u_lang))
$langId = Yii::$app->user->identity->u_lang;
else
$langId = \Yii::$app->language;
return $this->hasOne(LangContractTemplate::className(), ['lcont_cont_id' => 'cont_id'])->onCondition(['lcont_lang_id' => $langId]);
}
//------------------OR------------------
/**
* relation with language table
*/
public function getContractByLang()
{
return $this->hasOne(LangContractTemplate::className(), ['lcont_cont_id' => 'cont_id']);
}
/* and Get data */
$contract_content = ContractTemplate::find()
->joinWith(['contractByLang' => function($query) use ($lang) {
return $query->where(['lcont_lang_id' => $lang]);
}])
->one();

Zend_Validate_Between on Another Value

What is the best way to validate a number range based on the value of another form element? If the user selects "percentage" as a discount type, the discount amount should be between 0 and 100, and not 140! The problem seems to be passing in another form element value.
Also, I've viewed other resources, one dealing with a similar topic, but perhaps not all the way relevant.
How to validate a field of Zend_Form based on the value of another field?
Form.php
$isValid = new Application_Model_Validate();
$discount = $this->createElement('text', 'discount')
->setLabel('Discount Amount')
->setDescription("Enter an amount in the format \"200.00\" ")
->setRequired(true)
->setDecorators(array('Description', 'ViewHelper', 'Errors',
array('HTMLTag', array('tag' => 'dd')),
array('Label', array('tag' => 'dt'))));
$discount->addValidators(array(array('Float')), $isValid->isValid(new Zend_Validate_Between(array('min' => '0', 'max' => '100')), $discountType));
$this->addElement($discount);
Application_Model_Validate.php
Require_once 'Zend/Validate/Abstract.php';
class Application_Model_Validate extends Zend_Validate_Abstract
{
/*
* Validation failure message key
*/
const INVALID_PERCENTAGE = 'InvalidPercentage';
/*
* Validation failure message template definitions
*/
protected $_messageTemplates = array(
self::INVALID_PERCENTAGE => 'Please enter a percentage greater than 0 and up to 100.'
);
protected $_percentageOption;
protected $_percentageValue;
/*
* Defined by Zend_Validate_Interface
* Validate the percentage parameters
*/
public function isValid($value, $context = null)
{
$this->_setValue($value);
/*
* If context key is valid, return true
*/
if(is_array($context))
{
if (isset($context['percentage']) && ($value))
{
return true;
}
}
$this->_error(self::INVALID_PERCENTAGE);
return false;
}
If you need anymore information, just say.
I modified your code a bit and added a drop down box:
Form:
$this->addElement('select', 'discounttype');
$this->getElement('discounttype')
->addMultiOptions(
array('percentage' => 'percentage', 'other' => 'other')
);
$discount = $this->createElement('text', 'discount')
->setLabel('Discount Amount')
->setRequired(true);
$discount->addValidators(
array('Float', new Application_Model_Validate(0, 140))
);
$this->addElement($discount);
Validator:
<?php
class Application_Model_Validate extends Zend_Validate_Between
{
public function isValid($value, $context = null)
{
$this->_setValue($value);
if ($context['discounttype'] == 'percentage') {
$this->setMax(100);
}
return parent::isValid($value, $context);
}
}
Now, if you validate the form in your controller using $form->isValid($this->getRequest()->getParams()), it will take an input between 0 and 100 if in the drop down box 'percentage' is selected and an input between 0 and 140 otherwise.
An alternative solution:
//controller validation
$discountValidate = new Application_Model_Validate();
$discountValidate->_checkDiscount($data['discountType'], $data['discount']);
if ($discountValidate->isValid())
{
//do
}
else
{
$element = $form->getElement('discount');
$element->addError($discountValidate->getError());
}

Custom errors e.g more than 1 record when using Codeigniter method

I have a codeigniter application.
My controller calls a function of a method.
I am checking if the row it is trying to select actually exists, and then returning true (and data) or false (and error message) respectively to my controller.
Within my controller there are multiple calls to this function.
I only want to load the 'success' view if all of these method calls return true.
Otherwise i want to display an error..
Given that i want to show the error within my layout, i could simply create an error view and pass an error message to it.. if there are multiple errors i want to display them all..
Is the correct/most efficient way to do this simply:
if($resultone['result'] == FALSE or $resulttwo['result'] == FALSE)
{
$data['error']['0']=$resultone['error'];
$data['error']['1']=$resulttwo['error'];
$this->load->view('custom_error',$data);
} else {
//load success view
}
I'd rather do this:
$data = array(
'data' => array(),
'errors' => array()
);
...
$result = call_that_function($arg1);
if (isset($result['error'])) {
$data['errors'][] = $result['error'];
} else {
$data['data'][] = $result['data'];
}
...
$result = call_that_function($arg2);
if (isset($result['error'])) {
$data['errors'][] = $result['error'];
} else {
$data['data'][] = $result['data'];
}
...
$result = call_that_function($arg3);
if (isset($result['error'])) {
$data['errors'][] = $result['error'];
} else {
$data['data'][] = $result['data'];
}
...
if (count($errors['errors']) > 0) {
$this->load->view('custom_error',$data);
} else {
$this->load->view('success',$data);
}

cakephp validation response returning data to controller

Hi i have made a custom validation in the model. How can i access the result($visitor) from this in the controller?
model:
<?php
class Visitors extends AppModel
{
var $name = 'Visitors';
var $validate = array(
'xxx' => array(
'rule' => array('checkxxx'),
'message' => 'yyy.'
)
);
function checkIxxx($check){
$visitor = $this->find('first', array('conditions' => $check));
return $visitor;
}
}
?>
in my controller i want this:
function start() {
$this->Visitors->set($this->data);
if($this->Visitors->validates())
{
if($this->Visitors->xxx->type == 'value') //this is a value from the $visitor array in the model**
{
//do something
}
}
is this possible?
Updated to be a relevant answer, apologies.
//Model
var myField = 'invalid';
function myValidation($var){
if($var === true){
// Passed your validation test
$this->myField = 'valid';
}else{
$this->myField = 'invalid';
}
}
// Controller
$this->Model->set($this->data);
$this->Model->validates($this->data);
if($this->Model->myfield == 'valid'){
// Field has passed validation
}
You will want to use
$this->Model->invalidFields()
PS: You dont follow cake conventions
the model should be "Visitor" (singular)

Resources