I'm trying to understand how passing variables work exactly.
I've set a controller:
class indexController
{
public function calling()
{
$route = new Route():
$route->title = 'Register user';
$route->getview('users','register');
}
}
And a model:
class Route
{
public function getview($module,$filename)
{
require_once('templates/'.$module.'/'.$filename.'.phtml');
}
}
And a view file which has something like this:
<div class="title"><?php echo $this->title; ?></div>
How to set title for the view? Should I 'public' this var in controller, and get it while constructing model to use in my view file?
There are problems with your design but forgetting those this is a way you could do it.
public function var( $var, $val ) {
$this->vars[$var] = $val; // should disallow _view as a $var
}
public function getview($module,$filename)
{
$_view = 'templates/'.$module.'/'.$filename.'.phtml';
extract( $this->vars ); //creates variables for
require_once( $_view );
}
Use it like this
$route = new Route():
$route->var( 'title', 'Register user' );
$route->getview('users','register');
What gave you an impression that you are implementing MVC? Because from where stand, it looks like you have mixed up the responsibilities for each part of the pattern.
Here are the basics ..
MVC is an architectural design pattern, that is an expression of SoC principle. It separates the model layery (that is responsible for implementing domain business logic) from presentation layer. And within presentation layer it separates the parts that handle user input (controller) from logic that generates the user interface (view).
When applying this pattern to Web, the flow of information goes something like this:
controller receives request from users
controller alters the state of model layer and (maybe) the current view
view request necessary information from model layer
view produces a response to the user
What you have there is NOT a view, but simply a template. And what you have there is NOT model, but simply a class.
And now you questions:
How to set title for the view?
Your view should request the information, that it needs, from model layer:
namespace Views;
class Doclument
{
// ... some code
public function foobar()
{
$library = $this->serviceFactory->acquire('Library');
$title = $library->getCurrentDocument('title');
$content = $library->getCurrentDocument('content');
$this->template['main']->assign([
'title' => $title,
'body' => $content,
]);
}
// ... some more code
public function render()
{
/*
if any templates have been initialized,
here you would put code for combining them and
return html (or some other format)
*/
}
}
Off course, you would need to know, which document the user wanted to see .. that should be done in a controller:
namespace Controllers;
class Document
{
// ... again, some code, that's not important here
public function getFoobar( $request )
{
$library = $this->serviceFactory->acquire('Library');
$library->useLanguage( $request->getParameter('lang') );
$library->locateDocument( $request->getParameter('id') );
}
}
The $serviceFactory would be shared between both controllers and views, since it's how you interact with the model layer. This also gives you a way to initialize each service only once, without creating a dependence on global state.
Should I 'public' this var in controller, and get it while constructing model to use in my view file?
No.
Model layer (yes, it should be layer and not a class) should not be aware of anything from implementation of presentation layer. An actually, view should not be aware of controller's either.
Actually, having public variables in OOP is considered to be a bad practice (unless you are creating data structures .. think: stuff like binary trees). It causes your code to leak encapsulation.
P.S.
I'm trying to understand how passing variables work exactly.
That's basics of OOP. You should not be playing around with high-level constructs like MVC pattern, if you do not have a good grasp on OOP concepts, practices and methodology.
Look up thing called "dependency injection".
Related
Good Morning everyone. Recently i've read an article about mvc pattern saying that most of the php frameworks out there implemented the mvc pattern wrong.
php master mvc pattern part 1
php master mvc pattern part 2
Well after reading this and looking over that implementation a question appeared.
How on earth would call in the view the method called in model? What i'm trying to say is this.
This is a piece of code from the article.
<?php
$model = $_GET['model'];
$view = $_GET['view'];
$controller = $_GET['controller'];
$action = $_GET['action'];
if (!(empty($model) || empty($view) || empty($controller) || empty($action))) {
$m = new $model();
$c = new $controller($m, $action);
$v = new $view($m);
echo $v->output();
}
let's say we've written a small implementation of this design pattern after reading the article and we have the following code:
<?php
class Index extends Controller
{
public function __construct(IndexModel $model, $action)
{
$this->model = $model;
}
public function someAction($id)
{
$this->model->getData($id);
}
}
class Index extends View
{
public function __construct(IndexModel $model, $action)
{
$this->model = $model;
}
public function someAction()
{
$this->model->getData();
}
}
class Index extends Model
{
public function __construct()
{
//Some Code Here
}
public function someAction()
{
// Inserting Data into database.
}
}
As you can see we are calling the same method both in controller and in view to get the data from the database. But if i know correctly the view should take care of the controller's job so the $id wouldn't be right to parse it again in the view or something like that. Then how this can be solved?
There's no 1:1 correlation between controllers and parts of the model (note: not "models" but parts of _the model_). Just because you have an "index controller" doesn't mean you need an "index model" and "index view".
The M, V and C are not constructed together. The controller is constructed, and then it decides which model method to load/construct/invoke and which view should respond to the request.
There's discussion about whether the controller should invoke the view, or whether the model should "update" the view. Since web requests are ephemeral and there's no "constant" view, the latter makes little sense in PHP; it's more appropriate for the original SmallTalk or Obj-C or similar environments.
The first code snippet has terrible use of empty (see here) and, again, should not construct all parts together.
MVC should be approached like this:
The model is the app. It's not just a "data handler" or "data store", it is the core app. Everything the app does, business logic wise, is "the model". This includes sending email notifications, database maintenance work and such auxiliary things, they're all in the model.
The view is responsible for producing output of various forms. The view should be able to interact with the model to get the data it needs to do its job. Data should not be "pushed into" the view, the view should be able to "pull" the data it needs; otherwise something external to the view needs to know what data the view needs, which means the view logic is not self contained in the view anymore.
The controller is just the little bit of glue that's left to invoke the correct model method and view in response to the incoming request.
I typically structure these parts like this:
The model consists of various parts, including data storage handlers, "primitives" (classes that model individual business objects) and "services". The "services" contain all the "actions" your app can do and form the model API. Whenever you want to "do" something in the app like "register a user" or "fetch all records for date range X through Y", there's one specialized method for it in the service API. Just looking at this service API you should be able to enumerate all the things your app "does".
There's one object which is either a "dispatcher" or a "service locator" or simply a dependency injection container that simplifies instantiation of these service classes and allows someone to call them. The controller gets one of these and so does the view.
There's a router which does some "rough routing" based on the URL, invoking a controller method. The controller further looks at the details of the request and decides to call a model method and/or to respond with a view.
The view may decide the best way to present some data based on the specifics of the request, e.g. whether to respond with an HTML page or a JSON data blob. Yay for RESTful services.
In rough pseudo code:
$r = new Router;
$r->route($_GET, $_POST, $_SERVER); // or something like that
This dispatches to something like:
class FooController {
public function __construct(ServiceLocator $services) { ... }
public function bar(Request $request) {
$request->assertIsPost();
$this->services->locate('Baz')->froogleTheWibbles($request->getPostParams());
(new BarView($this->services))->displayWibbles($request);
}
}
class BarView {
public function __construct(ServiceLocator $services) { ... }
public function displayWibbles(Request $request) {
switch ($request->accepts()) {
case 'html' :
$this->loadTemplate(...);
...
case 'json' :
echo json_encode($this->services->locate('Baz')->getWibbles());
}
}
}
And the model does whatever it needs to do...
class Baz {
public function froogleTheWibbles(array $data) {
foreach ($data as $wibbleData) {
$wibble = new Wibble($wibbleData);
$this->wibbleStore->save($wibble);
}
...
}
}
There is no "one answer" for MVC, the important part is that the model contains everything your app "does" independent of input and output, the view can produce the right output as requested as independently as possible and the controller is just the little bit of glue that handles input conditions. There are various ways in which this can be realized. The important design principle should be the realization that the view and controller are interchangeable to fit different conditions (web page, JSON API, XML API, SOAP API, CLI invocation, ZeroMQ node etc.), but "the model" is not.
I realize this topic has been asked and addressed repeatedly, and although I've read through countless similar questions and read through countless articles, I'm still failing to grasp a few key concerns... I'm attempting to build my own MVC framework for learning purposes and to better familiarize myself with OOP. This is for personal private use, not to imply that as an excuse for being lazy, but rather I'm not so concerned with having all the bells and whistles of more robust frameworks.
My directory structure is as follows:
public
- index.php
private
- framework
- controllers
- models
- views
- FrontController.php
- ModelFactory.php
- Router.php
- View.php
- bootstrap.php
I have an .htaccess file with directs all requests to index.php, this file contains basic configuration settings such as timezone and global constants, and it then loads the bootstrap.php file. The bootstrap contains my autoloader for classes, starts the session, defines global functions to use throughout my project, and then calls the router. The router picks apart the request from the URL, validates it using a ReflectionClass, and executes the request in the form of example.com/controller/method/params.
All of my controllers extend the FrontController.php:
<?php
namespace framework;
class FrontController
{
public $model;
public $view;
public $data = [];
function __construct()
{
$this->model = new ModelFactory();
$this->view = new View();
}
// validate user input
public function validate() {}
// determines whether or not a form is being submitted
public function formSubmit() {}
// check $_SESSION for preserved input errors
public function formError() {}
}
This front controller loads the ModelFactory:
<?php
namespace framework;
class ModelFactory
{
private $db = null;
private $host = 'localhost';
private $username = 'dev';
private $password = '********';
private $database = 'test';
// connect to database
public function connect() {}
// instantiate a model with an optional database connection
public function build($model, $database = false) {}
}
And base View:
<?php
namespace framework;
class View
{
public function load($view, array $data = [])
{
// calls sanitize method for output
// loads header, view, and footer
}
// sanitize output
public function sanitize($output) {}
// outputs a success message or list of errors
// returns an array of failed input fields
public function formStatus() {}
}
Finally, here is an example controller to demonstrate how a request is currently processed:
<?php
namespace framework\controllers;
use framework\FrontController,
framework\Router;
class IndexController extends FrontController implements InterfaceController
{
public function contact()
{
// process form if submitted
if ($this->formSubmit()) {
// validate input
$name = isset($_POST['name']) && $this->validate($_POST['name'], 'raw') ? $_POST['name'] : null;
$email = isset($_POST['email']) && $this->validate($_POST['email'], 'email') ? $_POST['email'] : null;
$comments = isset($_POST['comments']) && $this->validate($_POST['comments'], 'raw') ? $_POST['comments'] : null;
// proceed if required fields were validated
if (isset($name, $email, $comments)) {
// send message
$mail = $this->model->build('mail');
$to = WEBMASTER;
$from = $email;
$subject = $_SERVER['SERVER_NAME'] . ' - Contact Form';
$body = $comments . '<br /><br />' . "\r\n\r\n";
$body .= '-' . $name;
if ($mail->send($to, $from, $subject, $body)) {
// status update
$_SESSION['success'] = 'Your message was sent successfully.';
}
} else {
// preserve input
$_SESSION['preserve'] = $_POST;
// highlight errors
if (!isset($name)) {
$_SESSION['failed']['name'] = 'Please enter your name.';
}
if (!isset($email)) {
$_SESSION['failed']['email'] = 'Please enter a valid e-mail address.';
}
if (!isset($comments)) {
$_SESSION['failed']['comments'] = 'Please enter your comments.';
}
}
Router::redirect('contact');
}
// check for preserved input
$this->data = $this->formError();
$this->view->load('contact', $this->data);
}
}
From what I'm able to understand, my logic is off for the following reasons:
Validation should be done in the Model, not the Controller. However, a Model should not have access to $_POST variables, so I am not entirely sure whether or not I'm doing this part correctly? I feel like this is what they call a "fat controller" which is bad, but I'm not sure what needs to change...
The controller should not send data to the View; instead, the View should have access to the Model to request its own data. So would moving the $data property out of the FrontController and into the ModelFactory, and then calling the View from the Controller without passing along data resolve this issue? Technically it would then adhere to the MVC flowchart, but the proposed solution seems like such an insignificant or even trivial detail, assuming it's that simple, which it probably isn't..
The part that has me questioning my whole implementation is that I have a User object that is instantiated with a users corresponding roles and permissions, and I've been trying to figure out how or more specifically where to create an isAllowed() method that can be called from both the Controller and View. Would it make sense then to put this method in the Model, since both the Controller and View should have access to the Model?
Overall, am I on the right track here or what glaring problems do I need to address in order to get on the right track? I'm really hoping for a personal response specific to my examples rather than a "go read this".. I appreciate any honest feedback and help.
The $_POST superglobals should be abstracted by a request instance, as explained in this post.
Input validation is not the responsibility of the controllers. Instead it should be handles by domain objects within model layer.
Model factory is no a model.
Defining class parameter visibility as public breaks the object's encapsulation.
HTTP location header (redirect) is a form of response. Thus, it should be handled by view instance.
In its current form, your controllers are directly manipulating superglobals. This causes tight coupling to the globals state.
Authorization checks should be performed outside controller. Not inside of it.
Your "model factory" should instead be a service factory, that is injected in both controller and view. It would ensure that each service is instantiated only once and thus let your controllers work with same model layer's state.
First, I think it's great you are trying to create you own framework. Many say that everyone should do this, if only for learning purposes.
Second, I would suggest you read this Wikipedia article on frameworks. Many people don't realize there are different patterns for routing (url dispatch, traversal), and views (push, pull).
Personally, I don't see a need to abstract out the super globals since they are already abstractions (by php) from the raw input (php://input) and can be modified. Just my opinion.
You are right that validation should be done by the Model. You don't validate forms, you validate data. As for the View accessing the data, that depends on the pattern you choose. You can push the data to the View, or the View can pull the data.
If you are curious, my attempt at a MVC basic framework is on github. Its 4 files, less 2K line of code (DB layer is 1K lines). It implements traversal (component) routing and pulls data, there were already plenty of frameworks that implement the alternate patterns.
Validation should be done in the Model, not the Controller. However, a
Model should not have access to $_POST variables, so I am not entirely
sure whether or not I'm doing this part correctly? I feel like this is
what they call a "fat controller" which is bad, but I'm not sure what
needs to change...
That is right, Model should know nothing about the request, so, you need to pass $_POST to the models, but it will not know that are request parameters.
One thing: validation that has nothing to do with business logic should stay in controller. Let's say, you create a CSRF token for your forms for security reasons, this valitadion should be inside the controller, because it handles requests.
The controller should not send data to the View; instead, the View should have access to the Model to request its own data. So would moving the $data property out of the FrontController and into the ModelFactory, and then calling the View from the Controller without passing along data resolve this issue? Technically it would then adhere to the MVC flowchart, but the proposed solution seems like such an insignificant or even trivial detail, assuming it's that simple, which it probably isn't..
That's not necessarily true. This approach is called Active Model, and normally you use the Observer pattern, with models being observed by the views. If some model changes, it notifies the view that will update itself. This approach is more suitable for desktop applications, not web-based ones. In web applications, the most common is to have controllers as intermediaries between model and view (Passive Model). There's no right approach, you should choose the one you like the most.
The part that has me questioning my whole implementation is that I have a User object that is instantiated with a users corresponding roles and permissions, and I've been trying to figure out how or more specifically where to create an isAllowed() method that can be called from both the Controller and View. Would it make sense then to put this method in the Model, since both the Controller and View should have access to the Model?
Well, this one there's no way, I'll have to tell you to read about ACL.
I was too sleepy when I asked the question, so sorry for that, anyway to make things clear I prepared the question for 2 hours.
I'm trying to organize my code and decided to organize it mvc'ish(mvc-like), I don't know if I can follow all the principles, but I wanted to be at least close to that.
My application has a front-controller (dunno if my definition is right), so that all the http-request of my application will be passing through a single point, in my case the index.php in the root directory of my application.
Having said that I have set it up like that, you can imagine that I used .htaccess to direct all request to index.php.
I exploded the url and created an array out of it, $url[] like so. So whenever I access my app like this http://localhost/app/pagename it'll be accessing a controller (pagename_controller)
I did it like this :
$file = $controller_path . $page . '_controller.php';
if (file_exists($file)) {
require $file;
$class_name = ucfirst($page) . '_controller';
$target = new $class_name();
}
also I wrap it up in a Container, the 'decorator pattern', for future use, validations maybe.
like this :
$controller = new Wrap($target);
$controller->index();
I don't know if the use of $controller variable name is appropriate so please forgive me when it is all wrong.
I kinda think that I can setup my application like this :
user sends a request, how? by using the application means that he/she sends out a http-request, that will load the initial state of the application
As you can see in the diagram of my desired application structure, I was able to do only the first part which is to direct the request to a single entry (index.php)
Now the problems are the initialization of other parts of the application.
As of this moment, I have 3 files that I want to setup, but I am confused on how.
index_controller, index_view, Template
class Index_controller {
private $model;
private $view;
public function __construct(){
// optional model -> $this->model = 'index'
$this->view = 'index' //
}
public function index(){
$this->load->view($this->view)
}
}
class Index_view {
private $model;
private $template;
public function __construct(Model $model = null){
$this->template = new Template('default');
}
public function view() {
$this->template->assign('css', 'default_css'); // don't know if this is efficient
// or $this->template->assign('header', 'default_header');
// or $this->template->assign('sidebar', 'default_sidebar');
// or $this->template->assign('footer', 'default_footer');
// or any other things I want to use in the template
}
}
class Template {
public $data = array();
private $tmpl;
public function __construct($template) {
$this->tmpl = $template . '_tmpl.php';
}
public function assign($name, $value){
$this->data[$name] = $value;
}
// public function output
// function that will explode the data array and render it out as a webpage
// I'll create templates and
}
With that at hand, I want to know now how do I link those things together. At the moment I have a system folder that can contain classes, and I setup a autoloader for that folder.
I am thinking of creating a Controller class and View class that acts as the ActionFactory and ViewFactory as illustrated in the diagram, although I know that these are not their responsibilities.
I am thinking of this :
class Controller {
protected $load;
public function __construct() {
$this->load = new View();
}
}
class View {
public function __construct() {
// some things i don't know
}
public function view() {
// some things i don't know
}
}
What are your suggestions and comments in my setup. How can I initiate the triad?
Well, let's not get stuck on your implementation details too much. You can go read about securing your framework at some other time. Let's deal with your question...
I actually created a framework that works along the lines you are trying to implement. I think what you are missing is a RoutingHandler class. Routing is the physical manipulation of the URL, which tells your application which Controller to load, and which Action to run.
In my world I also have Modules, so the basic routing scheme is
Module -> Controller -> Action
These three items map to my URI scheme in that fashion. Variables can be appended also like so...
http://www.domain.com/module/controller/action/var1/val1/var2/val2
So, what happens after the URI is parsed, and control is passed over to the appropriate controller and action? Let's make some code up to demonstrate a simple example...
<?php
class indexController extends Controller {
protected function Initialize() {
$this->objHomeModel = new HomeModel;
$this->objHeader = new Header();
$this->objFooter = new Footer();
$this->objHeader
->SetPageId('home');
}
public function indexAction() {
$this->objHeader->SetPageTitle('This is my page title.');
}
}
?>
In the Initialize method, I'm setting some controller-wide stuff, and grabbing an instance of my Model to use later. The real meat is in the indexAction method. This is where you would set up stuff to use in your View. For example...
public function randomAction() {
$this->_CONTROL->Append($intSomeVar, 42);
}
_CONTROL is an array of values that I manipulate and pass onto the View. The Controller class knows how to find the right template for the View because it is named after the Action (and in a sibling directory).
The Controller parent class takes the name of the action method and parses it like so...
indexAction -> index.tpl.php
You can also do some other fun stuff here, for example...
Application::SetNoRender();
...would tell the Controller not to render inside a template, but just complete the method. This is useful for those situations where you don't actually want to output anything.
Lastly, all of the controllers, models, and views live inside their own directory like so...
my_module
controllers
indexController.class.php
someotherController.class.php
:
:
models
HomeModel.class.php
:
:
templates
index.tpl.php
someother.tpl.php
:
:
I could go on, but I'm writing this from memory, and there are some wrinkles here and there, but hopefully this gives you food for thought.
I would like to implement controllers that connect to any specific views like MVC does. I'm not using any framework that provided in PHP.
So, I need some guide and advice on doing it.
I have some controllers and views. For my views,i would like to just output my data only.
My concern now is how my function (like create() ) in controllers, can get all the $_POST['params'] that users input data in my views/create.php, and create a new Model in the create() controllers's function.
So,right now, i'm thinking to do in this way, I will create MyViews class in my controllers folder. The purpose is loading the specific views and get all the $_POST params into an object. Then, every controllers like Users_controllers, will create MyViews. In the function of Users_controllers, like create(), destroy(), I might use the function in MyViews to load specific views to load the object.
I found a source that load views
<?php
class MyView {
protected $template_dir = 'templates/';
protected $vars = array();
public function __construct($template_dir = null) {
if ($template_dir !== null) {
// Check here whether this directory really exists
$this->template_dir = $template_dir;
}
}
public function render($template_file) {
if (file_exists($this->template_dir.$template_file)) {
include $this->template_dir.$template_file;
} else {
throw new Exception('no template file ' . $template_file . ' present in directory ' . $this->template_dir);
}
}
public function __set($name, $value) {
$this->vars[$name] = $value;
}
public function __get($name) {
return $this->vars[$name];
}
} ?>
hmm,I have no idea How I can detect the _POST params
if(isset($_POST['Post']))
{
$model->attributes=$_POST['Post'];
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
this is the Yii framework I observed. How could I detect params whether is $_POST or $_GET after load a specific views.
Any guidance and advice to archive my tasks?
Unrelared to question You have one major problem: your ability to express what mean is extremely limited. The question, which you asked, was actually unrelated to your problem.
From what I gather, you need to detect of user made a POST or GET request. Do detect it directly you can check $_SERVER['REQUEST_METHOD'], but checking it withing controller might be quite bothersome. You will end up with a lot of controller's methods which behave differently based on request method.
Since you are not using any of popular frameworks, is would recommend for you to instead delegate this decision to the routing mechanism.
A pretty good way to handle this, in my opinion, is to prefix the controller's method names with the request method: postLogin(), getArticles() etc. You can find few additional example here. If there is a POST request, it will have something in $_POST array.
What are calling "views" are actually templates. If you read this article, you will notice, that the code there is actually an improved version of your MyView. Views are not templates. Views are instances which contain presentation logic and manipulate multiple templates.
P.S. If you are exploring MVC and MVC-inspired patterns in relation to PHP, you might find this post useful.
I am building a custom MVC framework using PHP. My problem is when I want to access any model class through the controller class. One way I have seen this done is through a registry design pattern using magic methods such as get and set, though PHP get and set are considered bad practise by some. I have read about dependency injection done through a container, but I can not see this working effectily as the container would have to call the models or it would have to contain the models which would defeat the purpose of MVC and create a massive super class. Singleton is seen as bad practise. Is there any solutions or improvements of the methods I have mentioned. It may just be my understand and knowledge of PHP needs improving.
Currently I have this: router.php (loads up controllor through a GET varible
<?php
class router {
function __construct() {
if (file_exists("controller/".$_GET['url']."Controller.php")) {
function __autoload($controller) {
$controlinclude = "controller/".$controller.".php";
include $controlinclude;
}
$control = $_GET['url']."Controller";
new $control();
}
else {
// throw exception
}
}
}
?>
Hope that makes sence
First of all ... Do no put autoloading script in routing mechanism. You are mixing the responsibilities. You will be better off creating a separate class for this based on spl_autoload_register.
Neeext .. do no put complicated operations on constructor. It is makes you code somewhat untestable. Maybe you should be something like:
// you might want to replace $_GET with $_SERVER['QUERY_STRING'] later
$router = new Router( $_GET['url'] );
// where 'default' is the name of fallback controller
$controller_class = $router->get_controller( 'default' );
$method_name = $router->get_action( 'index' );
$model_factory = new ModelFactory( new PDO( ... ) );
$controller = new {$controller_class}( $model_factory );
$controller->{$method_name}();
Additionally, you should look into php namespaces. There is no point in ending class with ...Controller just to know where the class will be located.
Ok ... back to the Model.
There is quite common misconception about models in web development community ( i blame RoR for this mess ). Model in MVC is not a class, but an application layer which contains multitude of instances. Most of the instances belong to one of two types of classes. With following responsibilities:
Domain Logic :
Deals with all the computation, calculation and all the domain specific details. Objects in this group have no knowledge of where and how data is actually stored. They only manipulate the information.
Data Access
Usually made of objects that fit DataMapper pattern (do not confuse with ORM of same name .. nothing in common). Responsible for storing data from Domain Objects and retrieving them. Might be in database.. might not. This is where your SQL queries would be.
In semi-real world situation () it might looks something like this (related to code abowe):
class SomeController
{
// ... snip ...
protected $model_factory = null;
// ... snip ...
public function __construct( ModelFactory $factory )
{
$this->model_factory = $factory;
}
// ... snip ...
public function action_foobar()
{
$user = $this->model_factory->build_object( 'User' );
$mapper = $this->model_factory->build_mapper( 'User' );
$user->set_id(42);
$mapper->fetch($user);
if ( $user->hasWarning() )
{
$user->set_status( 'locked' );
}
$mapper->store( $user );
}
// ... snip ...
}
As you see, there is no indication how the data was stored. It does not even matter if user account was new, or already existing.
Some materials you might find useful
Videos
Advanced OO Patterns (slides)
Clean Code Talks: Don't Look For Things!
Clean Code Talks: Unit Testing
Clean Code Talks: Global State and Singletons
Books:
Real-World Solutions for Developing High-Quality PHP Frameworks and Applications
Patterns of enterprise application architecture
Clean Code: A Handbook of Agile Software Craftsmanship
SQL Antipatterns: Avoiding the Pitfalls of Database Programming
A great Dependency Injection container is "pimple", which may be considered a service locator by some. It uses php 5.3's closures to create a class, that is used to create all of your project's objects through lazy loading. So, for instance, you can create a closure that contains the code for initializing a given object. You would then use the DI container's get() method, which would in turn, call the closure to create the object. Or simply pass you the object, if it has already been created.
// simplified dic class
class dic {
protected $closures = array();
protected $classes = array();
public function addResource($name, Closure $initialization_closure) {
$this->closures[$name] = $initialization_closure;
}
public function get($name) {
if (isset($this->classes[$name]) === false) {
$this->classes[$name] = $this->closures[$name]();
}
return $this->classes[$name];
}
}
//setup
$dic = new dic();
$dic->addResource('user', function() {
return new UserClass($some_args);
});
$dic->addResource('userContainer', function() use ($dic) {
return new UserContainerClass($dic->get('user'));
});
// usage
$userContainer = $dic->get('userContainer');
This allows you to keep the flexibility of being able to change how and what objects get created throughout your project by only changing a very small amount of code.