Jump to content

Validating field before page save


thetuningspoon
 Share

Recommended Posts

I'm not sure where to look for this one. I would like to be able to do some custom validation on a WYSIWYG field (checking to make sure some custom tags have matching closing tags) before a page is saved in the admin, and prevent the save and provide an error message if it fails to validate. I gather that this means hooking into the page's save method, but where do I get the pre-save field data from and where should my custom code go?

Thanks!

Link to comment
Share on other sites

Usually this is a good and simple method:

In a autoload module you hook into the processInput of InputfieldTextarea.

public function init(){
    $this->addHookAfter("InputfieldTextarea::processInput", $this, "validateText");
}

public function validateText($event){
    $field = $event->object;
    
    if($field->name == "body"){
        $page = $this->modules->ProcessPageEdit->getPage();
        $oldValue = $page->get("$field->name");
        $newValue = $field->value;
        echo "old value: " . $oldValue;
        echo "new value: " . $newValue;
        if($newValue !== $oldValue){
            $field->value = $oldValue;
            $field->error("Go away!");
        }
    }
}

For a error message you simply add error("text") to the field. It will get showed after saving. What this examples also shows nicely is how to get the old value and new value.

The code may slightly varies for different type of fields but the principle is always the same. There's also a method to hook into Pages::saveReady() but I'm not sure what the advanced really are atm.

  • Like 9
Link to comment
Share on other sites

Soma, when you say that the error message will get shown after saving, does that mean that in your example the new value would be lost and overridden with the old? I don't want to lose the new value, but just to prompt the user to fix it before saving. Would that possibly be a case for hooking into Pages::saveReady() instead?

Link to comment
Share on other sites

I don't know how to prevent page from getting saved. Whatever you mean by definition "save page".

What about other fields that are correct and edited, they will get lost? So PW will save page regardless, except for fields that are validated, the inputfield processInput defines what get's saved (not sure in details and have no time to test out). But required fields will just throw an error.

So in this case PW saves the page but you won't be able to publish it until all "validation/required" errors are gone, only then the page can be published.

So whatever you do with old and new value is up to you. As soon as you throw an error PW says this:

  • Session: Change: body

  • Session: Saved Page: /de/about/ (1 change) - Cannot be published until errors are corrected

  • Session: Go away! (body)

  • Like 2
Link to comment
Share on other sites

I understand. Ideally, the page would continue to display with the old database values on the front end while in the editor the new values would just be repopulated (i.e. they would be stored in the session until they were all validated). Nothing would be overwritten until everything was validated for saving to the database. But I see that that isn't how PW is designed to handle validation.  

Basically, the thing that I would want to avoid is having the page disappear from the website (unpublish) due to the client making an error. I would rather it continue to show the old values on the front end and let the user see and fix his error on the backend.

It sounds like the upcoming draft system would probably solve this problem.

Link to comment
Share on other sites

It is a CMS page after all and not a front-end from where you make submission and it won't get sent before all errors are corrected. I understand what you're saying and in future this for sure will be possible. Currently publish/unpublished, creating, editing page is limited to that there's only one version of a page and one status. So editing a page and not being able to save it because a field is not valid may cause issues and keeps the page in a state the user can't go on (maybe he doesn't know etc) and all data will get lost. Anyway many scenarios and things that can happen with such validation. Saving in session wouldn't scale.

It's not as simple and we're even in a privileged situation where PW at least has validation and field dependencies etc, I don't know of a similar CMS that has this anyway. PW is designed to do it all and more you can't even dream of :D, but Ryan has only two hands and one brain, 16 hours a day. But I'm sure he could provide more and better worded answers than me.

Yes exactly: versioning/draft versions of pages will for sure give you more what you need here.

  • Like 2
Link to comment
Share on other sites

I don't want to lose the new value, but just to prompt the user to fix it before saving. Would that possibly be a case for hooking into Pages::saveReady() instead?

It might be feasible to do something like Soma's function above, where it populates the old (valid) value back when an invalid value is received. But rather than throwing out the old value, remember it a session variable. Then your module would also hook after ProcessPageEdit::buildForm and cycle through the any saved session variables, populating back the values it recorded (and removing them from the session). It's necessary to use session variables here just because there is a redirect between saving an editing again, something that is not obvious when you are using PW to edit pages. I would recommend something like:

$values = array(
   123 => array( // indexed by page_id
        'date_from' => 'October 33, 2013', // invalid date
        'body' => 'some bad words here', // invalid value 
        ); 
$session->set('PageEditBadValues', $values); 

Also wanted to recommend hooking ProcessPageEdit::processInput rather than InputfieldForm::processInput, just so that you are limiting the action to the PageEdit form and not getting involved with other InputfieldForms unnecessarily. 

Your after(ProcessPageEdit::buildForm) function might look like this:

function hookPageEditBuildForm($event) {
  $form = $event->arguments(0); 
  $page = $event->object->getPage();
  $values = $this->session->PageEditBadValues; 
  if(empty($values) || empty($values[$page->id])) return;
  $values = $values[$page->id];
  foreach($values as $fieldName => $value) {
    $inputfield = $form->getChildByName($fieldName);
    if(!$inputfield) continue;
    $inputfield->attr('value', $value); 
  }
}
  • Like 3
Link to comment
Share on other sites

  • 1 year later...

Hi, 

I was looking whether I can validate the page before it is saved and get errors . Eg : 

$page = new Page();
$page->template = 'some-template';
$page->field1 = 'some-value';
$page->setOutputFormatting(true);
$page->save();

Assume there is 

$page->field2

which is also required. Is there a way I can validate and get the errors?

Link to comment
Share on other sites

Basically what I am doing is trying to build the form depending on the template .

public function buildForm()
{
        $form = $this->modules->get('InputfieldForm');
        $form->set('protectCSRF', false);
        $template = $this->templates->get($template);
        foreach ($template->fields as $field) {

            $f = $this->modules->get('InputfieldText');
            $f->name = $field->get('name');
            $f->required = $field->get('required');
            $form->add($f);
        }
        return $form;
}

So I could do a

$form->processInput($this->input->post);

One of the problem here is the field is always Text. Is there a better way to pass the field to the form, so the other properties can also be validated. Eg : Email, Url etc.

Also even there is input with post values it is showing error, that the value is required in 

$form->getErrorrs()

Thank you.

Link to comment
Share on other sites

You're right that it requires a form to run processInput(), creating and saving a page via API doesn't validate anything

Like this, but won't work with file fields.

$p = new Page();
$p->template = "basic-page";
$p->parent = 1;
// $p->save();

$in = new WireInputData();
$in->setArray(array("title" => ""));

$form = $modules->InputfieldForm;

foreach($p->fields as $field){
    $inputfield = $field->getInputfield($p);
    $form->add($inputfield);
}

$form->protectCSRF = false;
$form->processInput($in);

foreach( $form->getErrors() as $err ) {
    $content .= $err;
}
  • Like 2
Link to comment
Share on other sites

Hi Soma, 

I was trying the code 

$p = new Page();
$p->template = "basic-page";
$p->parent = 1;

$in = new WireInputData();
$in->setArray(array("title" => "Hello World"));

$form = $modules->InputfieldForm;

foreach($p->fields as $field){
    $inputfield = $field->getInputfield($p);
    $form->add($inputfield);
}

$form->protectCSRF = false;
$form->processInput($in);

foreach( $form->getErrors() as $err ) {
    $content .= $err;
}

but even if there is title it is showing title is empty on the errors. Do you know what may be the reason ?

Thank you.

Link to comment
Share on other sites

Hi Soma,

I understood you need to pass all the fields that are required. If you miss a field, all the errors are thrown than throwing the missing one.

I have also added a way to iterate through the fields and set the value on the Page.

foreach ($form->getIterator() as $field) {
    $f = $field->name;
    $page->{$f} = $this->input->post->{$f};
}

Thanks!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...