Jump to content


Photo

How to create an intuitive interface for dependency management combined with code includes?


  • Please log in to reply
No replies to this topic

#1 AbayoB

AbayoB
  • New Members
  • Pip
  • Newbie
  • 1 posts

Posted 22 February 2017 - 01:58 PM

Heya,

 

I am building on 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 inside a different scope, so I 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 because the dependency container is defined in a different scope, this object is not visible when working inside an include file.

 

The question that arises is: 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;
    }
}

An include file would look like this:

<?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?

Also, a variable is not standing out into the page, which seems to be what I need here for readability.

 

I have searched in the Laravel Framework, but they use Facades, which I think looks awesome, but is to much work to implement ATM.

Static classes that are stateful, which is what the dependency container would be, are bad practice, is it not?

 

Pure based on readability, this looks great:

App::get('SomeClass');

This does not:

$app->get('SomeClass');

Are there more options to choose from?






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users