Get access to Page from PageController

Hello @all,

I´m using a route to a controller:

SilverStripe\Control\Director:
  rules:
    'abteilung': 'App\Control\MyPageController'

By handling the request in the controller I want to overwrite properties of the corresponding myPage before returning the rendered page in the response. If I load the Page as DataObject

MyPage::get(...)

I´m able to set the properties. This works so far for the properties of MyPage itself. This page uses Elemental-blocks and i want to update properties of these blocks too. This works not.

If i debug the MyBaseElement-constructors i notice my debug-statements twice. Are the two instances of MyBaseElement in place and is this the reason why my properties-update is not visible after rendering?

Best regards,
chrclaus

I noticed, that a new instance of myPage is created, and therefore my setProperty is lost.

    public function index($request)
    {
        // GET param
        $myParam = $request->latestParam('$1');
        $myPage = MyPage::get_one(MyPage::class, ....);
        $myPage->setMyParam($param);
        return $myPage->renderWith('Page');
    }

Handling the HTTPRequest in MyPageController, i loaded myPage from db and set a property, which is derived from the URL. By calling

 return $myPage->renderWith('Page');

a new instance of myPage is created and initialized. How should i handle page-rendering keeping my properties set before?

Following the CMS Docs by

    public function index($request)
    {
        // GET /staff/managers/bob
        // managers/bob
        $request->remaining();
    }

returns an empty Response and results in a blank page. I have no idea, how to handle the URL-request correctly and i assume, that my problem is located in handling the request. Does anybody has an idea?

I’m not entirely sure what your working towards here, but you might be over-complicating things.

In a controller, you can generally get access to the current page model with $this->data()

You may not even need that though, depending what you’re trying to achieve. You can pass data directly into the renderer in the second argument of 'render(), and for some things you can even just set it globally with $this->SomeProperty = ‘foo’;` and it will become available in the template.

If you can expand a little on the actual problem you’re trying to solve, that might give some clues to the best approach.

Thank you, maybe I oversimplified my problem.

I’m creating a page for my sports club, and my pages have categories like badminton, basketball, etc - this is stored as a property in the DB.
We have many sports where the site will look identical with small exceptions. I would now like to create a generic page where I can overwrite the category from the URL so that I only have to create and maintain a single generic page in cms.

Routing and handling the URL is not a problem. Unfortunately, overwriting in the DataObject does not work because the value is apparently reloaded from the DB. This is by itself correct for unwritten DB modifications.

I’ve already thought about data extensions. Since these are also stored in the DB, I probably will have the same problem.

I’m looking for a solution where I can overwrite properties of generic pages at runtime, but store them in the DB for specific pages. Do you have any idea?

It still sounds to me like you’re making life more complicated that it needs to be. It sounds like you want to use your dataobjects as pages… it’s a little out of date, but have a look here: https://www.silverstripe.org/learn/lessons/v4/controller-actions-dataobjects-as-pages-1

That shows how to get a dataobject based on the request and render it using a common template.

This, to me, sounds like a bit of an anti-pattern, and it may be the root of some of the confusion. I’d suggest trying to make your architecture consistent… if you need different functionality for different pages, that’s exactly why SIlverstripe has different page subclasses.

If the intention is to display some values differently to how they’re stored, you can achieve this by adding methods that are only used in templates.

For example if your $db field was named Category and you want to display that in a certain way in the template, you might implement a getCategoryForTemplate() method in your page class.

You can then call that using $CategoryForTemplate in the template. No need to mess around with director routing rules or anything like that.

Thanks for all hints. My GenericPage is a subclass of Page and I want to derive properties from URL. Handling these properties in the action-handler in my GenericPageController and setting instance-properties (not db-attributes) is not a problem. I´m using silverstripe-elemental in my GenericPage and be not able to pass these instance-properties to my elemental-blocks. Accessing the properties in the elemental-block via ownerpage returns null.

Enabling DNADesign\Elemental\TopPage\SiteTreeExtension and DNADesign\Elemental\TopPage\DataExtension adds TopPageID to the elements. Accessing the ID from template works, other properties on TopPage set by the controller remains null.

I do not understand, why all my updates on the concrete instance of my GenericPage object are lost, when ElementalArea is rendered in the templates … I´, using 4.13.

An alternative solution i looked for was accessing the url-params in my elemental-block again, to derive my properties twice. But i did not get the params in an acceptable way.