Search

For a member registration, I'd like to customize a standard front-end event created by Symphony and add checkbox validation (we have terms of service that need to be accepted in order to finish registration): the event should return an error when the checkbox is not checked by the user.

I've never used events that much and a few things seem to have changed under the hood with the 2.3 release, so I'm looking for the simplest way to add my additional validation.

Are there any recommendations?
How do the cool kids handle this today?

Does making the checkbox required in the section not give you the error XML response when the checkbox is not checked?

Ironically, checkboxes cannot be required. There is an extension but it hasn't been updated to 2.3 yet and I'd like the numbers of extensions low – that's why I thought about customising the event.

Oh, I see! Sorry for the useless post. :-) I'd either forgotten or just didn't realise.

You could modify the event before the include or create an extension to use EventPreSaveFilter to check if the box is checked. The latter:

    public function getSubscribedDelegates(){
        return array(

                    array(
                        'page' => '/frontend/',
                        'delegate' => 'EventPreSaveFilter',
                        'callback' => 'customCheck'                         
                    ),
        );
    }

    public function customCheck(&$context){
        if(isset($context['fields']['waiver']) && $context['fields']['waiver'] != 'yes')
        {
            $context['messages'][] = array('waiver', false, 'You must agree to the terms and conditions by checking the waiver box.');
        }
    }

Creating the filter as extension sounds like a good idea.
Thanks for the code, Lewis!

Right, this works quite well.

Question: Is there a way to stop the event execution and still get the validation results from the other fields? Currently – using the code above – I only get the result of my own validation but I'd like to display possible errors for all fields in my front-end form and not just for the checkbox.

Is there a way to stop the event execution and still get the validation results from the other fields?

I don't think so. You'll have to override the execute method and copy+paste the checking stuff from original event. Here's the grosso modo part:

$result = new XMLElement($this->ROOTELEMENT);

$post = General::getPostData();
$fields = $post['fields'];

$post_values = new XMLElement('post-values');
if (is_array($fields) && !empty($fields)) {
    General::array_to_xml($post_values, $fields, true);
}

$entry =& EntryManager::create();
$entry->set('section_id', $this->getSource());

if(__ENTRY_FIELD_ERROR__ == $entry->checkPostData($fields, $errors, false)){
    $result->setAttribute('result', 'error');
    $result->appendChild(new XMLElement('message', __('Entry encountered errors when saving.')));

    foreach($errors as $field_id => $message){
        $field = FieldManager::fetch($field_id);

        if(is_array($fields[$field->get('element_name')])) {
            $type = array_reduce($fields[$field->get('element_name')], '__reduceType');
        }
        else {
            $type = ($fields[$field->get('element_name')] == '') ? 'missing' : 'invalid';
        }

        $result->appendChild(new XMLElement($field->get('element_name'), null, array(
            'label' => General::sanitize($field->get('label')),
            'type' => $type,
            'message' => General::sanitize($message)
        )));
    }
}
else{
    $result->setAttribute('result' ,'success'));
    $result->appendChild(new XMLElement('message', 'Entry checked successfully')));
}

if(isset($post_values) && is_object($post_values)) $result->appendChild($post_values);

return $result;

You could do something like:

$result = parent::execute();

Which would run the normal routine, and then you might be able to modify the result. This works for data sources, but not sure what is returned from events (hopefully an XMLElement to which you can append more elements).

Yeah, but running parent::execute() will create the entry if it validates.

Good point.

Thanks guys for your help and the code examples. Everything is working now how it needs to: I've customized my event by changing the load() function to the following:

    public function load(){
        if(isset($_POST['action']['mitglieder-anmeldung'])) {

            // TOS not accepted
            if(isset($_POST['fields']['nutzungsbedingungen']) && $_POST['fields']['nutzungsbedingungen'] != 'yes') {
                $result = new XMLElement($this->ROOTELEMENT);

                $post = General::getPostData();
                $fields = $post['fields'];

                $post_values = new XMLElement('post-values');
                if (is_array($fields) && !empty($fields)) {
                    General::array_to_xml($post_values, $fields, true);
                }

                $entry =& EntryManager::create();
                $entry->set('section_id', $this->getSource());

                // Check other fields
                $entry->checkPostData($fields, $errors, false);

                $result->setAttribute('result', 'error');
                $result->appendChild(new XMLElement('message', __('Entry encountered errors when saving.')));

                foreach($errors as $field_id => $message){
                    $field = FieldManager::fetch($field_id);

                    if(is_array($fields[$field->get('element_name')])) {
                        $type = array_reduce($fields[$field->get('element_name')], array($this, '__reduceType'));
                    }
                    else {
                        $type = ($fields[$field->get('element_name')] == '') ? 'missing' : 'invalid';
                    }

                    $result->appendChild(new XMLElement($field->get('element_name'), null, array(
                        'label' => General::sanitize($field->get('label')),
                        'type' => $type,
                        'message' => General::sanitize($message)
                    )));
                }

                // Add TOS error message
                $result->appendChild(new XMLElement('nutzungsbedingungen', null, array(
                    'label' => 'Nutzungsbedingungen',
                    'type' => 'invalid',
                    'message' => 'Du musst die Nutzungsbedingungen und Datenschutzerklärung akzeptieren.'
                )));

                // Append post values
                if(isset($post_values) && is_object($post_values)) {
                    $result->appendChild($post_values);
                }

                return $result; 
            }

            // TOS accepted
            else {
                return $this->__trigger();
            }
        }
    }

I have to say that event management is not very intuitive. I'm quite surprised how much PHP knowledge is needed to get things going – not very Symphony-like.

Thanks again for your help.

I'm quite surprised how much PHP knowledge is needed to get things going

Tell me about it ... It took me a while to understand what's going on in a section event.

But on the other side, it's PHP code inside a framework. With some basic knowledge (after spending time reading the docs) it's really comprehensible.

I still wouldn't expect the need of that much PHP for the end user in a framework focussing on XML and XSLT :)

Currently – using the code above – I only get the result of my own validation but I'd like to display possible errors for all fields in my front-end form and not just for the checkbox.

Hmm... you can combine error messages and filter messages in your XSLT. That's what I've done.

you can combine error messages and filter messages in your XSLT.

Yes, that would be possible if both were in the XML. But I didn't get any else but the filter messages.

Better solution?!

http://symphonyextensions.com/extensions/conditionalizer/

Not the extension I remember, conditionals for event saving is a hidden feature.

Would Nils' code above for validating chained event post data? I'd like to ensure the data from a chained event with multiple entries are valid before allowing the first one in the chain to trigger.. so was thinking to deal with all of the post data in one job lot and deny the trigger if any part of the event failed.

Hey Lewis, is there any documentation regarding the conditional event saving application for conditionalizer at all?

Wondering if this field could be used to check if from date and to dates are valid before allowing the entry to be submitted..

i.e. If someone enters an end date + time that is older than the start date and time input fields.. Conditionalizer would trigger an error for the user on the front end.

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details