zf2 form validation (zfcAdmin and BjyAuthorize rel

2019-08-04 09:12发布

I'm facing validation problems integrating my custom module in zfcAdmin and BjyAuthorize.

My form class:

...    
$formOptions = $this->settings->getFormSettings();
foreach ($formOptions as $field){
if (isset($field['field']))
    $this->add($field['field']);        
}
...

My filter class:

$formOptions = $this->settings->getFormSettings();
foreach ($formOptions as $filter){
if (isset($filter['filter']))
    $this->add($filter['filter']);   
}
...

Fields, filters and other options are retrieved from config file.

Basically everything works fine: form data can be added, edited or deleted from db. Also after the zfcAdmin module installation no problem rose. Everything works fine using both 'site/mymodule' route and 'site/admin/mymodule' route: i can still add, edit and delete items from db.

Here the problem: I need some form elements (a Select in this particular case) editable/viewable only by administrator. (I can write a new controller/entity class 'ad hoc' for admin but i would like to use the same code for the whole site.)

I installed and configured bjyoungblood/BjyAuthorize module: it allowed me to display some form elements/fields only to admin but when i'm in edit mode a form validation error is displayed: "Value is required and can't be empty"

Here the code:

//view/mymodule/mymodule/update.phtml
<div id="page" style="margin-top: 50px;">

<?php if (isset($this->messages) && count($this->messages) > 0 ): ?>
<?php foreach ($this->messages as $msg): ?>
<div class="alert alert-<?php echo $this->escapeHtmlAttr($msg['type']); ?>">
    <?php if (isset($msg['icon'])) echo '<i class="'.$this->escapeHtmlAttr($msg['icon']).'"></i>&nbsp;'; ?><?php echo $this->escapeHtml($msg['message']); ?>
</div>
<?php endforeach; ?>
<?php endif; ?>

<?php
$title = 'Edit Item';
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>

<?php
$form = $this->form;
$form->setAttribute('action', $this->url($this->route . 'mymodule/update', array('action' => 'update', 'id' => $this->id )));
$form->prepare();
$form->setAttribute('method', 'post');
$input = $form->getInputFilter();

?>

<?php echo $this->form()->openTag($form) ?>
<dl class="zend_form">
    <?php foreach ($form as $element): ?>

        <?php
            //CHECK USER PRIVILEDGES
            $elName = $element->getName();
            $elResource = isset($this->form_options[$elName]['auth']) ? $this->form_options[$elName]['auth']['resource'] : "userresource"; 
            $elPrivilege = isset($this->form_options[$elName]['auth']) ? $this->form_options[$elName]['auth']['privilege'] : "view";

            //SHOW THE ELEMENT IF ALLOWED
            if($this->isAllowed($elResource, $elPrivilege)): 
        ?>
            <?php if ($element->getLabel() != null): ?>
                <dt><?php echo $this->formLabel($element) ?></dt>
                <?php endif ?>
            <?php if ($element instanceof Zend\Form\Element\Button): ?>
                <dd><?php echo $this->formButton($element) ?></dd>
                <?php elseif ($element instanceof Zend\Form\Element\Select): ?>
                <dd><?php echo $this->formSelect($element) . $this->formElementErrors($element) ?></dd>
                <?php else: ?>
                <dd><?php echo $this->formInput($element) . $this->formElementErrors($element) ?></dd>
                <?php endif ?>
           <?php else: ?>
           <?php        

           ?>          
        <?php endif ?> 

    <?php endforeach ?>
</dl>
<?php echo $this->form()->closeTag() ?>


</div>
<div class="clear-both"></div>

My controller action

//controller
        public function updateAction(){
            $messages = array();
            $id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
            $form = $this->getServiceLocator()->get('FormItemService');

            $itemMapper = $this->getItemMapper();
            $item = $itemMapper->findById($id);
            $form->bind($item);

            $request = $this->getRequest();

            if($request->isPost()){
                $form->setData($request->getPost());
                if ($form->isValid()) {             
                    die('c');//never here
                    $service = $this->getServiceLocator()->get('mymodule\Service\Item');
                    if ( $service->save($form->getData()) )
                    {
                        $messages[] = array(
                                'type'    => 'success',
                                'icon'    => 'icon-ok-sign',
                                'message' => 'Your profile has been updated successfully!',
                        );
                    }
                    else
                    {
                        $messages[] = array(
                                'type'    => 'error',
                                'icon'    => 'icon-remove-sign',
                                'message' => 'Profile update failed!  See error messages below for more details.',
                        );
                    }
                }else{
                    var_dump($form->getMessages());//Value is required and can't be empty
                }
            }

            return array(
                'messages' => $messages,    
                'form' => $form,
                'id' => $id,    
                'form_options' => $this->getServiceLocator()->get('mymodule_module_options')->getFormSettings(),
                'route' => $this->checkRoute($this->getEvent()->getRouteMatch()->getmatchedRouteName())
            );
        }

If user is not allowed to view the resource, the element is not echoed. So $request->getPost() has no value for that form element and an error is returned by isValid().

Has anyone solved a similar problem or can anyone point me to the right direction? Thanks

2条回答
贼婆χ
2楼-- · 2019-08-04 09:42

The problem is that you don't do any security check in your FormFilter class, where you define your required fields.

The $form->isValid() function checks the posted data against those filter elements. So it's not enough to prevent the 'echo field' in your view, you still need to apply the security check to the filter element.

查看更多
Bombasti
3楼-- · 2019-08-04 09:48

One other approach would be to make two forms one for the front end and one for the admin. Since the one for the admin will have the same fields plus one extra select field you can make the admin form extends the front end one. E.g.

class myForm 
{
    public function __construct(...) 
    {
         // add fields and set validators
    }
}

and the admin form could be:

class MyAdminForm extends myForm
{
    public function __construct(...)
    {
        parent::__construct(...);
        // add the extra field and extra validator
    }
}

In that way even if you edit the front end form (or validators) the back end will always be up to date.

Hope this helps :),

Stoyan

查看更多
登录 后发表回答