In the application login I have the following code that throw ...HttpException on logging errors:
// common/models/LoginForm.php which is called from the backend SiteController actionLogin method as $model = new LoginForm();
public function loginAdmin()
{
//die($this->getUser()->getRoleValue()."hhh");
if ($this->getUser()->getRoleValue() >= ValueHelpers::getRoleValue('Admin') && $this->getUser()->getStatusValue() == ValueHelpers::getStatusValue('Active')){
if ($this->validate()){
return \Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30:0);
}
else{
throw new \yii\web\NotFoundHttpException('Incorrect Password or Username.');
}
}
else{
throw new \yii\web\ForbiddenHttpException('Insufficient privileges to access this area.');
}
}
It is working fine, but I want to customize the page the rendered with each of NotFoundHttpException and ForbiddenHttpException. I tried to search the Yii2 api to find any parameters that may define view in the construct of the object but I could not find that. So, is there any way to custom the view of the exception?
From Mihai P. (Thank you) answer, I have got this answer. I opened the file of the error class at vendor\yiisoft\yii2\web\ErrorAction.php and I have found that it has a public property for view, so, I decided to use it and hence I defined it in the error array of the actions method as follows:
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
'view' => '#common/views/error.php',
],
];
}
Finally, in common folder I had to create a new folder named views and fill it with a view file called error.php with the following simple code
<?php
$this->title = $name;
echo $name;
echo "<br>";
echo $message;
echo "<br>";
echo $exception;
The three variables in the view $name, $message and $exception are supplied from the ErrorAction object and they could be found in the last lines of that file
...
else {
return $this->controller->render($this->view ?: $this->id, [
'name' => $name,
'message' => $message,
'exception' => $exception,
]);
}
...
If you take a look here https://github.com/yiisoft/yii2-app-advanced/blob/master/frontend/controllers/SiteController.php
You can see that it uses an external action to handle the errors
/**
* #inheritdoc
*/
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
You can either create your own ErrorAction file that extends the default one and use yours instead of the default one from Yii, or just comment out that action and create a normal actionError and put it in there.
Related
Hi everyone i'm having trouble with my software developed with yii2.
I Have a model called Anagrafica and with its primary key id. With this model everything works.
I also have a model called AnagraficaOpzioniCarriera which extend the first one.
I have a view anagrafica/index that show a Kartik grid with the data of people enrolled that you can find in anagrafica. Admin user can update the data of an Anagrafica model by clicking on an the attribute "cognome" that render to anagrafica/update.
this is the command that call the controller AnagraficaController to reach anagrafica/update
'cognome'=>Grid::Labels('cognome',['anagrafica/update'],\app\helpers\Permits::allow('anagrafica','update'),'id','btn','info','10%'),
This is AnagraficaController
public function actionUpdate($id,$error=0,$message='')
{
$id = (int)$id;
$model = Anagrafica::findOne(['id' => $id]);
$model->scenario = 'update';
if ($model->load(Yii::$app->request->post())) {
if($model->validate()){
}
if($model->save(false)){
return $this->redirect(['anagrafica/update','id'=>$model->id]);
}
}
}
return $this->render('update', ['model' => $model, 'extended'=>true]);
}
i removed some portions of code to semplify it, but this is the core.
One time the view anagrafica/update is reached in this page i have an ActiveForm to modify data of the model and i have a render to a grid that show the attributes contained in AnagraficaOpzioniCarriera about the $model that i'm updating.
<?= $this->render('_opzioni_carriera',['parent'=>$model]); ?>
anagrafica/_opzioni_carriera view contain a Kartik grid that shows the column in the model AnagraficaOpzioniCarriera
<?php
use kartik\grid\GridView;
use kartik\select2\Select2;
use kartik\widgets\ActiveForm;
use kartik\editable\Editable;
use kartik\widgets\SwitchInput;
use yii\helpers\ArrayHelper;
use app\helpers\Autoconfigurazione;
use app\models\AnagraficaOpzioniCarriera;
use app\helpers\Grid;
use yii\helpers\Html;
use app\helpers\UserInfo;
/* #var $this yii\web\View */
/* #var $model app\models\AnagraficaOpzioniCarriera*/
$model = new AnagraficaOpzioniCarriera(['scenario'=>'search']);
?>
<div class="">
<?php
echo GridView::widget([
'options'=>[
'id'=>'opzioni_carriera',
],
'dataProvider'=> $model->search($parent->id,Yii::$app->request->queryParams),
'showPageSummary'=>false,
'headerRowOptions'=>['class'=>'kartik-sheet-style'],
'pjax'=>true, // pjax is set to always true for this demo
'pjaxSettings'=>[
'neverTimeout'=>true,
],
'toolbar'=> [
[
'content'=>''
],
],
'panel'=>[
'heading'=>false,
'footer'=>false,
'after'=>false,
],
'columns' => Grid::gridColumns([
'model'=>$model,
'checkbox'=>false,
'remove'=>Grid::gridRemove($model),
'extraOptions' =>[
'cashback' =>Grid::YNColumn('cashback',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'compensa'=>Grid::YNColumn('compensa',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'associazione'=>Grid::YNColumn('associazione',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
'formazione'=>Grid::YNColumn('formazione',['anagrafica-opzioni-carriera/update', 'id' => $parent->id],'left',true,'5%'),
],
]);
?>
</div>
cashback, compensa etc.. are the attributes in the model AnagraficaOpzioniCarriera.
Here when i try to update this attributes everything looks fine, the function model->validate() and model->load returns true value, but at the end of the process doesn't works.
Honestly i don't know what i have to return from the function of the controller.
public function actionUpdate($id)
{
$model = AnagraficaOpzioniCarriera::findOne(['id_anagrafica' => $id]);
if (!$model) {
// Se l'anagrafica opzioni carriera non esiste, genera un'eccezione 404
throw new \yii\web\NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
}
$model->scenario = 'update';
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if(Yii::$app->request->post('cashback') != null) $model->cashback = Yii::$app->request->post('cashback');
if(Yii::$app->request->post('compensa') != null) $model->cashback = Yii::$app->request->post('compensa');
if(Yii::$app->request->post('associazione') != null) $model->cashback = Yii::$app->request->post('associazione');
if(Yii::$app->request->post('formazione') != null) $model->cashback = Yii::$app->request->post('formazione');
if ($model->save()) {
return Json::encode(["success" => true, 'message' => 'Dati aggiornati']);
}
}
// Mostra il form di modifica
return $this->render('_opzioni_carriera', [
'parent' => $model,
]);
}
anyone can help me? i hope i explained my problem in a good form, but my english is not the best, i know. Anyway thanks in aadvance to everyone who want to try to help me, if you need anything other you can easily ask.
I tried every everything, also a logger but nothing worked
Like someone suggest these are the rules of the model AnagraficaOpzioni, but like i said prevously model->validate() works, for this reason i think the problem is not over there
public function rules()
{
return [
[['id_anagrafica'], 'required'],
[['id_anagrafica'], 'integer'],
[['cashback', 'compensa', 'associazione', 'formazione'], 'required', 'on'=>['update']],
[['cashback', 'compensa', 'associazione', 'formazione'], 'integer'],
[['id_anagrafica', 'cashback', 'compensa', 'associazione', 'formazione',], 'safe', 'on'=>['search']],
];
}
I am building a CSV uploader and I want to add a custom validation function that will check the header row of the CSV file to ensure the correct columns are in place.
I am trying to put a custom validation rule in the model to do this but failing at the first hurdle.
I am getting
Setting unknown property: yii\validators\FileValidator::0
exception but as far as I can tell from the documentation this should work.
Model
/**
* UploadForm is the model behind the upload form.
*/
class UploadForm extends Model
{
/**
* #var UploadedFile file attribute
*/
public $file;
/**
* #return array the validation rules.
*/
public function rules()
{
return [
[['file'], 'file', 'extensions' => 'csv', 'checkExtensionByMimeType'=>false, 'headerCheck', 'skipOnEmpty' => false]
];
}
public function attributeLabels(){
return [
'file'=>'Select csv'
];
}
function headerCheck($attribute, $params, $validato){
$this->addError($attribute, "error");
}
}
Controller function:
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
$filename = $model->file->baseName . '.' . $model->file->extension;
if ($model->file && $model->validate()) {
$upload = $model->file->saveAs('uploads/'.$filename );
if($upload){
define('CSV_PATH','uploads/');
$csv_file = CSV_PATH . $filename;
$filecsv = file($csv_file);
foreach($filecsv as $data){
$lines = explode(',',$data);
$t=1;
}
}
}
}
return $this->render('csvUpload', ['model' => $model]);
}
View
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'file')->fileInput() ?>
<button>Submit</button>
<?php ActiveForm::end() ?>
Why is headerCheck() not getting picked up as a custom validation function?
Short Answer
Your rules should be written like so:
return [
[['file'], 'file', 'extensions' => 'csv', 'checkExtensionByMimeType'=>false, 'skipOnEmpty' => false],
[["file"], "headerCheck"],
];
Note that your validation rule, "headerCheck", is a separate item in the array.
Long Answer
A rule's structure is like so:
[["attributes_to_validate"],"vaildatorCallback","param1"=>"value","param2"=>"value]
Note the first two items are the attributes and the callback respectively, and then after that you can specify params that should be assigned to the validator, or passed to your validator callback. These params are expected in a form where the key is the name of the property, and the value is the value to assign to the property.
In the example you provided, Yii sees that you want to utilize the "file" validator, so it creates an instance of yii\validators\FileValidator. It then sees that you want the parameter "extensions" set to "csv", so it does:yii\validators\FileValidator::$extensions = "csv"; But then, because you have included your custom validator in this part of the array, it thinks that "headerCheck" is actually a value of a property you want to assign to the validator. Because you have entered this "param" without a key, the key defaults to 0 and so Yii thinks the property you want to assign is called '0'. Thus, Yii attempts this: yii\validators\FileValidator::0 = "headerCheck";
Of course, there is no property '0' on FileValidator, and so that's where the error you're getting is coming from.
I am using Laravel 5.5.14 and created a request or validation with php artisan make:request CreateInviteRequest.
I want the user to not be able to invite themselves.
Is there a way to give a proper error saying "cannot be self"?
Right now I accomplished this with 'not_in:'.Auth::guard('api')->user()->id like this:
public function rules(Request $request)
{
return [
'invite_user' => ['numeric', 'exists:users,id', 'not_in:'.Auth::guard('api')->user()->id]
];
}
This gives error message The selected invite_user is invalid.
define messages
public function messages()
{
return [
'invite_user.not_in' => 'cannot be self',
];
}
You can add ID to ignore as third parameter to the exists() rule:
'invite_user' => 'numeric|exists:users,id,' . auth()->id(),
u can achieve this by Not In.
public function rules(Request $request)
{
return [
'invite_user' => 'required|email|unique:users,email',
Rule::notIn([Auth::guard('api')->user()->id]),
];
}
I am building an API, the desired output when there is an error is as follows:
{
"success": false,
"messages" : [
{
"field is missing for example",
....
}
]
}
I have a custom request called when from the controller as follows:
public function store(CoverageValueRequest $request, CoverageValueManager $manager){
$manager->create($request);
return response()->json(['success' => $manager->isSuccessful(), 'message' => $manager->getErrorMessage()]);
}
if the CoverageValueRequest has an error it would through something similar to this:
[
{
"series.0.values.0.cells": [
"The series.0.values.0.cells field is required when none of series.0.values.0.wifi are present."
],
"series.0.values.0.wifi": [
"The series.0.values.0.wifi field is required when none of series.0.values.0.cells are present."
]
}
]
How can I modify the error outcome of the custom request to follow the first posted structure.
Thanks in advance.
All you need to do is implementing your own failedValidation method. Default is
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException($this->response(
$this->formatErrors($validator)
));
}
In fact you should rather leave this method unchanged and implement your own version of default:
protected function formatErrors(Validator $validator)
{
return $validator->getMessageBag()->toArray();
}
I created a form with validation rules. Everything is fine, form is visible and works.
Problem is with validators. Only first validator works in addValidators([ ....])
My form class source code:
public function initialize()
{
$title = new Text('title');
$title->setLabel('Title of article');
$title->setFilters([
'striptags', 'trim'
]);
$title->addValidators([
new PresenceOf([
'message' => 'Title can not be empty'
]),
new StringLength([
'min' => 5,
'messageMinimum' => 'Title is too short. Should has more than 5 letters'
]),
new MYArticleAddCheckTitleValidator([
'message' => 'aaaaaaaaaaaaaaa'
])
]);
$this->add($title);
..........
Validator PresenceOf works fine. validation flash message is visible.
Validator StringLength does not work. It looks like form doesn't know about it
Validator MYArticleAddCheckTitleValidator (my own validator class) - the same as StringLength.
Phalcon version 2.0.4 on windows.
Any proposition, or suggestions ?
Thanks a lot.
Using Phalcon\Flash\Direct
The best way to get around this problem is to use flash messages, with the class Phalcon\Flash\Direct. You can find the documentation here.
This strategy is used by the phalcon vokuro project which I suggest you to look at.
The key of this solution is the message() function inside your form class.
Form class
<?php
namespace Your\App\Forms;
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
use Phalcon\Validation\Message;
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\StringLength;
use Your\App\Validation\MYArticleAddCheckTitleValidator;
class YourForm extends Form {
public function initialize()
{
$title = new Text('title');
$title->setLabel('Title of article');
$title->setFilters([
'striptags', 'trim'
]);
$title->addValidators([
new PresenceOf([
'message' => 'Title can not be empty'
]),
new StringLength([
'min' => 5,
'messageMinimum' => 'Title is too short. Should has more than 5 letters'
]),
new MYArticleAddCheckTitleValidator([
'message' => 'aaaaaaaaaaaaaaa'
])
]);
$this->add($title);
}
/**
* Prints messages for a specific element. Call it in the view
*/
public function messages($name)
{
if ($this->hasMessagesFor($name)) {
foreach ($this->getMessagesFor($name) as $message) {
$this->flash->error($message);
}
}
}
}
Controller
<?php
namespace Your\App;
use Your\App\YourForm;
class YourController extends ControllerBase
{
public function indexAction()
{
$form = new YourForm();
$this->view->form = $form;
if($this->request->hasQuery('title')){
if ($form->isValid($this->request->getQuery()) != false) {
// Code when form is valid
}
}
}
}
View
If you follow the suggested schema should be located in /app/views/your/index.html
<form method="GET" action="">
<?= $form->label('title') ?>
<?= $form->render('title')?>
<?= $form->messages('title') //show messages here ?>
</form>
If you have more than one form, it is useful to register the flash service with the DI.
When you define your services (could be in the index.php in the root folder or services.php in the /app/config/ folder) you define your flash service:
<?php
use Phalcon\DI\FactoryDefault;
$di = new FactoryDefault();
// Register the flash service with custom CSS classes
$di->set('flash', function () {
$flash = new Phalcon\Flash\Direct(
array(
'error' => 'your-error-class',
'success' => 'your-success-class',
'notice' => 'your-notice-class',
'warning' => 'your-warning-class'
)
);
return $flash;
});