Override core single page within a package

Permalink
I want to add some custom functionality to the page_not_found single page, which I know can be done by just copying the controller to the root /controllers directory, but I would like to do it within the context of a package.

Is there any way to get a single page to look within package for the controller?

jgarcia
View Replies:
jgarcia replied on at Permalink Reply
jgarcia
After doing a little bit of research, I don't think this is actually possible. If someone knows for sure otherwise let me know...
nazweb replied on at Permalink Reply
This is still a top hit on Google, so I'll share how I got around this problem. First, you can't change the package id of a page through the update method.

public function install() {
   $pkg = parent::install();
   $pkgID = $pkg->getPackageID();
   $p = Page::getByPath('page_not_found');
   $p->update(array('pkgID' => $pkgID));
}


This code will, at the time of this post, never update pkgID. In my package controller I had to write custom code to update it, since I didn't want to delete and re-create it.

The other problem is that Concrete5 has an order of precedence when overriding a single page. It checks in DIR_FILES_CONTENT, DIR_FILES_CONTENT_REQUIRED and then finally in the page's package. That means you can never override anything in the concrete/single_pages folder at a package level. I got around this by renaming these files in the controller. Here is my example code, it's highly situational, so please don't copy and paste. Ideally Concrete5 would just change its order of evaluation so that package single pages are looked at first.

private function takeOverSinglePage(\Package $pkg, $page_path) {
   $db = \Loader::db();
   $core_file = DIR_FILES_CONTENT_REQUIRED . rtrim($page_path, '/') . '.php';      
   if(file_exists($core_file)) {
      if(!rename($core_file, $core_file.'.naz-common-overridden.php')) {            
         throw new \Exception("Could not override {$core_file}.  Please ensure the user has permissions to the directory.");
      }
   }      
   $db->query("update Pages set pkgID = ? where cID = ?", array($pkg->getPackageID(), Page::getByPath($page_path)->getCollectionID()));
}


You can call it like this:

$this->takeOverSinglePage($pkg, '/page_not_found');


Your executing user has to have rights to the folder. There are cleaner ways to do this! This is really just a proof of concept to illustrate the problem and a potential solution.
ijessup replied on at Permalink Reply
ijessup
Your install function should look something like:
public function install() {
   $pkg = parent::install();
   $pkgID = $pkg->getPackageID();
   $p = Page::getByPath('page_not_found');
   $p->update(array('pkgID' => $pkgID));
}

Not tested, but should work. Just change the path to the page you want to change.

A dashboard page would be something like:
Page::getByPath('dashboard/reports/logs');


- IJ
jgarcia replied on at Permalink Reply
jgarcia
Yeah, I tried that actually. I also tried

$p = Page::getByPath('page_not_found');
$p->delete();
//Add a new single page name with page /page_not_found


but apparently there's some hard-coded stuff in the dispatcher that causes it to not look at the package when loading the 404 page.
ijessup replied on at Permalink Reply
ijessup
Hmmmm... look at the Pages table and look to see if the code actually changed the pkgID of the page in question.

If the code didn't work than I would editing the DB manually through the install script.
andrew replied on at Permalink Reply
andrew
After deleting the page, did you reinstall the new single page pointing to /page_not_found with your pagckage as well? If so and it's still not working then you're right, we probably have a bug.
Mnkras replied on at Permalink Reply
Mnkras
my question, what if package 1 installs a page_not_found singlepage that for examples adds a logo, then how would package 2 for example add some text in the center,

how would we do this without manually merging the files
jgarcia replied on at Permalink Reply
jgarcia
In theory, I don't think this is really possible. A single page can only be associated with one package (or with no package).
jgarcia replied on at Permalink Reply
jgarcia
Yes, andrew, I did re-install the page with the following code:

$pkg = parent::install();
$pageNotFound = SinglePage::add('/page_not_found', $pkg);


I checked the DB and confirmed that the package ID for the single page did match up, but it still did not work as expected.
bobkennedy replied on at Permalink Reply
I made this happen, but I feel dirty. Maybe you could tell me if I've horribly overstepped...

I added the file to my package, then did a require_once() to get it from the file at {docroot}/single_pages/same_directory/same_script

Thusly:
require_once($_SERVER["DOCUMENT_ROOT"]."/packages/packagename/single_pages/dashboard/users/search.php");


I realize that this doesn't allow it to be installed automatically, but that doesn't matter in my case.