I am building a PHP CMS system that parses template files and replaces tags with content. Sometimes this content is a HTML, CSS or JS snippet, but it can also be a code include.
Most code includes use dependencies, already set in the main scope: the app class, where the start() function resides and all needed domain objects are loaded.
Some of these objects are: site
, URL
, page
, etc..
The PHP scripts are included in a different scope, so I am can't access the dependencies the way I want -> from the app class.
I am thinking about Dependency Injection using a dependency container class, but of course, this is not visible when working inside an include.
How do I keep the dependencies accessible in an intuitive way?
Code example:
class app {
protected $dependencyContainer;
function __construct() {
$this->dependencyContainer = new dependencyContainer();
}
// Called by index.php
public function start() {
// Load in navigator that contains routing information
$this->dependencyContainer->set('navigator', new navigator($_SERVER['REQUEST_URI'], $_SERVER['HTTP_HOST']));
// Load site data
$domainController = new domainController();
$site = $domainController->loadSite($this->dependencyContainer->get('navigator'));
$this->dependencyContainer->set('site', $site);
$pageController = new pageController();
$page = $pageController->loadPage($this->dependencyContainer->get('navigator'));
$this->dependencyContainer->set('page', $page);
// Etc...
// Etc...
$templatePath = $site->getTemplate();
$this->renderDocument($templatePath);
}
private function renderDocument($templatePath) {
$template = file_get_contents($templatePath);
$lines = explode("\n", $template);
foreach($lines as $line) {
// If a tag is found, the dependencies are asked if it contains data for this
if($tag = $this->filter($line)) {
$fragments = $this->dependencyContainer->output($tag);
foreach($fragment as $fragment) {
if($fragment->needDependencies()) {
// AT THIS POINT I TRAVERSE INTO AN OBJECT AND
// INCLUDE A PHP SCRIPT
$fragment->render($this->dependencyContainer);
} else {
$fragment->render();
}
}
// Process lines, echo the ones that are plain HTML
} else {
echo $line;
}
}
}
}
The fragment object that the dependencies are passed to:
class dependencyFragment {
protected $data;
const NEEDSDEPENDENCIES = true;
// THIS IS THE LOCAL SCOPE OF THE INCLUDE:
public function render($dependencies) {
return include __PATH__ . $this->data;
}
}
A script file that gets included:
<?php
// Do I comment in every script file that the variable $dependencies is set and is usable?
// And just call it like this?
$dependencies->get('page')...
I have the feeling this is very hard to understand without first understanding how and where the dependencies are set and injected?
Is this usual way to go?