Iniezione delle dipendenze - Oggetti nidificati

3

# Introduzione

Sto lavorando su un'applicazione CMS in PHP con circa 200 classi. Il CMS, in generale, fa la stessa cosa di ogni CMS: genera siti.

Sto imparando molto su OOP e sui modelli di progettazione e solo da poco ho iniziato a imparare a creare un codice gestibile usando Dependency Injection.

Il problema è che non so come risolvere i problemi che ho attualmente e con quale modello di progettazione.

# Possibili soluzioni

Ho letto le seguenti (possibili) soluzioni:

  • Il servizio fornisce
  • Contenitori di iniezione delle dipendenze
  • Classi di fabbrica
  • Iniezione delle dipendenze
  • Etc ...

Tutte le soluzioni sembrano avere vantaggi e svantaggi, ma più ne leggo, più difficoltà ne ho scelta.

# Il problema

Il problema più grande è la dipendenza da stato, come page o site che contengono dati caricati dal database, in un oggetto annidato all'interno di altre classi.

Per spiegarlo meglio, penso che sia meglio mostrarti un esempio. Il flusso del sistema è qualcosa del tipo:

  1. Ogni richiesta viene reindirizzata al file index.php utilizzando il modulo di riscrittura di Apache
  2. Lo script index.php avvia app class e chiama la funzione start_app()
  3. La funzione start_app() analizza l'URL e utilizza GET/POST variabili per generare un percorso verso una determinata pagina
  4. Ogni dipendenza caricata è contenuta in dependencyLoader
  5. Una volta caricate tutte le dipendenze, viene analizzato un file modello e ogni riga viene controllata per tag specifici (ad esempio <!-- CSS-FILE --!> ) e i dati dalle dipendenze vengono quindi visualizzati in HTML e posizionati al posto del tag.
  6. Se viene trovato un tag, viene chiesto alle dipendenze se contiene dati per questo specifico tag e restituiscono oggetti specifici che rendono i loro dati in un modo univoco. Per esempio. oggetti come "phpInclude", "cssFile", "elemento", "metaData" ecc.

La classe dell'app è simile a questa (semplificata):

     class app {

        protected $dependencyContainer;

        function __construct() {
            $this->dependencyContainer = new dependencyContainer();
        }

        public function start_app() {

            // 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()) {
                            $fragment->render($this->dependencyContainer);
                        } else {
                            $fragment->render();
                        }
                    }
                // Process lines, echo the ones that are plain HTML
                } else {
                    echo $line;
                }
             }
        }
    }

Gli oggetti restituiti (frammenti) possono essere di due tipi:

elementFragment {
     protected $data;
     const needDependencies = false;

     public render() {
          // Render logic here
          return 'SOME HTML';
     }
}

dependencyFragment {
     protected $data;
     const needDependencies = true;

     public render($dependencies) {
          if($dependecies->has('page')) $page = $dependencies->get('page');
          if($dependecies->has('site')) $site = $dependencies->get('site');
          // Etc etc etc etc etc

          // Logic to generate HTML here
          // E.g the phpInclude fragments has logic like this:
          return include __PATH__ . $this->data;
     }
}

Il problema sorge quando ho un altro livello di oggetti all'interno dell'oggetto dependencyFragment . Questa è purtroppo una situazione comune.

# Domande

  • Continuo a spingere dependencyContainer in ogni chiamata di funzione o costruttore di oggetti?
  • O forse uno schema (statico) di singleton è una soluzione migliore per ospitare le dipendenze e renderle disponibili?
posta Abayob 17.02.2017 - 17:00
fonte

0 risposte

Leggi altre domande sui tag