Ik doe in mijn MVC nu in elke controller dit, als ik een view wil laten zien:


<?php
// Voorbeeld, maakt niet echt uit waar variabelen vandaan komen
$data = array("title" => "Beveiligde pagina"
              "username" => $username,
              "css_href" => $url,
              "subpage" => "views/users/settings.php",
              "subpage_content" => "views/users/email-settings.php",
              
              "email" => $email,
              "form_msg" => $form_msg,
              );             
$this->loadView("views/users/index.php", $data);
?>


Elke controller extends de Base Controller. Daardoor heeft elke controller de methode loadView om een view weer te geven. De methode loadView krijgt ook nog de $data parameter mee, dat is een array met de variabelen die de view nodig heeft. Deze array wordt ge-extract.
Ik kan dus maar 1x data aan de view meegeven. Daardoor moet ik in bijna elke controller opnieuw dezelfde variabelen in de $data array zetten en meegeven aan loadView.
Ik had dus bedacht om een nieuwe laag toe te voegen tussen de controllers. Bijvoorbeeld de UserAreaController voor alles van het gedeelte waar bv. een gebruiker ingelogd moet zijn.
Dan krijg je:
Controller (base controller)
|- UserAreaController
|- (de specifieke controller van een pagina)

In die UserAreaController kan ik dan in de constructor alle (boilerplate) variabelen maken. Het probleem is dus dat ik dan meerdere keren data moet mee kunnen geven aan de view. Terwijl die view nog moet worden gemaakt in een lager gelegen controller.
Wat is dan beter: naast de loadView methode, een nieuwe methode maken in de base controller die bv. storeViewData heet. Dan sla ik daar tijdelijk de data op, totdat loadView wordt aangeroepen. Als die wordt aangeroepen wordt de eerder opgegeven (bewaarde) data ook ge-extract (net als de $data in de loadView parameter) en zo wordt dus alles berijkbaar in het view bestand.
Of helemaal die $data parameter van loadView eruit halen, en via een aparte methode van de base controller de data meegeven. Zodat er een aparte methode is voor het laden (includen) van een view, en een aparte voor het meegeven van de data.
Jan terhuijzen op 05/07/2014 18:14:43

Het probleem is dus dat ik dan meerdere keren data moet mee kunnen geven aan de view. Terwijl die view nog moet worden gemaakt in een lager gelegen controller.


Feitelijk is er geen lager gelegen controller.

Dit:
<?php
class Controller
{
private $a;

public function a()
{
}
}

class UserController extends Controller
{
private $b;

public function b()
{
}
}
?>

Is (nagenoeg) hetzelfde als
<?php
class UserController
{
private $a;
private $b;

public function a()
{
}

public function b()
{
}
}
?>
Ja, maar ik denk ook niet dat dit het probleem is.
Het probleem zit vooral in de volgorde.
Als de view is gemaakt door loadView, kan ik niks meer aan de view veranderen. Een controller om de gebruikersinstellingen te veranderen moet nu dus ook data naar de view sturen die eigenlijk standaard al nodig is. Bijvoorbeeld de begruikersnaam rechts boven in beeld, de href voor de stylesheet etc. Dan zou ik in elke methode (action) van een controller opnieuw een lange array neer moeten zetten. Het is eigenlijk best simpel. Ik zoek gewoon een manier om meerdere keren data naar de view te kunnen sturen uit verschillende controller klassen (lagen) *, vóórdat de view is geladen natuurlijk.

* Dit is natuurlijk heel makkelijk al gedaan door overerving
Maar goed de een Controller is gewoon een class waarin je private functies kunt aanroepen:

<?php
class UserController
{
public function indexAction()
{
$data = array_merge(
$this->_getStandardBehavior(),
array(
"blabla" => "jajaja",
"zozozo" => "mooimooi",
)
};

$this->loadView("views/users/index.php", $data);
}

public function viewAction()
{
$data = array_merge(
$this->_getStandardBehavior(),
array(
"blabla" => "neeneenee",
"zozozo" => "oeioeioei",
)
};

$this->loadView("views/users/index.php", $data);
}

private _getStandardBehavior()
{
return array(
"title" => "Beveiligde pagina"
"username" => $username,
);
}
}

?>

De view laden doe je als allerlaatste inderdaad.
Dat is ook een manier! i.p.v. de stukjes apart aan de view meegeven kun je ook de data van verschillende plekken halen zoals hier:

<?php
$this->_getStandardBehavior(),
            array(
                "blabla" => "neeneenee",
                "zozozo" => "oeioeioei",
            )
?>

Dan hoef je ook maar 1x de data aan de view te geven.
Je kunt ook overwegen om per pagina verschillende controllers aan te roepen. de eerste wordt aangeroepen door de router. alle volgende vanuit de view.

index.php (view)

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>

<body>
	<nav>
		<?php render('MenuController:indexAction'); ?>
	</nav>

	...

</body>
</html>
Kun je niet de $data attribuut in je Base Controller zetten?

Dus zoiets?


class Base_Controller
{
    public $data = array();

    public function __construct()
    {
        $this->data = array("title" => "Beveiligde pagina"
              "username" => $username,
              );  
    }
}

class UsersController extends Base_Controller
{
    public function __construct()
    {
        parent::__construct();
    }

    public function index()
    {
        $this->data['subpage'] = 'views/users/settings.php';
        $this->data['subpage_content'] = 'views/users/email-settings.php';
        $this->loadView("views/users/index.php", $this->data);
    }
}

Ja zeker dat kan ook maar dan zou je dus wel in elke controller met $this->data moeten gaan werken, anders ben je niet consequent bezig.
Ik doe het gewoon zo: loadView heeft de $data parameter gewoon, en er komt naast loadView nog een andere methode in de base controller die setViewData heet.
De hele view data wordt opgeslagen als property in de base controller.
Zo doe je de data gewoon instellen met setViewData(), en eventueel later nog bij loadView($path, $data).
In loadView heb je dan de $data parameter als een aanvulling op de (eventueel) eerder gevulde $data property van de base controller. In de methode loadView kun je de array dan samenvoegen etc.

Reageren