processwire / processwire-issues

ProcessWire issue reports.
44 stars 2 forks source link

Cannot create a page with a page class static method #1938

Open jlahijani opened 1 month ago

jlahijani commented 1 month ago

Please view video: https://www.youtube.com/watch?v=eWjSORgMXNA

Potentially related: https://processwire.com/talk/topic/29931-can-not-set-template-to-new-page-created-from-custompagestaticmethod-corrupted-admin/

Short Description... I can't do this:

// /site/classes/WidgetPage.php
class WidgetPage extends Page {
  public static function foo() {
    $p = new WidgetPage();
    $p->template = 'widget';
    $p->parent = wire('pages')->get("/widgets/");
    $p->name = 'x';
    $p->title = 'x';
    $p->save();
  }
}

WidgetPage::foo();

But I can do this:

// /site/classes/WidgetPage.php
class WidgetPage extends Page {
  public static function foo() {
    foo();
  }
}

// ready.php
function foo() {
  $p = new WidgetPage();
  $p->template = 'widget';
  $p->parent = wire('pages')->get("/widgets/");
  $p->name = 'x';
  $p->title = 'x';
  $p->save();
}

WidgetPage::foo();
BernhardBaumrock commented 1 month ago

@jlahijani does it work when changing to this:

$p->template = wire()->templates->get('widget');

This works for me:

class WidgetPage extends Page
{
  public static function foo()
  {
    $p = new WidgetPage();
    $p->template = wire()->templates->get('home');
    $p->parent = wire()->pages->get(2);
    $p->name = 'x';
    $p->title = 'x';
    return $p;
  }
}

bd(WidgetPage::foo());
jlahijani commented 1 month ago

@BernhardBaumrock Yes, that worked! What's the explanation for this?

szabeszg commented 1 month ago

What's the explanation for this?

See: https://processwire.com/talk/topic/25557-weekly-update-%E2%80%93-7-may-2021/?do=findComment&comment=214109

Quote from Ryan: "The reason I prefer to call it as a function $this->wire()->pages rather than a property $this->wire->pages (or $this->pages) is because it will work consistently everywhere in PW"

hiboudev commented 1 month ago

@szabeszg Your explanation doesn't look related with the issue, or maybe I miss something. You can check my forum thread to see that template is not retrieved by string when called from custom page class static method. It is retrieved from string when called from another class, or by using "templates->get()" API variable. So that looks like a bug in the API. https://processwire.com/talk/topic/29931-can-not-set-template-to-new-page-created-from-custompagestaticmethod-corrupted-admin/

matjazpotocnik commented 1 month ago

One can also use the $page->setTemplate($tpl) or $page->template($tpl) method, where $tpl can be string, obj, or template ID.

@ryancramerdesign, looking at the Page class, docs about setTemplate() method:

     * // The following 3 lines are equivalent
     * $page->setTemplate('basic-page');
     * $page->template = 'basic-page';
     * $page->templates = $templates->get('basic-page'); 

Is this info correct?

ryancramerdesign commented 1 month ago

It's a strange PHP behavior, but if you are in a particular class and you create a new object of the same class within it, it has direct access to protected properties of the new object you created, despite it being a completely different instance than the one you are in. So if you are setting native Page properties like $page->template = 'something' from within a Page object, it bypasses the internal __set(), set() and setTemplate('something') methods that would usually be called and instead directly sets the internal $template property of the page without any logic applied to it. The way to avoid it is to use methods for setting native page property values, such as set(), i.e. $page->set('template', 'something'); when you are manipulating a Page from within a Page class. I don't think it matters of a static method is involved or not.

matjazpotocnik commented 1 month ago

it bypasses the internal __set(), set() and setTemplate('something') methods that would usually be called and instead directly sets the internal $template property of the page without any logic applied to it.

Yes, that's exactly what I observed. Thanx for the explanation.

Regarding the correctness of the docs, is there a typo in $page->templates = $templates->get('basic-page'); (plural in $page->templates)?