ZF2 - Allow an empty input file on submit - zend-framework2

I have a form that allows a user to edit his information and upload an image. The image upload is optional but when I submit the form, I always have an error telling me that the image has not been uploaded.
Here is the partial fieldset code:
public function init() {
$this->add([
'name' => 'avatar',
'type' => 'file',
'attributes' => [
'id' => 'avatar',
'class' => 'input-file',
'accept' => 'image/*'
],
'options' => [
'label' => 'avatar',
]
]);
}
This fieldset implements InputFilterProviderInterface, so here is the code:
public function getInputFilterSpecification() {
return [
'avatar' => [
'type' => '\Zend\InputFilter\FileInput',
'allow_empty' => true,
'required' => false,
'validators' => [
[
'name' => 'FileExtension',
'options' => [
'extension' => ['jpg, jpeg, png'],
'message' => 'wrong_type_file'
]
],
[
'name' => 'FileSize',
'options' => [
'max' => '2MB',
'message' => 'file_too_large'
]
]
],
],
];
}
Despite the fact that this field is not required and allow_empty option is true, when I submit the form and debug the value, I still have validation that fails and this as my debug value:
'avatar' =>
array (size=5)
'name' => string '' (length=0)
'type' => string '' (length=0)
'tmp_name' => string '' (length=0)
'error' => int 4
'size' => int 0
Do you know how could I validate my form event when no file is downloaded?
Thanks in advance for your answers!
EDIT 1: Here are the messages returned by the form after submission:
'avatar' =>
array (size=2)
'fileExtensionNotFound' => string 'Extension d'image non admise (.jpg, .jpeg, .png seulement)'
'fileSizeNotFound' => string 'Le fichier est trop volumineux, 2097152 maximum.' (length=48)
EDIT 2: the action in the controller:
$prg = $this->fileprg($form);
if ($prg instanceof Response) {
return $prg;
} elseif (is_array($prg)) {
$data = $form->getData();
if ($form->isValid()) {
if ($data['person']['file']) {
// #TODO upload file
}
if (!$this->personMapper->updatePerson($data)) {
$this->flashMessenger()->addErrorMessage($this->translator()->translate('error_occurs_backup'));
} else {
$this->flashMessenger()->addSuccessMessage($this->translator()->translate('data_saved'));
}
} else {
// #TODO file error management
\var_dump('not valid');
\var_dump($form->getMessages());
}
}

Related

Yii2: GridView: add button or link to controller action

I have a controller with an action method:
namespace frontend\controllers;
class EmployeeController extends FrontController
{
/**
* Deletes an existing Employee status.
* #param integer $id
* #return mixed
*/
public function actionDeleteStatus($status_id)
{
error_log("actionDeleteStatus " . $status_id);
return $this->redirect(['update']);
}
}
In update form, I have a detail GridView, in which I want to add a "delete" link with an URL for this method as a GET request.
I try to get the URL with this: Url::toRoute(['employee/deleteStatus','status_id' => $model->status_id]) which gives me an url like /employee/deleteStatus?status_id=4 and throws a 404, here is the detailed code:
<div class="col-xs-12">
<?php
echo Html::label(Yii::t('app', 'Employee status history'));
echo GridView::widget([
'summary' => '',
'options' => [
'id' => 'status-history',
],
'emptyText' => '',
'export' => false,
'dataProvider' => $statusHistory,
'columns' => [
[...],
[
'class' => 'kartik\grid\DataColumn',
'attribute' => 'status_id',
'headerOptions' => [ 'class' => 'kv-grid-hide' ],
'contentOptions' => [ 'class' => 'kv-grid-hide' ]
],
[
'class' => 'yii\grid\ActionColumn',
'urlCreator' => function($action, $model, $key, $index) {
return Url::toRoute(['employee/deleteStatus','status_id' => $model->status_id]);
},
'template' => '{delete}',
'contentOptions' => ['class' => 'column-action'],
'buttons' => [
'delete' => function ($url, $model, $key) {
if (Yii::$app->user->can('globalDAF')) {
$options = [
'title' => Yii::t('app', 'Delete'),
'aria-label' => Yii::t('app', 'Delete'),
'data-confirm' => Yii::t('app', 'Sure to delete status?'),
'data-method' => 'post',
'data-pjax' => '0',
'class' => 'btn-llyc'
];
return Html::a('<span class="glyphicon glyphicon-remove"></span>', $url, $options);
} else {
return;
}
}
]
]
],
'hover' => true,
'responsiveWrap' => false
]);
?>
</div>
Is the url generation wrong? Why am I getting a 404?
Thanks.
For example, index becomes actionIndex, and hello-world becomes
actionHelloWorld.
Note: The names of the action methods are case-sensitive. If you have
a method named ActionIndex, it will not be considered as an action
method, and as a result, the request for the index action will result
in an exception. Also note that action methods must be public. A
private or protected method does NOT define an inline action.
Link
Url::toRoute(['employee/delete-status','status_id' => $model->status_id])
Or in config file:
'urlManager' => [
'class' => 'yii\web\UrlManager',
#code ..
'rules' => [
'employee/deleteStatus' => 'employee/delete-status',
],
],

Yii2: Sending params with Anchor as POST request

I try to get POST Variables in my controller from view with:
<?= GridView::widget([
'dataProvider' => $dataProvider_products,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
[
'label'=>'Name',
'format' => 'raw',
'value'=>function ($data) use ($model, $dataProvider_products) {
return Html::a($data['name'],['suppliers_orders/addproduct', 'order' => $model->id, 'product' => $data['id'],
'data-method'=> 'post',
'data-params' => ['dataProvider' => $dataProvider_products],
]);
},
],
'supplier_product_number',
'size',
'price_net',
],
]); ?>
The parameter dataProvider will always be sent with the URL and results in a GET variable. What is wrong, respectively what must be done, that dataProvider will be sent as POST variable?
Part of my controller is:
public function actionAddproduct($order, $product){
// look for GET variable
$request = Yii::$app->request->get('data');
$dataProvider = $request['params']['dataProvider'];
// look for POST variable
$param1 = Yii::$app->request->post('dataProvider', null);
$dataProvider_suppliers_orders_products = $dataProvider;
return $this->actionView($order);
}
First of all you are passing the data-params in the url parameter rather than setting in the options parameter, so yes it will always be sent as query string no matter you pull your hairs off and become bald ¯\_(ツ)_/¯.
Then According to the DOCS
If the attribute is a data attribute as listed in
yii\helpers\Html::$dataAttributes, such as data or ng, a list of
attributes will be rendered, one for each element in the value array.
For example, 'data' => ['id' => 1, 'name' => 'yii'] generates
data-id="1" data-name="yii" and 'data' => ['params' => ['id' => 1,
'name' => 'yii'], 'status' => 'ok'] generates
data-params='{"id":1,"name":"yii"}' data-status="ok"
So, you need to change the anchor to look like
Html::a($data['name'], ['suppliers_orders/addproduct', 'order' => $model->id, 'product' => $data['id']], [
'data' => [
'method' => 'POST',
'params' => ['dataProvider' => $dataProvider_products]
]
]);
But since you are passing the $dataProvider object to the params it aint going to work because it will be changed to [Object Object] but if it is simple text then it will work, otherwise you have to change your approach.
Your complete code for the GridView should look like below
<?=
GridView::widget([
'dataProvider' => $dataProvider_products,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
[
'label' => 'Name',
'format' => 'raw',
'value' => function ($data) use ($model, $dataProvider_products) {
return Html::a($data['name'], ['suppliers_orders/addproduct', 'order' => $model->id, 'product' => $data['id']], [
'data' => [
'method' => 'POST',
'params' => ['dataProvider' => $dataProvider_products]
]
]);
},
],
'supplier_product_number',
'size',
'price_net',
],
]);
?>

Laravel Request showing error, _POST showing the variables

I have route.php like below :
Route::get('/edit/{num}', [
'as' => 'department.edit',
'middleware' => ['admin'],
'uses' => 'DepartmentsController#edit'
]);
Route::post('/update/{num}', [
'as' => 'department.update',
'middleware' => ['admin'],
'uses' => 'DepartmentsController#update'
]);
And edit.blade.php as below :
{!! Form::model($department, array('route' => ['department.update', Crypt::encrypt($department->id)], 'id' => 'department_update', 'class' => 'form-horizontal row-border')) !!}
#include('admin.departments._form')
{!! Form::label('', '', array('class' => 'col-md-2 control-label')) !!}
{!! Form:: submit('Update', ['class' => 'btn btn-success']) !!}
{!!form::close()!!}
And the DepartmentsController.php update() as :
public function update($id, Request $request) {
$id = Crypt::decrypt($id);
dd($_POST);
}
The above showing the POST variables :
array:3 [▼
"_token" => "UI6tBMuJlwmGZuaeB9ilJq6v0wUMOgKRlEY4eY0I"
"name" => "Material Management"
"department_code" => "MMD"
]
But if I try to output dd($request), it throws error
ReflectionException in AbstractCloner.php line 245: Class 1 does not
exist
Whats wrong ? Where I have made the mistake
Try this way, move your $request to 1st params.
public function update(Request $request, $id) {
$id = Crypt::decrypt($id);
dd($request->all());
dd($_POST);
}

ZF2 Adding filters with element definition

I am trying to add filters and validators with element definition. But so far it is not working. Here is my controller class code.
public function validateAction() {
$testVals = Array ('question1' => 'value1' );
$formMaker = $this->getServiceLocator ()->get ( 'ttForm\Maker' );
$form = $formMaker->generateForm();
$form->setData($testVals);
if ($form->isValid()){
echo "Valid form";
}
else{
print_r($form->getMessages());
echo "Invalid form";
}
die;
}
This is form class code
public function generateForm (){
$element = array (
'options' => array(
'label' => "First Name :",
),
'attributes' => array(
'required' => 'required',
'type' => 'text'
),
'name' => 'firstName',
'filters' => array(
array('name' => 'Zend\Filter\StringTrim'),
),
'validators' => array(
array(
'name' => 'not_empty',
)),
);
$form = new Form();
$form->add($element);
return $form;
}
As you can see in form class, I have attached filters and validators with element definition, it does not work. Looking at docs, it seems like we can do so. Can anybody point out missing link? Thanks.

Yii2 Kartik-V SideNav widget pass url method

How do we pass url method in the kartik v sidenav widget
echo SideNav::widget([
'type' => $type, 'encodeLabels' => false,
'heading' => $heading,
'items' => [
Yii::$app->user->isGuest ?
['label' => 'LOGIN', 'url' => '', 'active' => ($item == 'login')] :
['label' => 'LOGOUT', 'url' => 'site/logout', 'linkOptions' => ['data-method' => 'post']],
],
]);
I get error as logout needs method post
Where do we pass the data method in this widget
I also use kartk v sidenav widget andthis is my SiteController
class SiteController extends Controller
{
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'access' => [
.......
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
public function actionLogout()
{
Yii::$app->user->logout();
return $this->goHome();
}
}
in sidenav i simply have this
['label' => 'logout', 'url'=>Url::to(['/site/logout'])],
I had the same problem and used the template option for the SideNav widget. I was inspired by this SO answer.
Your code would look like this:
echo SideNav::widget([
'type' => $type, 'encodeLabels' => false,
'heading' => $heading,
'items' => [
Yii::$app->user->isGuest ?
['label' => 'LOGIN', 'url' => '', 'active' => ($item == 'login')] :
['label' => 'LOGOUT', 'icon' => 'log-out', 'url'=>Url::to(['/site/logout']), 'template' => '{icon}{label}' ]
],
]);
I added an icon as a little extra example.

Resources