I have been tasked with finding a solution to wrapping a custom made application in the silex framework as they are going to continue forward using silex. The dilemma is the legacy application is a flat php style with no controllers or models, and php with mysql queries embedded within the via files.
I have been struggling to find any clean solution to wrap the legacy app in the routing of silex to allow for new portions to be done in a controller based setyp instead of flat php. I have been checking for some time between stack overflow and other Google results, but they an del seem to end up specifying ways of doing default routes with a legacy app that has a controller based setup.
For good measure, the legacy app does use session variables so the solution must allow for those to be used.
Any and all help is appreciated.
Before people ask, I have looked at Routing in Silex/Symfony - Providing a default route and it is similar to how I would like to do it, but I need to make it work with the flat php app, not legacy controllers.
The solution ended up being a 2 part process.
Place the legacy code within the web root of the silex application.
Get the silex application to store sessions that are accessible by both Silex, and the legacy application.
Code Placement
By placing the legacy code into the web folder, anything in the URL that matches a file will go to that file instead of looking for a route. This allows for not needing to create routes for all of the old code, as it is not controller based in our situation and needs to be handled differently than most of the other restructuring that has been referred to on this site.
Placing the code into the web directory also means that we can continue to make updates and changes to the old code, while writing new Silex based code to replace it in our available time.
Sessions
When it came to using the same sessions, the option we went with was....less than desirable, but it allows for us to continue with our plans without hindering the use of either application. The current plan is to implement database stored sessions once we have completed migrating the application's code to Silex.
We went with an option first identified in this post Symfony session avoid _sf2_attributes. This is quite an ugly solution, but allows for the flexibility we need in attempting to migrate the application over in time with minimal effort up front. The goal is to migrate it over completely to the new Silex application, but the timeframe is over a year or more to do so.
Here is how the session is configured in our Silex application. It is using file based storage.
$app->register(new Silex\Provider\SessionServiceProvider(), array(
'cookie_lifetime' => 86400,
));
$app['session.storage'] = $app->share(function () use ($app) {
return new \Symfony\Component\HttpFoundation\Session\Storage\LegacySessionStorage;
});
Here is a copy of the controller code located originally here, in case it is removed at some point.
<?php
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
/**
* Session sotrage that avoids using _sf2_attributes subkey
* in the $_SESSION superglobal but instead it uses
* the root variable.
*/
class LegacySessionStorage extends NativeSessionStorage
{
const SYMFONY_SESSION_SUBKEY = '_sf2_attributes';
/**
* #inheritdoc
*/
protected function loadSession(array &$session = null)
{
if (null === $session) {
$session = &$_SESSION;
}
parent::loadSession($session);
foreach ($this->bags as $bag) {
$key = $bag->getStorageKey();
if (self::SYMFONY_SESSION_SUBKEY === $key)
{
$bag->initialize($session);
}
}
}
}
I hope this helps some others in allowing them to migrate to a new coding style from an old application that is a thorn in their side. Wanted to make sure to sum up our findings over time in order to ensure others don't have to look as much in the future hopefully.
there is a really good article written by Matthias Noback about this. Basically the trick would be to match the legacy urls and return the legacy output inside a Silex Response object. Beware of memory use with ob_* methods.
An alternative is to modernize the flat PHP application in place (leaving you with one unified codebase) instead of wrapping it (which leaves you with 2 codebases). The step-by-step details are in Modernizing Legacy Applications in PHP but the overview is this:
Implement an autoloader
Consolidate classes and functions to a central location
Remove globals in favor of dependency injection
Remove the new keyword in favor of dependency injection
Write unit tests
Extract SQL code to Gateway classes ("Model, Part 1")
Extract domain logic to Transaction classes ("Model, Part 2")
Extract presentation logic to Response classes ("View")
Extract action logic to Controller classes ("Controller")
Extract remaining includes
Extract application code from the document root
Implement a front controller
Prepare the application for a dependency injection container
Add a dependency injection container
Hope that helps.
Related
I'm developing a PHP MVC REST API which will have OAuth for authenticating if the call can be performed.
So my plan is to develop it for an Angular 2/4 app which will handle the API calls.
The idea was to create a structure where my domain for example test.com will have a subdomain api.test.com.And from it the API calls will be requested.
The thing that i would like to confirm before i start building this is my MVC backend structure.
Ref.Pic
Model will have all the logic
View will be the api.test.com/api/call presentation.Outputing the JSON in my case.
Controller will accept input exmp:the api.test.com/api/call call the logic in the Model if the call is correct.Than the call will react on the view where presenting the JSON.It would hold the OAuth also....
I'm trying to understand the whole concept of this, since i have tried several times to build it and every time i end up in a mess of code.I'd like to see if my understanding of the project above makes sense.
Thank you
There are multiple issues, that you will encounter as you try to apply SoC principle in your codebase.
And, what to do with communication between views and controllers, is one of the more visible ones. That's because, if you mess it up, there are no abstractions to hide it all behind.
The two major approaches are Supervising Controller and Autonomous View (which has no article, but you can deduce some of it from this and this).
Supervising controller
This approach is best suited for smaller applications (well .. for large values of "small", since really small projects don't really need the architectural bloat of MVC). It essentially looks like this:
/* in a controller */
public function verifyEmail(Request $request)
{
$identity = $this->search->findEmailIdentityByToken(
$request->get('token'),
Identity::ACTION_VERIFY
);
$this->registration->verifyEmailIdentity($identity);
$body = [
'status' => 'ok',
];
return new JsonResponse($body);
}
Essentially, what you have there is a controller, that interacts with the business model and (when necessary) populates the view with data. Then it causes the view to be rendered and returns the response.
In my own experience, I have found this to be the best approach to use, when writing backend applications, that are expected to only be manipulated via REST-like API.
As you see in the example, the "view" in this case is extremely trivial. It is basically array, that you render as JSON (which the provided code would actually do - it's copied from a real project).
Note:
If your intention is to fully implement REST as it was proposed (not just the REST-like resource endpoints) and/or
have functionality of resource expansion, then this approach might be wrong and even harmful.
Autonomous View
When your presentation logic becomes complicated or have to provide different UIs for the same application with the same functionality (like having single app with both website and REST API, with both xml an json interface), then using Supervising Controller becomes a ball and chain around your neck. Your controllers start to grow uncontrollably and your project can be described as "legacy codebase", before it even reaches production.
And that's where you use this approach.
You use views and controllers as completely separate classes and you interact of their instances at the same layer (for example: bootstrap stage). It ends up looking something like this:
/* in /src/application.bootstrap.php */
$command = $request->getMethod() . $parameters['action'];
$resource = $parameters['resource'];
$controller = $container->get("controllers.$resource");
if (method_exists($controller, $command)) {
$controller->{$command}($request);
}
$view = $container->get("views.$resource");
if (method_exists($view, $command)) {
$response = $view->{$command}($request);
$response->send();
}
Again, example from a different live project, which also uses a DI container. In this case there is only one UI (hence, no "type" prefix, when making a view instance), which mean that the code can take advantage of 1:1 relation between controllers views (it would be 1:n, if you need multiple UIs).
The controller in this case basically only "writes" to the model layer. And the view (which also has access to services from model layer) only performs "reads" and extracts only the information, that it requires for populating templates and rendering them.
And, if your presentation logic grows further, it is a good idea to start adding presentation objects, that will contain the repeating parts of the presentation logic (e.g. deciding, which menu item in the sidebar has to be expanded and which submenu item has to be highlighted), that are common for multiple views.
If your backend application only deals with API, then this approach might be too complex, unless you are doing one of the things mentioned in the "note" part.
... maybe this helps a bit
Yes, That makes sense. I suggest using the Laravel framework instead. Or the OctoberCMS even better.
I'm writing this small blogging platform in Laravel 4.1, for learning purpose. My first obstacle is, I don't know where the global data (ie. dynamic blog settings, plugin and theme array) should be put, so that I can access them from anywhere (similar to how $wpdb in WordPress works - we only need global $wpdb; to access it).
Of course $GLOBALS works, but we know that it's evil and should be avoided. Also, I'd like everything to be as Laravel'y as possible.
Have tried:
App::bind('settings', []); // error
App::instance('settings', []); // how to populate and retrieve it back?
Any ideas? Thanks in advance.
If this is not something you need to keep between sessions, you can use:
Config::set('myglobals.name', 'An Phan');
And then
var_dump( Config::get('myglobals.name') );
But you also have to think a bit and think why would you need globals in the first place. Take a look at this: http://c2.com/cgi/wiki?GlobalVariablesAreBad.
EDIT
This is not a workaround, this is something Laravel provides out of the box and you can use yourself. Usually the purpose of Config would be having configuration files to be used by your application, but sometimes you just need to change those values during the request, that's why Laravel provides also a set() method.
Unfortunately WP has an old codebase and if you are trying do things the way WP does things, you're goind the in wrong path.
What would be the Laravel way depends on what you're trying to accomplish with your project, so you'll have to tell a little bit more about it.
The mindset to start with is: "I don't need globals" and when you get to a point where a global is needed, you ask yourself "how do I do this without using a global?".
Usually, you just need global values if you have settings to store. If it's something that you have to use to set a state during a request, you need to use objects. You can have global objects in Laravel, you can have singletons (objects that has only one instance in the whole application), you can create properties objects:
class SidebarProperties {
private $width;
public function __construct($width)
{
$this->width = $width
}
public getWidth()
{
return $this->width;
}
}
So you have an uncountable number of way to not use globals, you just have to think about your project and pick the one is best at that moment.
Well, global in a Laravel context means relative to Application, if you are not writing anything that "lives" outside of Application context.
There are couple of ways in which you can make you data available to application. But first, you have to make decision what kind of "globals" do you need ?
First and most important rule is that any change that you make besides Application specific folder structure, has to be told to composer.
Second, without making any changes, Laravel has default locations for most important parts of any "ordinary" web application.
Application folder structure is pretty self descriptive, but in short:
Configurations belongs to app/config
Models to app/models
Views to app/views
Controllers to app/controllers
Database to app/database
Routes to app/routes.php
If you follow this basic structure, you can create amazing web-apps. these folders and files are already namespaced and classes inside them are auto resolved. In you example you were trying to bind something to application, which is redundant in you case. Bindings to container are used in cases when you want to add some new classes and functionality to existing structure.
In short:
create you first route in routes.php like this:
Route::get("GET",function(){
return "my first route";
})
And from that point follow basic MVC flow, which is no different then most frameworks. Laravel is talking to you, just open you ears :)
And if you stack, just ask here, somebody will help.
Our web site is built on top of a custom php mvc framework and we wanted to slowly convert each flow (for eg: signups) to Laravel.
So in essence, the existing code and the new code using laravel have to co-exist. But we hit a snag, where session information set by laravel is not availble to the other mvc and vice-versa because of their conventions.
For eg, the custom mvc uses the following.
$_SESSION['AUTH']='TRUE';
While Laravel uses something like this.
Session::put('AUTH', 'TRUE');
We tried to set $_SESSION['AUTH'] = 'TRUE' through laravel classes. But we are not able to access it when control is passed to the older MVC.
I know its complicated, and i should just wait to convert the entire code base to Laravel, and be done with it. But we are a small company with minimal resources. So we dont have the luxury to stop feature development and spend time re-writing using Laravel Exclusively.
So my question is this. How , if by any mechanism, can we achieve this?
Global variables?
Any other suggestions?
I would recommend you to use Laravel's Auth-Class here, listen to the auth.login event and set your session flag by hand.
Event::listen('auth.login', function($user)
{
$_SESSION['AUTH']='TRUE';
});
It is the easiest way and you only have to delete the event listener when you completly migrated to Laravel.
I know this is a quick and dirty thing, but after full migration you don't want to use the $_SESSION ever again to manage your authentication ;) so I think this should be a very good bridge between your new and old codebase.
For example if you have the following folder stuctures
projectFolder/oldMVC
projectFolder/Laravel
in the oldMvC/main.php we included the following
require '../Laravel/bootstrap/autoload.php';
require_once '../Laravel/bootstrap/start.php';
After that we were able to access session and other config variables set in Laravel from the non Laravel MVC.
Actually only by requiring bootstrap/autoload.php and bootstrap/start.php you will not be able to access the real Laravel session. Not even by calling Application::boot() anymore.
I've created a Gist, that makes it possible to share Laravel's session and check authentication from external projects:
https://gist.github.com/frzsombor/ddd0e11f93885060ef35
I run an arcade site and over the past few years it's had many features added, it's got to the point where procedural programming just looks way too complicated and adding new features or making simple design modifications can be very tricky.
Therefore I've decided to try and recode the site from the ground up with the same features but in an OOP format.
The issue I have is picking the classes, I understand OOP and how it should work but always seem to have trouble getting started. I am unsure whether I should be trying to make functions for classes such as a user class with log in user function or if the user class should just be to add/update/show user details and the log in part would be better in a system class?
At the moment I've started with the following class and functions but do they fit in this category?
<?
class User {
var $userId,
$username,
$userRole,
$userEmail;
function isLoggedIn(){
}
function login($postusername, $postpassword)
{
}
function increaseLoginCount(){
}
function logout(){
}
}
?>
I could then have something like the following in a page.php .. (connect class not shown)
<?
$db = new Connect;
$db->connect();
$user = new User;
if(!$user->isLoggedIn())
{
echo "Please Log In.";
if($_POST['user'])
{
$user->login($_POST['username'], $_POST['password']);
}
}
else
{
if($_POST['logout'])
{
$user->logout();
exit;
}
echo $user->username." Logged In.<br />";
}
?>
But then the site would have pages to show game categories and I don't know where the displayGames() function would fit as it's not a single game so wouldn't go in the 'Game' class?
I've tried to find 'real world' examples but php code showing me how to make an elephant change colour or dance doesn't really help ...
Let's start with some textual analysis, highlights by me:
I run an arcade site and over the past few years
Think about how much you are able to cope with and what you are dealing with. Also understand that over the years you have gained specific knowledge about running arcade site. You have gained profession in your area. Never underestimate your own position and assets, it's the base you're operating from and you will introduce changes to. This includes your site's userbase.
it's had many features added, it's got to the point where procedural programming just looks way too complicated and adding new features or making simple design modifications can be very tricky.
If systems grow, they become more and more complicated. That's not specific to procedural programming only, it's a matter of fact. As you're running the site now for many years, you know how things changed, especially in the area how the user interfaces with your site.
Therefore I've decided to try and recode the site from the ground up with the same features but in an OOP format.
It's said that it could be possible to use OOP techniques to make re-useable software, there is (and can not be) any proof of this.
But there are only very few examples in commercial software development where re-writing the whole application from scratch was a success. Very few. The rules of commercial software development might not apply in your specific case, so just saying.
Think twice before you recode the site. Doing a lot of work only to achieve the same is somewhat fruitless and can be disappointing. Instead probably look more specifically which of your current design is introducing the biggest problem you would love to change.
It is possible with PHP to mix procedural and object-oriented style, which can be especially useful when you have legacy code (a common definition of legacy code is code w/o automated tests).
The issue I have is picking the classes,
I try to rephrase that: For what write classes for?
I understand OOP and how it should work but always seem to have trouble getting started.
The beginning is always the hardest step. You're in the position ready to make decisions now, but you can't look into the future. Reduce the risk by eliminating the most risky part. You've probably started to ask a question here to gain some feedback to base your decisions on, but that will probably not reduce the burden and might lead to confusion. However, getting educated is most often a good thing.
I am unsure whether I should be trying to make functions for classes such as a user class with log in user function or if the user class should just be to add/update/show user details and the log in part would be better in a system class?
That highly depends on the nature of your application and the nature of the user. Probably the most of your script only need to know if a user is concrete or anonymous (an anonymous user has not logged in), it's ID, name or nickname.
The application should provide that user to any consuming component, so each command/script does not need to deal with a) obtaining users information and handling users (like logging in), b) verifying if the component is valid for the user (access control). That should be placed somewhere else, e.g. in the application controllerPofEAA.
Each of your scripts/commands that has the application controller object, can ask for the user and just interact with the user.
However this is just technically speaking. Deal with the fact of yourself being unsure, work with that information. Try to better formulate your concrete problem, list pros and cons for a specific way of solving it, get away from concrete code again before starting to code. Then compare pros and cons. Try to make things more simple and less complicated.
Probably write down in simple words what should be happening instead of writing code.
At the moment I've started with the following class and functions but do they fit in this category**?**
Your code is quite bare, so it's hard to say much about it - especially as I don't know what your arcade site is (and what the category is you write about). It's still good for an example probably. What can be seen in your classes is that you tightly integrate everything with each other.
For example you start with the DB. That's common, because the DB is a central component for any application. The application needs the DB to operate on. However you want to keep things loosely coupled so that all your commands can be run with some other DB or a new user object that is connected with some even other DB than the rest of your application's data objects.
$application->getDB();
As the user is such a central subject in each application, it should have a very simple interface. All the glory details about authentication, retrieving of the users properties etc. should be delegated into another class/component, so that you can change the implementation where users are stored and how they authenticate:
/**
* #package command.modules.games
*/
function ListGamesCommand(Request $request, Response $response)
{
$application = $request->getApplication();
$user = $application->getSession()->getUser();
$games = $application->getModels()->build('games');
$games = $games->findByUser($user);
$response->setProp('games', $games);
}
As this example shows, you can add the functionality when you need it. E.g. as long as your application does not need to actually log in users, why care about how it's written now?
Create a factory that is producing the user for the application object - whatever it will need now or in the future (see the Two Piles of Objects in The Clean Code Talks — Inheritance, Polymorphism, & Testing). If you then need the authentication, either add it to the session object or the user object interface.
The authentication itself would be implemented in a class of it's own anyway, the Authenticator. So you can review your interfaces later on as well, by moving the invocation of authentication from session to user or whatever. Only a fraction of your commands will need to deal with these specific task and as all new code is under automatic tests as you want to rewrite and benefit from OOP, you have ensured that all the places are covered and properly re-factored.
Same is true for accessing request variables. If you want to make use of the benefits of OOP - which is highly connected with indirection (and each layer of indirection comes with a price) - you should first of all make your base classes operate on specific data and not on any data (like globals and superglobals, I've seen $_POST in your example code).
So enable your new code to operate on a request and deliver a response (Input - Processing - Output):
$request = new Request($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES, $_ENV);
$response = new Response;
Example taken from the BankAccount - Sample application used for PHPUnit training
Now everything below this can operate on a Request and a Response object - process input and turn it into output. The domain command (your scripts/commands that do the thing) do not need to care any longer about extracting input from the HTTP request like using $_POST or $_GET they can take it directly from the Request - or if you write a class of commands of it's own - this can be even more tailored. And some commands can operate on requests and responses of their own.
The next big topic is the user-interface. You write you want to:
I've decided to try and recode the site from the ground up with the same features but in an OOP format.
I already wrote that such a doing can be fruitless. To have a benefit of OOP code would mean that the next time you change your code, you're still able to re-use components. As software changes constantly, this time now is already the next time. So you want to already re-use existing code. I assume one part of your existing code is the output logic. So the existing output logic needs to interface with the exemplary Request and Response above.
I bet you love websites. You love to make them just work and look great. You've build your site over the years and even not everything is like you wish it to be, you don't want to drop it. So it's crucial for your re-write that you don't destroy everything but you can preserve it's working form from now to the future (See as well Preserve a Working Application; last point of the list).
In webapps the view is such a crucial part. If you loose the view, your site will loose it's identity. If you change too much of it, your site will loose users that are comfortable with using it today.
If you break it,
will you even notice?
can you fix it?
On the other hand you want your application code (the features, the functionality) to not be that tightly bound to it any longer to have a benefit in rewriting your code. As you want to rewrite your application, let's take a look:
.---------. .-------------.
| website | ---> [interface in ] ---> | application |
| user | <--- [interface out] <--- | |
`---------´ `-------------´
As this schema shows, to make your application more independent to whatever the interaction looks like (can be a website, a (smartphone) GUI or the ticketing system), the application code should be replace-able. You don't want to code the logic to obtain a users games for example for every type of user-interface in the new application code, but you did in the old application code.
Taking the User object as an example here. How it authenticates and where it is stored shouldn't be something your new application commands code are concerned about. It's just there if the command needs it. Not globally but specifically if the command asks for it.
Where-as the registration and lost password procedures are part of your existing application and continue to exist.
Now you need to bring the old and the new code together.
So you will probably start with an interface for HTTP requests and a HTTP response. The view kicks in with that Interface Out. You assign/pass all needed data for the view via that interface, your application does not know the view any longer. You don't deal with any CSS, Javascript or HTML code within your new application code. That's just the sugar on top for the output. Your application should interface as well via console/telnet in plain text or as a remote XMLRPC service, AJAX endpoint - whatever.
So you can probably just generalize your view code and inject variables to it. To write a view layer could be as simple as including a PHP file. It operates on variables that are available within it's scope. It can make use of "helper" functions (template macros) that are available in it's scope. It can make use of view model objects. It's even possible to write your own language for the view (templating language, a Domain Specific Language (DSL)).
But this is only possible if you create an interface that allows the application code to do so.
So what you now do is to move away the HTTP/HTML/CSS/JS from your application into an adapter of it's own. That adapter is able to formulate the generic command that can be passed to any application via interface in.
The application will only take care to execute the command and deliver it's response via interface out. So you have two domains now: Your application and the website.
You can start to create these two new domains and then offer an interface in and out for your legacy code and one for your new code.
You also have "two" applications next to each other. They are finally bound together (invisible in their own code) with your database which takes care that the data of your site is in order. And that's what the database is for. Separate the data from your code, so you can change your code over time.
Also if you want to re-code, draw a border between the existing code and the new code.
Good luck! And I hope reading this will show you some options for your specific case. Also take note that you don't turn your controllers into just another facade to the database. Probably you've got the best benefits (don't know your concrete biggest problem) by using a lightweight HTTP abstraction and a view layer only as it might be that your application is for websites only.
Because as in HTTP / PHP:
[Interface In] Plain Text HTTP request
[Application] Free to go
[Interface Out] Plain Text HTTP response
You normally need only some functionality to parse the input and build the output.
Additionally not using fat models has the benefit that you access your data quickly and sequentially, e.g. if you don't need to pass the output at once (buffered, one-block), you can make of the benefit to stream the output to the server.
You should decide which parts are important to refactor for your application, not OOP or not. Like procedural, OOP needs to be done well as well. If you today run into problems by writing procedural code, OOP code might not the answer to your problem. The need to write better procedural code might be it. Just saying, it's not easy to refactor an application and you should identify the actual problem first.
If you break it, will you even notice?
If you break it, can you fix it?
The crucial part is that you can notice and that you have everything at hand to do the fix.
Get your website under test, so you can say if changing code here or there is actually doing good. Be able to turn any change back if it comes to light it's not working (better).
That done you can easily decide about a new feature or not. As long as you don't need to introduce new features, there is no need to change anything in how you write features. And until there, you can't plan for the new features.
So better think twice before re-writing your application. As written, this can kill the project.
See as well: How to implement MVC style on my PHP/SQL/HTML/CSS code?SO Q&A
OOP is all about identifying areas of responsibility and constructing self-contained units of code intended to handle one, and only one, of those areas. A general rule of thumb is that each object in your system should embody an equivalent object or concept in the real world but that's not always true as you need to also worry about abstract things that are needed to make your system work (I mean abstract here in the sense that they don't represent an item of business logic, but are still needed to make the system work. I don't mean abstract classes, which is something else altogether).
For example, in your gaming site, you're probably going to have to deal with Games, Users, Moderators, Accounts, Reviews, Comments and so on. Each of these should be a class in its own right, and every instance of that class should represent a particular User, Game, Comment and so on.
But classes have areas of responsibility, and a stated above, a class should deal with its area of responsibility and nothing else. Rendering a page is not the responsibility of any of the object classes mentioned above. This is where the classes that don't represent the entities of your system come in. You'll probably need a class for a Page, a class for a Session, a class for database connections (though PHP has you covered there already with PDO and some of the other DB modules such as mysqli).
To render a page you'd use an instance of a page class. You'd pass it a reference to the logged in user object, references to any game objects you'd want it to display, and so on. Then you'd have it render the actual HTML. The Page class doesn't need to know anything about the inner workings of the objects you pass it, other than about the APIs that those objects expose (known in OOP circles as the object's protocol, in otherwords their public methods and properties). A (very basic) Page class might look like this:
class Page
{
private $user = NULL;
private $games = array ();
public function setUser (User $user)
{
$this -> user = $user;
}
public function getUser ()
{
return ($this -> user);
}
public function addGame (Game $game)
{
$this -> games [] = $game;
}
public function getGames ()
{
return ($this -> games);
}
public function generate ()
{
$user = $this -> getUser ();
$games = $this -> getGames ();
$pageFile = '/path/to/a/php/script/representing/the/page/markup.php';
require ($pageFile);
}
public function __construct (User $user, array $games)
{
$this -> setUser ($user);
foreach ($games as $game)
{
$this -> addGame ($game);
}
}
}
The actual markup.php script would probably look something like this:
<html>
<head>
<title>Games page for <?php echo ($this -> user -> getName ()); ?>
</head>
<body>
<p>Hello, <?php echo ($this -> user -> getName ()), here are your games.</p>
<?php if (count ($this -> games)) { ?>
<ul>
<?php foreach ($this -> games as $game) { ?>
<li><?php echo ($game -> getName ()); ?>: your best score is <?php echo ($game -> getHighScore ($this -> user)); ?></li>
<?php } ?>
</ul>
<?php } ?>
</body>
</html>
As you might have noticed, if you use this approach then your application's modules will tend to fall into one of three categories. Your business logic objects like User and Game, your display logic like the markup.php file, and the third group that serves as a form of glue logic and coordination like the Page class.
Whilst in this particular case it's specific to your site, if you were to generalize this approach further it would fall into a design pattern known as MVC, which stands for Model, View, Controller (well actually it's closer to a pattern called PAC for Presentation, Abstraction, Controller, but it's almost always called MVC in the PHP community for some reason, so we'll just say MVC for now). A pattern is a generalization of a class of problems that programmers run into on a regular enough basis that having a toolkit of pre-made solutions is handy.
In the case of your gaming application, User and Game are models, Page is a controller, and markup.php is a view. If you substitute a different markup.php script into this code you can use it to present the exact same data in a completely different way, say as an XML file for example. You could also use the same models with a different controller to get them to do different things. The important thing to keep in mind here is that models should not concern themselves with how they are being used, that way they can be used in different ways depending on what the controller needs to achieve.
As MVC is a pattern, there are already toolkits that exist to build MVC (though they aren't really MVC ;) ) applications in PHP. These are called frameworks. There are plenty to choose from out there, such as Symfony, CodeIgnitor, Zend Framework and so on. The most popular framework these days is Zend, though I'm not personally a fan of it. (I would say that the beta versions of Zend Framework 2 do look a lot better than the current version of the framework though).
I hope this has been helpful for you. I know OOP can be daunting at first. It does require you to change your way of thinking as a programmer, but don't worry, it will come with enough practice.
All the members in the user class look like they belong there. It's important to separate the gui code from other code, I'd put displayGames() in some sort of gui class.
GordonM's post is a good one to get you started. I would certainly recommend using an established framework to get you started - they do a lot of the heavy lifting for you and will help you get used to OOP within PHP. Personally, if you're using PHP5.3 I'd recommend Symfomy2 but that's purely a personal preference. What I would also suggest is you get hold of a copy of the "Gang of Four" book. It's pretty much essential reading and although it comes mainly from a non-request-driven-environment background many of the patterns are still relevant in PHP.
I'm developing several web sites in Kohana using its template system so that one code base is running several web sites using the same back end DB. I'm starting to see a lot of if statements in the views to say if this site do this, if that site do that. It starting to look very non-MVC or Object Oriented. Do other developers have any rules they follow when deciding to breakout view into separate partial views? I want to reuse as much of the code as possible but not swim in if statement in every view. Any reference would be great also.
If you are using Kohana, you should use modules for stuff you don't want to duplicate for every application. Then you can keep specifics in your application with extended classes or specific settings in config files.
http://kohanaframework.org/3.2/guide/kohana/modules
A lot of if statements are mostly an indication that you need to do refactoring. A large cascading if statement to allow for different sites to be loaded is bad practice in the sense that you make files tightly coupled causing to edit multiple files when you need to make a simple addition or change. Furthermore, it will eventually become ugly if every site needs to load different dependencies or settings or whatever in your if statement.
It's difficult to say what you need to change without seeing the code, but try looking at design patterns like the factory or abstract factory design patterns to create site objects.
A good book that deals with the subject of patterns and best practices with PHP is PHP 5: Objects, Patterns and Practice by Matt Zandstra: http://www.amazon.com/PHP-5-Objects-Patterns-Practice/dp/1590593804. A very good book.
I had a similar issue cropping up with this, to keep the views nice and neat I extended the view class into a theme class. I would give the factory method two (or more) views ie Theme::factory(array('site1/home','default/home'),$data)->bind(...); If a themed view existed it would use that, else just serve up the default. That way I, or someone else less competent could easily override to display structure and view behaviour.
The class looks like this
class Theme extends View {
public static function factory($pages = NULL, array $data = NULL){
if (is_string($pages)) {
$pages=array($pages);
}
if (!is_array($pages)) {
$pages=array(0=>null);
}
foreach ($pages as $page){
if ((Kohana::find_file('views', 'themes/'.$page)) !== FALSE){
return new View('themes/'.$page,$data);
}
}
throw new Kohana_View_Exception("None of the requested views ':file' could not be found.", array(
':file' => join($pages,"' or '"),
));
}
}
You really want ViewModels, only you don't know how to name them yet. Little birds have been tweeting that it'll be in Kohana 3.3 but unless you have a year or so to wait, I recommend trying either View-Model module by Zombor or moving away from Kohana's templating system whatsoever in favour of KOstache (it's Mustache for Kohana)
If for any reason you want to stick with your current codebase, I'd go with splitting the view into several smaller interchangable parts and loading them when necessary (echo View::Factory(($something == 'one' ? 'view_one' : 'view_two')) or a custom written helper would be a nice toy here)