Jump to content

Fatal Error Page created via API if Template has Filefield


kixe
 Share

Recommended Posts

Pages are created via API. The assigned template has an Image- or Filefield.
PagefilesManager path() method throws Exception if page->id is 0 (which is default in case of instantiation of new Page object).

Any ideas for a workaround?
For now I changed path() method in PagefilesManager Class. Not sure if this is a good idea ...

/**
 * Get the published path (for use with hooks)
 *
 */
	public function ___path() {
		if(is_null($this->path)) {
                // if(!$this->page->id) throw new WireException("New page '{$this->page->url}' must be saved before files can be accessed from it");
		// replacement
                if($this->page->id === null) throw new WireException("New page '{$this->page->url}' must be saved before files can be accessed from it");
		$this->path = self::_path($this->page);
	}
	return $this->path;
}

Error: Exception: New page '/admin/access/users//' must be saved before files can be accessed from it (in [...]/wire/core/PagefilesManager.php line 262)
#0 [...]/dev/wire/core/PagefilesManager.php(253): PagefilesManager->___path()
#1 [...]/dev/wire/core/PagefilesManager.php(213): PagefilesManager->path()
#2 [...]/dev/wire/core/PagefilesManager.php(67): PagefilesManager->createPath()
#3 [...]/dev/wire/core/PagefilesManager.php(55): PagefilesManager->init(Object(Page))
#4 [...]/dev/wire/core/Page.php(1921): PagefilesManager->__construct(Object(Page))
#5 [...]/dev/wire/core/Pagefiles.php(74): Page->filesManager()
#6 [...]/wire/core/Pagefiles.php(58): Pagefiles->setPage(Object(Page))
#7 [...]/dev/wire/modules/Fieldtype/FieldtypeImage.module(33): Pagefiles->__construct(Object(Page))
#8 [...]/dev/wire/core/Fieldtype.php(479): FieldtypeImage->getBlankValue(Object(Pag

Opened an issue here: https://github.com/ryancramerdesign/ProcessWire/issues/1259

Link to comment
Share on other sites

Yes I have read this, but it should be possible to instantiate a page and assign a template to this page, without getting errors. I don't want to access or save any files at the moment. It works proper with all the other fieldtypes.

Link to comment
Share on other sites

Can you show code or tell what you're doing? From the error you create new user, and this works fine here with file fields on user template.

$u = new User();
$u->name = "test2";
$u->save();
Link to comment
Share on other sites

I use a module FormProcessor which is a derivation of Ryans FormTemplateProcessor. This module initialize a page instance, assign a specific template to it. Then a form based on this template will be rendered in frontend. The page will be saved AFTER submission and validation. The problem is the render of the file inputfield if empty and with a page->id = 0, which is default for new page instances (unsaved pages).
I am getting the error in the frontendform template.

init() and set() method of module

	/**
	 * Initialize a web form
	 *
	 *
	 */
	public function init() {
		// create a page for holding form fields
		$this->page = new Page();
		$this->page->id = 0;

		// Template to use for the form fields (required).
		// must be a Template object, it will be assigned to $this->page.
		$this->set('template', null);

	 	// Optional E-Mail address that form will get submitted to
		$this->set('email', '');

	 	// E-Mail sender
		$this->set('fromEmail', 'noreply@example.org');

		// Array of field names that are required to complete the submission
		// if not specified, it will use the admin field settings.
		$this->set('requiredFields', array());

	 	// Array of field names that should be skipped when drawing AND processing the form, blacklist
		$this->set('skipFields', array('title'));

	 	// Array of field names that will be added to the form when drawing AND processing the form
	 	// whitelist. If empty all fields are added
		$this->set('showFields', array());

	 	// Associated Array of fieldnames and values that should be skipped when drawing the form but will be processed if set via API in the form-template file. Set $fieldname => $value
		// $form->hiddenFields = array('myHiddenFieldKey'=>'myHiddenFieldValue');
		$this->set('hiddenFields', array());

		// Subject of the email that will be sent 
		$this->set('emailSubject', 'Web Form Submission'); 

		// Optional parent for the page.
		// If ommited, the page will not be saved to the DB.
		$this->set('parent', null);

		// Status of page which stores submitted form data
		$this->set('status', 2048); //default unpublished

		// message output upon successful completion of the form. You have access to all submitted values to use them with sprintf()
		$this->set('successMessage', 'Thank you, your submission has been sent!'); 

		// field from where the page name is taken 
		$this->set('nameField', null);

		// submit field name and value
		$this->set('submitValue', 'submit');

		// set to true if email is sent and to page->id if page->save()
		// also hookable method success()
		$this->set('success', false);

	}

	/**
	 * Set properties to our Page Instance
	 *
	 */
	public function set($key, $value) {
		if($key == 'parent' && $value) {
			if(!$value instanceof Page) throw new WireException('Parent must be a Page object');
			$this->page->parent = $value;
		} else if($key == 'template' && $value) {
			if(!$value instanceof Template) throw new WireException('Template must be a Template object');
			$this->page->template = $value;
		}
		return parent::set($key, $value);
	}

// ....
Link to comment
Share on other sites

This FormTemplateProcessor is older and wasn't meant to work with file/image fields, because of "you need to save page before files.."

protected function ___savePage($form) {

    if(!$this->contact->parent) return; 

    $this->contact->name = date('y-m-d-H-i-s-u');

    if(in_array('title', $this->skipFields)) {
        $this->contact->title = date($this->dateFormat);
    }

    if(ProcessWire::versionMajor == 2 && ProcessWire::versionMinor == 0) {
        $this->contact->status = Page::statusHidden;
        $this->contact->removeRole('guest');
    } else {
        // PW 2.1 and above
        $this->contact->status = Page::statusUnpublished; 
    }

    $this->contact->save();
}

You'd need to change how the script saves the page values to exclude file fields, save page and add files.

Apart from that I doubt the rendering of a file or even image field in the way this module is set does work, as when you render a form from a page's (input)fields will throw problems as file field in a context of a page isn't working as it needs a page that is existing and saved. It's designed for backend primarily.

// get the collection of inputs that can populate this page's fields
$inputfields = $this->contact->getInputfields();

// make all the fields required and add them to the form
foreach($inputfields as $inputfield) {
    if(in_array($inputfield->name, $this->skipFields)) continue; 
    if(in_array($inputfield->name, $this->requiredFields)) $inputfield->required = true; 
    $form->add($inputfield);
}

It can get tricky to use this approach and need special workarounds to get this working. File fields need a page id to know where to store and upload the image. So after submitting and processing the form the page should already be created and the file will get uploaded no matter if the form was valid or not and so on.

Link to comment
Share on other sites

This FormTemplateProcessor is older and wasn't meant to work with file/image fields, because of "you need to save page before files.."

protected function ___savePage($form) {

}

You'd need to change how the script saves the page values to exclude file fields, save page and add files.

I made many changes to the module. savePage method is different in my module. It is working proper with last PW Versions, even with new fields like ProfieldsTable or so.

Apart from that I doubt the rendering of a file or even image field in the way this module is set does work, as when you render a form from a page's (input)fields will throw problems as file field in a context of a page isn't working as it needs a page that is existing and saved. It's designed for backend primarily.

[...]

It can get tricky to use this approach and need special workarounds to get this working. File fields need a page id to know where to store and upload the image. So after submitting and processing the form the page should already be created and the file will get uploaded no matter if the form was valid or not and so on.

I don't want to render an image or file before page is saved. I know that an id is needed to create the assets-folder. Filefield is not rendered before page is saved. I excluded the field by skipping it in the render method. But no success. If it is part of the template the error occurs anyway.

Found a solution by adding a hook to the render method in the module in case of new page.

         // prevent error if fieldtype file or image is assigned and page has id = 0
        $this->addHookBefore('PagefilesManager::path', function ($e) {$e->replace = true;$e->return = null;});
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...