# 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:
- Ogni richiesta viene reindirizzata al file index.php utilizzando il modulo di riscrittura di Apache
- Lo script
index.php
avviaapp class
e chiama la funzionestart_app()
- La funzione
start_app()
analizza l'URL e utilizzaGET/POST
variabili per generare un percorso verso una determinata pagina - Ogni dipendenza caricata è contenuta in
dependencyLoader
- 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. - 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?