I have a registration form for my web client and API for the same registration form. I want to validate the data from the API by using the same rules that I use for the web client in the Model but I need to display different messages. In the web client I have messages like “‘Error in field Name” and for the API I need message like “1”. Now I`m doing this with if statement in the controller, if the error is ‘Error in field Name’ give me message ‘1’. The problem is that if I have to validate 10 fields I need to write 10 if statements in the controller. Is there any smarter way for doing this?
Model:
class User extends AppModel {
public $validate = array(
'name'=>array(
'rule'=>'notEmpty',
'message'=> ‘Error in field Name’
)
);
}
Controller
class RestUsersController extends AppController {
$errors = $this->User->invalidFields();
if(array_shift(array_slice($errors, 0, 1))== ' Error in field Name '){
$message='1';
}
}
Thank you in advance!
You can set validations rules in beforeValidation() callback in your model. In this method you can prepare two arrays of validation sets and and put one variable in AppModel which will be working like switch to choose proper validation set. All you need to make it working will be setting proper value for this switch in your API controller in beforeFilter() callback. For better understanding of my solution, look at code sample below.
Model
class User extends AppModel {
public function beforeValidate($options = array()) {
parent::beforeValidate($options);
$this->_prepareValidationRules();
}
protected function _prepareValidationRules() {
if (!empty($this->apiValidation)) { // for API
$this->validate = array(
'name' => array(
'rule' => 'notEmpty',
'message' => 'Error in field Name'
));
} else { // default behaviour
$this->validate = array(
'name' => array(
'rule' => 'notEmpty',
'message' => '1'
));
}
}
}
Controller
class RestUsersController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->User->apiValidation = true;
}
}
AppModel.php
class AppModel extends Model {
public $apiValidation = false;
(...)
}
Of course you could define $apiValidation variable as protected and controll it by method, but this is up to you.
Related
In Laravel, I am setting up Google ReCaptcha V3 which now returns a "score". I've managed to setup a validation rule to allow my form to submit (all working), but this is only returning true or false to pass the validation.
How do I base this on the score instead?
I'm using this composer package to help me out - https://github.com/google/recaptcha
This is in my controller (where I am sending the token to validate with the server):
// validation
$this->validate( $request, array(
'g_recaptcha_response' => ['required', 'string', new Captcha()]
));
This is the rule:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use ReCaptcha\ReCaptcha;
class Captcha implements Rule
{
public function __construct()
{
//
}
public function passes($attribute, $value)
{
$recaptcha = new ReCaptcha('SECRET');
$response = $recaptcha->verify($value, $_SERVER['REMOTE_ADDR']);
return $response->isSuccess();
}
public function message()
{
return 'Are you a robot?';
}
}
Can I access the class somehow from the controller? I can see in the package that I need to use ->getScore() but I don't know how to access it?
As you are doing in the validation rule, you can also get the score in controller :
public function something(YourRequest $request){
$recaptcha = new ReCaptcha('SECRET');
$response = $recaptcha->verify($request->g_recaptcha_response, $request->ip());
$score = $response->getScore();
}
More available methods of response can be found here
Validation functions don't work.
Validation customs rules are not applied to the usernmane field
module dektrium/user
PHP 7.1
Yii 2.0.16
Already try all from here: https://www.yiiframework.com/doc/guide/2.0/en/input-validation (Inline Validators and Standalone Validators)
Model Agent :
class Agent extends Profile
{
public $username;
public $password;
public $password2;
public function rules()
{
$rules = [
['username', AgentValidator::className()],// it's not work
[['email'], 'email'], // it's work
['password2', 'compare', 'compareAttribute' => 'password', 'message' => 'Пароли должны совпадать'],//// it's work
];
return array_merge(parent::rules(), $rules);
}
}
AgentValidator.php
<?php
namespace app\components;
use yii\validators\Validator;
class AgentValidator extends Validator
{
public function validateAttribute($model, $attribute)
{
if (User::findOne(['username' => $this->$attribute]]) {
$this->addError($attribute, 'Такой логин уже занят');
}
}
}
You are using standalone validator and you want the frontend validation to be working along with the backend so you need to override the yii\validators\Validator::clientValidateAttribute() in your Standalone validator AgentValidator, which returns a piece of JavaScript code that performs the validation on the client-side.
Within the JavaScript code, you may use the following predefined variables:
attribute: the name of the attribute being validated.
value: the value being validated.
messages: an array used to hold the validation error messages for the attribute.
deferred: an array which deferred objects can be pushed into.
You can go through the section Implementing Client Validation to read in detail.
Apart from everything listed above you have a mistake in your validator code User::findOne(['username' => $this->$attribute]], you need to use $model->$attribute rather than $this->$attribute which will never get the exact value entered in the form. You might have mistakenly added it from the model.
Your current validator should be like below
<?php
namespace app\components;
use yii\validators\Validator;
class AgentValidator extends Validator
{
public $message='Такой логин уже занят';
public function validateAttribute($model, $attribute)
{
if (User::findOne(['username' => $model->$attribute])!==null)
{
$model->addError($attribute, $this->message);
}
}
public function clientValidateAttribute($model, $attribute, $view) {
//check if user exists
$userExists = User::findOne(['username' => $model->$attribute])!==null;
$message = json_encode($this->message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
return <<<JS
if($userExists){
messages.push($message);
return;
}
JS;
}
}
So, Thank Muhammad Omer Aslam for right answer.
Yii2 does't generate any js code for validation by custom rules. Therefore it is necessary to add a check to the controller and the form
For me it:
Controller
if (\Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$model->load(\Yii::$app->request->post());
return \yii\widgets\ActiveForm::validate($model);
}
Form
$form = ActiveForm::begin([ 'enableAjaxValidation' => true]);
in my laravel 5.1 app, I've got a Book model with a required "Title" field and several others non-required fields. To validate Book create/update, I use form request validation like this:
class StoreBookRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'title' => 'required',
'year' => 'numeric',
'pages' => 'numeric',
];
}
}
I then type-hint the request on the controller action and everytning works fine. Now I need to create a new controller action that updates only one of the non-required fields. To do so, I created another request like this:
class StoreReviewRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'vote' => 'numeric',
];
}
}
and I type-hint the request in the controller action:
public function updateReview(StoreReviewRequest $request, Book $book)
{
$input = array_except(Input::all(), '_method');
$book->update($input);
Session::flash('message', 'Review updated');
return redirect('/book');
}
The problem is that when I use the new controller action, the update form does not pass validation, but complains about missing "Title" field, even tough I'm not decalring that field as required in my StoreReviewRequest class. What am I doing wrong? Thanks!
As #Needpoule suggested, I was using the wrong action in my form.
In Yii2 we use public function rules() { } for validation, in view we use $model->isNewRecord for check mode, I want to check mode in rule function. I tried by $this->isNewRecord but it is not working.
You implement different validation rules using scenarios.
In the controller you can set the different scenario on different actions or on different conditions in same action .
public function actionRegister(){
$model = new User;
$model->scenario = 'register';
}
You can then apply different validation rules to specific scenarios in your model
class User extends ActiveRecord {
public function rules()
{
return [
// email required in "register" scenario
[['email'], 'required', 'on' => 'register'],
// email, password are required in "login" scenario
[['email', 'password'], 'required', 'on' => 'login'],
];
}
}
I'm new to Laravel 4 and trying to figure out why I'm getting an error saying that Method [show] does not exist.
I do not have a method named "show" and can only imagine that this is an internal, Laravel method but I do not know how to affect this or what could have done this. Any thoughts or help on this would be incredibly appreciated as I have been stuck on this for two days now and cannot figure out what I am doing wrong.
View:
<li>Sign in</li>
Route:
/*Sign In (GET)*/
Route::get('/account/sign-in', array(
'as' => 'account-sign-in',
'uses' => 'AccountController#getSignIn'
));
AccountController:
class AccountController extends BaseController {
public function getSignIn(){
return View::make('user.signIn');
}
public function postSignIn(){
$validator = Validator::make(Input::all(), array( 'email' => 'required|email', 'password' => 'required' ) );
if($validator->fails()){ /*Redirect to the sign in page*/
return Redirect::route('account-sign-in') ->withErrors($validator) ->withInput();
}
else { /*Attempt user sign in*/
$remember = (Input::has('remember')) ? true : false;
$auth = Auth::attempt(array( 'email' => Input::get('email'), 'password' => Input::get('password'), 'active' => 1 ), $remember);
if($auth){
/*Redirect to the intended page*/ return Redirect::intended('/');
}
else {
return Redirect::route('account-sign-in')->with('global', 'Email/password wrong, or account not activated.');
}
}
return Redirect::route('account-sign-in') ->with('global', 'There was a problem signing you in.');
}
}
What does “Method [show] does not exist” mean?
Code provided in your question doesn't shows anything about show() method, anyways. According to to your comments you didn't extend the BaseController but all your controlers should extend the BaseController and the BaseController should extend the Controller so this is how your BaseController should look like (By default):
class BaseController extends Controller {
/**
* Setup the layout used by the controller.
*
* #return void
*/
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
}
}
Your controller should extend it like this:
class AccountController extends BaseController {
// Define all of your methods
// including show() if you are using it
}
It sounds like you just have a typo on the first line of your AccountController
It probably says class AccountController extends BasesController {
BasesController should be BaseController
I had this problem. I had previously listed a (now deprecated) resource that was causing a collision in the routes.php file.
Route::resource('scheduler', 'SchedulerController');
Route::get('scheduler/notices', 'SchedulerController#notices');