View Issue Details

IDProjectCategoryView StatusLast Update
16391Bug reportsPluginspublic2020-06-18 18:17
Reportergabrieljenik Assigned To 
PrioritynoneSeverityfeature 
Status newResolutionopen 
Product Version3.22.20 
Summary16391: Allow beforeModelSave and Dynamic model events to do validations
DescriptionCurrently, `beforeModelSave` and Dynamic model events can't be used for custom validations to be done on tokens, responses or any model.

Although Yii does accept it by the `isValid` attribute, this can't be used on the plugins.
The `isValid` atribute is part of the modelEvent object and that object is not sent to the plugin events handlers.

As it, the objectve of the feature is to hook up the Yii isValid attribute from the modelEvent to the plugins.
Additional Information# Code Samples
Please find below some code samples already developed as PoC.
Please notice a new `eventParams` parameter on the the `dispatchPluginModelEvent` and the `_dispatchDynamic` method.

```
        public function beforeSave(CModelEvent $event)
        {
            $this->dispatchPluginModelEvent('before'.get_class($this->owner).'Save', NULL, ["modelEvent" => $event]);
            if (!$event->isValid) return FALSE;

            $this->_dispatchDynamic('before','Save', ["modelEvent" => $event]);
            if (!$event->isValid) return FALSE;

            $this->dispatchPluginModelEvent('beforeModelSave', NULL, ["modelEvent" => $event]);
            if (!$event->isValid) return FALSE;

            return TRUE;
        }
        
        /**
         * Log parent event for dynamic (currently Token and Response)
         * and related id
         * @param string $when
         * @param string $what
         * @return PluginEvent the dispatched event
         */
        private function _dispatchDynamic($when,$what, $eventParams = [])
        {
            if(is_subclass_of($this->owner,'Dynamic')) {
                $params = array(
                    'dynamicId' => $this->owner->getDynamicId()
                );
                $params = array_merge($eventParams, $params);
                return $this->dispatchPluginModelEvent($when.get_parent_class($this->owner).$what,null,$params);
            }
        }
        
        /**
         * method for dispatching plugin events
         *
         * See {@link find()} for detailed explanation about $condition and $params.
         * @param string $sEventName event name to dispatch
         * @param CDbCriteria $criteria
         * @param array $eventParams array of params for event
         * @return PluginEvent the dispatched event
         */
        public function dispatchPluginModelEvent($sEventName, $criteria = null, $eventParams = array())
        {
            $oPluginEvent = new PluginEvent($sEventName, $this);
            $oPluginEvent->set('model', $this->owner);
            if(method_exists($this->owner,'getSurveyId')) {
                $oPluginEvent->set('iSurveyID', $this->owner->getSurveyId());
                $oPluginEvent->set('surveyId', $this->owner->getSurveyId());
            }
            foreach($eventParams as $param => $value) {
                $oPluginEvent->set($param, $value);
            }
            if (isset($criteria)) {
                $oPluginEvent->set('filterCriteria', $criteria);
            }
            return App()->getPluginManager()->dispatchEvent($oPluginEvent);
        }
    }
```

Also please find below a sample plugin method implementation:
```
        public function beforeTokenSave()
        {
            $event = $this->getEvent();

            $M = $event->get("modelEvent");
            $M->isValid = FALSE;
            $event->set("modelEvent", $M);
        }
```
TagsNo tags attached.
Complete LimeSurvey version number (& build)3.22.13
I will donate to the project if issue is resolvedNo
Browser
Database & DB-VersionMysql
Server OS (if known)
Webserver software & version (if known)
PHP Version7

Activities

gabrieljenik

gabrieljenik

2020-06-16 23:00

manager   ~58320

Last edited: 2020-06-16 23:04

View 2 revisions

As per error messages, they could be added to the model.
Not the best fit sometimes, as an error may not be tied to any specific attribute, but to a multiple combination of attributes.

An alternative would be to add some kind of error message array to the LSActiveRecord, as to use for general errors output from the plugin events.
DenisChenu

DenisChenu

2020-06-17 08:26

developer   ~58321

Let me check if we can addError easily or if we need to allow update rules too …

:)
DenisChenu

DenisChenu

2020-06-18 08:47

developer   ~58329

@gabrieljenik : not return TRUE finally : return parent ;)

Else isValid by plugins can be only false , I like to have only : return `$event->isValid && parent::beforeSave();` :)
gabrieljenik

gabrieljenik

2020-06-18 14:48

manager   ~58331

You know what?
I wasn't able to find a parent definition for PluginEventBehavior::beforeSave (). Is there one?
DenisChenu

DenisChenu

2020-06-18 14:56

developer   ~58332

You're right,

https://www.yiiframework.com/doc/api/1.1/CActiveRecord#onBeforeSave-detail
> This event is raised before the record is saved. By setting CModelEvent::isValid to be false, the normal save() process will be stopped.


I's an event …

Only before validate return : https://github.com/LimeSurvey/LimeSurvey/blob/0d2e1df50ecd9bb2cbff8548837a29cc760b46ab/framework/base/CModel.php#L187

https://github.com/LimeSurvey/LimeSurvey/blob/master/framework/base/CModel.php#L152-L165
gabrieljenik

gabrieljenik

2020-06-18 17:42

manager   ~58338

The name of the class cModelEvent doesn't help much. I guess part of all the confusion came from there.
DenisChenu

DenisChenu

2020-06-18 18:17

developer   ~58339

We don't have CModelevent ? Maybe it's totally impossible here to set isValid to false …

Add https://github.com/LimeSurvey/LimeSurvey/blob/0d2e1df50ecd9bb2cbff8548837a29cc760b46ab/framework/base/CModel.php#L179-L186 :)

Issue History

Date Modified Username Field Change
2020-06-16 21:45 gabrieljenik New Issue
2020-06-16 22:59 gabrieljenik Additional Information Updated View Revisions
2020-06-16 23:00 gabrieljenik Note Added: 58320
2020-06-16 23:04 gabrieljenik Note Edited: 58320 View Revisions
2020-06-17 08:26 DenisChenu Note Added: 58321
2020-06-18 08:47 DenisChenu Note Added: 58329
2020-06-18 14:48 gabrieljenik Note Added: 58331
2020-06-18 14:56 DenisChenu Note Added: 58332
2020-06-18 17:42 gabrieljenik Note Added: 58338
2020-06-18 18:17 DenisChenu Note Added: 58339