when to use MVC on PHP? - php

Ok I think I am pushing my self to far here, I'm createing a project in my own MVC even I don't know what MVS is itself,
<?php
class init
{
function __construct()
{
$this->enviroment();
$this->start();
}
function enviroment()
{
/* Required Classes */
require_once( ROOTPATH . BOOTSTRAP . REDENGINE . '/class.debug.php');
require_once( ROOTPATH . BOOTSTRAP . REDENGINE . '/class.theme.php');
require_once( ROOTPATH . BOOTSTRAP . REDENGINE . '/class.url.php');
require_once( ROOTPATH . BOOTSTRAP . REDENGINE . '/language/class.lang.php');
require_once( ROOTPATH . BOOTSTRAP . REDENGINE . '/class.sessions.php');
}
function start()
{
/* Start Classes */
$uSys = new Urlsystem;
$fragments = $uSys->getFragments();
$tSys = new ThemeSystem;
$lSys = new LanguageSystem;
$sSys = new Sessions;
/* defineing APPVIEWS & APPCONTROLLER */
define( 'APPVIEWS', '/appviews' );
define( 'APPCONTROLLER', '/appcontroller' );
if ( empty($fragments) )
{
require_once( ROOTPATH . APPCONTROLLER . '/app.home.php'); /* default app controller page */
require_once( ROOTPATH . APPVIEWS . '/view.home.php'); /* default app views page */
}
if ( !empty($fragments) )
{
// Start ENGINE
if ( !file_exists(ROOTPATH . APPCONTROLLER . '/app' . $fragments . '.php') &&
!file_exists(ROOTPATH . APPVIEWS . '/view' . $fragments. '.php')
) {
if ( file_exists(ROOTPATH . APPCONTROLLER . '/app.404.php') &&
file_exists(ROOTPATH . APPVIEWS . '/view.404.php')
) {
require ROOTPATH . APPCONTROLLER . '/app.404.php';
require ROOTPATH . APPVIEWS . '/view.404.php';
}
else {
echo "NO 404 APP || VIEW";
}
}
if ( file_exists(ROOTPATH . APPCONTROLLER . '/app' . $fragments . '.php') )
{
require ROOTPATH . APPCONTROLLER . '/app' . $fragments . '.php'; // load application
if ( file_exists(ROOTPATH . APPVIEWS . '/view' . $fragments . '.php') ) {
require ROOTPATH . APPVIEWS . '/view' . $fragments . '.php';// load view
}
}
// End ENGINE
}
}
} ?>
Ok, as you see my front controller, so I know it's failing, I just notice my fail after I nearly finish my project, especialy when I need to do www.someurl.com/?$getuser or www.someurl.com/myname or a user.
Anyway my question is when do we really need MVC for PHP?
I'm looking at facebook, etc
They still use the ?this=blabla get so they are not MVC , is that right? Anyway I'm still confused how facebook does www.facebook.com/myname without it. ( htaccess ? )
If they don't use MVC then when do we really need it?
Note :
I've read many thread about when use MVC, but I haven't found one in my problem, if there is please leave a comment so I can read :)
Thanks a lot.

I believe you are confused between MVC and having RESTful URL scheme (http://en.wikipedia.org/wiki/Representational_State_Transfer#RESTful_web_services).
MVC is just a coding pattern that separates entities and modules. Like Application Logic from GUI Templates while The URL pattern is a different thing altogether. URLs are just to access a Web Resource. MVC frameworks like CodeIgnitor can still give you 'ugly' URLs if you do not work it out with .htaccess

MVC is an architectural pattern focused on separation of concerns; the URL's have nothing to do with it.
URL's are handled by the server. If it's Apache you are using, set up mod_rewrite.
That being said, you might want not to reinvent the wheel, but look at options available out there, there are plenty of MVC-oriented PHP frameworks. Find one that you like and can be productive in and use it.

I think you're confusing MVC with query params. The two are not necessarily linked, though it is true that the more popular PHP MVC frameworks do mask the params by using mod_rewrite or an equivalent method.
MVC is simply a way to keep your presentation logic separate from your business logic. Think of it this way: if you have a site using MVC, you can easily create a mobile phone version by simply changing the views based on the browser, your site's logic doesn't need to change, just the HTML that is sent to the client.

It seems that your question is confusing two different topics together. Model View Controller(MVC) and pretty URLs.
Model View Controller is a design paradigm which allows you to separate your logic(model), your templates(views), and your directing input/output(controller).
Pretty URLs on the other hand, allow for redirecting urls based on format rules(typically .htaccess rules).
Model-View-Controller - design paradigm information.
Pretty URLs tutorial - implementation of using Apache's mod_rewrite.
mod_rewrite - information on what a rewrite engine is.

Saving your code, HTML, and data in different folders is the most basic way of structuring your application - and that's the primary reason for implementing MVC: organization.
The other design patterns present in most frameworks supplement MVC, and they promote code reuse, rapid development, etc. But you can do the latter even without MVC - all it takes is a code library! Most frameworks utilize the MVC design pattern, but MVC != frameworks.
Some frameworks require you to tweak Apache (Lighty, Nginx, etc) to make it a framework extension. Pretty URLs are just a way of presenting input data (view) that are consumed by the controller so the latter can route to the appropriate handler. Seen in this light, .htaccess is an integral part of MVC for such frameworks.
Before you plunge deeper into your project, it helps to do a little more research. Most frameworks have taken the convoluted approach to MVC, which have led many to confusion. Fat-Free Framework uses a more direct and easier-to-follow path.

you might consider starting by using one of the many different MVC frameworks out there, such as CodeIgniter or cakePHP. These frameworks have bene developed by many pople and refined over a period of time. MVC is not necessary, but once the boilerplate is established, creating web applications is very fast.

When to use... All the time, is a good practice.
Personally, my choice: Symphone and Doctrine can easier to write big applications by team. But began with CodeIgniter.

You are really making it hard on yourself by attempting to writing your own mvc. (You are not doing it by manipulating the URL scheme). While it is a good educational experience to write one yourself, you will not get the level of quality and the benefits of the MVC pattern by reinventing the wheel.
Write your app in symfony, zend, codeigniter cake or any of the good open source MVC frameworks out there. When you get a feel for how it should work, then you should create your own for fun.
These frameworks exist to make your projects faster to code and more maintainable.

Related

Downsides to Slim as a REST API framework

I have been experimenting with Slim for a few days now and there is a lot that I like. However, there is one thing that nags me - when Slim is used to build a REST API it insists on putting everything into one single .php file - or even worse, a load of anonymous functions (one for each exposed REST method).
This works, that is not the issue. However, does it not mean that when used for building any but the most trivial of APIs you are imposing an unnecessary burden on the server by getting it to load and parse a potentially really big PHP file when only a tiny percentage of its code is relevant?
If yes, then it begs the next question - I am a newbie to micro frameworks - is there a micro framework that does things in a way that avoids this issue?
I'm unsure whether you are looking for a framework for a complete website or for an api alone. If latter I can recommend restler, which is a very simple, OO and stable package for developing API's.
On the other hand Laravel has built in resource controllers to ease the api development, it also has a very fast growing community.
If you're looking for both a website framework ánd an api framework in one, my guess is it will be very difficult combining that into one micro framework. Laravel/Symfony and other frameworks will eventually be needed especially if you expect growth in the project.
I made a REST API using AltoRouter:
http://altorouter.com/
I like the fact that after one route matches I can choose how to make the call, so I can point to the folder where I have all the REST controllers divided in several well organized files.
http://altorouter.com/usage/processing-requests.html
An example:
function rest_data($data, $format)
{
header("Cache-Control: no-cache, must-revalidate");
header("Expires: 0");
header('Content-Type: ' . $format);
if (is_object($data) && method_exists($data, '__keepOut'))
{
$data = clone $data;
foreach ($data->__keepOut() as $prop)
{
unset($data->$prop);
}
}
$options = 0;
$json=json_encode($data, $options);
echo $json;
}
$router = new AltoRouter();
$router->setBasePath('/rest');
$router->map('GET|POST','/', 'home#index', 'home');
$router->map('GET','/sample_users/all', 'sample_user#all', 'sample_users_get');
// match current request
$match = $router->match();
if($match && $match['name']=='home')
{
// write some intro
exit();
}
if($match)
{
$target=$match['target'];
list($class_name,$function_name) = explode("#",$target);
require($conf["src.path"].'/rest/'.$class_name.'.php');
foreach($_GET as $k=>$v) $match['params'][$k] = $v;
$controller = new $class_name;
$res = $controller->$function_name($match['params']);
rest_data($res,RestFormat::JSON);
}
If you are not so keen on the Slim PHP framework might I suggest something like Symfony ? Personally I like the way Slim works, and suits what I need to build right down to a T - however I can see your frustration with creating a RESTful solution. Symfony on the other hand breaks things up a little more so you have less fat controllers.
If Symfony isn't right for you I guess you could pull out a heavyweight ike Laravel?

Autoload or File Search

I'm building a fork of OpenCart that involves some very heavy rewriting of the core functionality to including dedicated themes that allow for overriding the core, similar to the Wordpress theme system.
If a given controller, model or language file exists in the theme, use that, if not, use the core file.
I'm currently autoloading all the system files which works great. But I'm wondering if it would be better to also autoload all my controller, model, and language files as well?
I've noticed that (even in OpenCart) the same file gets searched via the file system, and loaded multiple times. (models and languages in particular)
Would it not be more efficient to autoload all these files then simply instantiate the exiting class, over searching for the files each time then using an include?
Let me give an example ...
My homepage contains the following modules:
Slideshow,
Latest Products,
Featured Products,
Carousel
This along with the header and footer controllers ends up calling:
$this->load->model('catalog/product');
23 times.
That's 23 times that the same exact file is being searched for using the file system. Plus of course all the other models being called.
So I guess the question is really more about overhead ...
Is it more expensive to autoload (and cache) all files regardless of whether they're being called, or search the file system and do includes for each file as it's needed?
I'm sure this is an age old question but I've yet to see a definitive answer.
And BTW either answer is fine, I'd just like to be as efficient as possible in my code.
Well I get Your point but to be honest You should be concerned about this only in the case You can prove that the response times are somehow slower because of this reason. After having such proof (which is relative to the server's hardware, connection speed, whether it is sunny or stormy weather or day or night) You can issue a bug and a patch-fix using the github repository.
Now the model loading performs file_exists check, then include_once and afterwards it instantiates a new model object while setting (or replacing) it as some key in the registry. Current code looks like this (system/engine/loader.php):
public function model($model) {
$file = DIR_APPLICATION . 'model/' . $model . '.php';
$class = 'Model' . preg_replace('/[^a-zA-Z0-9]/', '', $model);
if (file_exists($file)) {
include_once($file);
$this->registry->set('model_' . str_replace('/', '_', $model), new $class($this->registry));
} else {
trigger_error('Error: Could not load model ' . $model . '!');
exit();
}
}
By just slight modification we can improve this code to perform only one file_exists check, only one include_once and having only one model's object:
public function model($model) {
$key = 'model_' . str_replace('/', '_', $model);
if (!$this->registry->has($key)) {
$file = DIR_APPLICATION . 'model/' . $model . '.php';
$class = 'Model' . preg_replace('/[^a-zA-Z0-9]/', '', $model);
if (file_exists($file)) {
include_once($file);
$this->registry->set($key, new $class($this->registry));
} else {
trigger_error('Error: Could not load model ' . $model . '!');
exit();
}
}
}
You can now put some time debugging into the original code and to the fixed one and find out whether this brings so great improvement :-)
Edit: Either way I would check how is this handled and done in OpenCart 2.0 (in it's latest status since it is not release-ready so far) and file an issue only if this is done the same way. Otherwise just fix your own installation(s)...

Using Cakephp Classes in external php code

I'd like to use Cakephp classes (models) from regular php code unrelated to cakephp.
I tried this but it didn't work:
include('/lib/Cake/Core/App.php');
App::uses('Business', 'Model');
$b = new Business();
The last line gives me an error, and I've also tried several workarounds with no success...
I'll be ever grateful for a good answer :)
EDIT: Here's the solution I found! (Thanks, #Burzum!):
I copied webroot/index.php to webroot/cake_setup.php and removed the last few lines so it will only include stuff and not actually execute anything:
App::uses('Dispatcher', 'Routing');
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch(
new CakeRequest(),
new CakeResponse()
);
Then, this worked from external php code:
if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
include_once(__DIR__ . DS . '..' . DS . 'v2' . DS . 'app' . DS . 'webroot' . DS . 'cake_setup.php');
App::uses('AppModel', 'Model');
App::uses('Business', 'Model');
$b = new Business();
Thanks a lot guys!
CakePHP is not made to be used piece by piece. If you're looking for a standalone ORM go for doctrine or propel.
You can keep trying it but you'll have to run the bootstrapping process of the framework (see what it does inside webroot/index.php) and register it's class loader and point it the the core include path.
Edit:
While looking at this again today, I think the proper solution here would be to expose the stuff your need from your CakePHP app through an API that the other non-Cake app can consume. REST is pretty easy with CakePHP you might want to look at that solution. You don't tight couple your other app on the CakePHP app then. You can even upgrade to 3.0 without having to touch the other non-Cake app then.

Rewrite URL in a somewhat MVC Framework?

I am not quite sure if this is done by rewriting the URL, but I did not know how to title it accordingly.
Here is my problem. I am currently working on a website project where I am using a abstraction of the MVC Framework (it is mainly for learning the Framework).
This is how my folder-structure looks like:
/controller/
|--indexcontroller.php
/myaccount/
|--/controller/
|--indexcontroller.php
|--index.php
/globals/
|--framework.php
/templates/
/options/
|--settings.php
|--config-www.php.inc
So currently I am using autoloader to load the classes which are needed. The index.php in the myaccount folder inherits the Framework class which should handle the class loading:
$urlparts = explode("/", $_SERVER['REQUEST_URI']);
$urlparts2 = explode("?", $urlparts[2]);
$class = str_replace(".php", "", $urlparts2[0]);
if ($class == "") {
$class = "index";
}
$letters_first = substr($class, 0, 1);
$letters_last = substr($class, 1, strlen($class));
$class = strtoupper($letters_first).$letters_last."Controller";
if (class_exists($class)) {
$object = new $class();
} else {
echo "Problem: class $class does not exist.";
}
The problem i have at the moment is, that I can only use "http://www.url.com/myaccount/" which is loading the indexcontroller.php in the controller folder from myaccount (which is fine). But I want also be able to use "http://www.url.com/myaccount/profile", where then instead "profilecontroller.php" in the controller folder from myaccount should be called.
How can I do this? URL rewriting? Or am I doing it totally wrong?
This might be a bit overwhelming at first but if you get it, it will make you life a lot easier.
1 ) Take a look at an existing framework like symfony, codeigniter, etc to see how they get the routing done.
2 ) Try to reuse these "components" (like routing form symfony) through composer so you won't have to do it yourself.
This way:
You won't have to write it all yourself.
You are using the hot stuff, like composer :)
You still learn by looking at the implementation of other frameworks
I hope this helps a bit :).

Zend Framework project without using Zend_Application

I've been reading on many sites even here that in order to improve performance of Zend Framework applications is not to use the Zend_Application in bootstrap, but haven't been able to find a site that has this demonstrated.
Do you guys know of a place that has this method described and might provide me with some code samples?
Thanks
I just threw this together:
https://gist.github.com/2822456
Reproduced below for completion. Not tested, just some ideas for how I think it generally (!) might work. Now that i have walked through it a bit, I have a greater appreciation for Zend_Application, its bootstrap classes, and its configurable/reusable application resources. ;-)
// Do your PHP settings like timezone, error reporting
// ..
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/_zf/application'));
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
// Get autoloading in place
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
// Any additional configs to autoloader, like custom autoloaders
// Read config
$config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', APPLICATION_ENV);
// bootstrap resources manually:
// * create db adapter
// * create resource autoloaders with the mappings you need
// * etc
// Get the singleton front controller
$front = Zend_Controller_Front::getInstance();
// Set controller directory
$front->setControllerDirectory(APPLICATION_PATH . '/controllers');
// Or set module directory
$front->setModuleDirectory(APPLICATION_PATH . '/modules');
// Other front config, like throw exceptions, etc.
// ...
//
// Create a router
$router = new Zend_Controller_Router_Rewrite();
// Add routes to the router
$router->addRoute('myRoute', new Zend_Controller_Router_Route(array(
// your routing params
)));
// More routes...
// Alternatively, the routes can all be in an xml or ini file and you can add
// them all at once.
// Tell front to use our configured router
$front->setRouter($router);
// Add an plugins to your $front
$front->registerPlugin(new My_Plugin());
// other plugins...
// Dispatch the request
$front->dispatch();
There might be some View/ViewRenderer stuff to do, as well. But as noted in other places, the ViewRenderer incurs a non-trivial performance hit. If performance is the issue, then you'll want to disable the ViewRenderer and make your action controllers call their own rendering using $this->view->render('my/view-script.phtml')
When you call $front->dispatch(), the $request and $response objects will be created automatically. If you want to do something specific to them at bootstrap - like setting the charset in Content-Type header of the response - then you can create your request/response object yourself, do what you want to it, and then attach it to the front with $front->setResponse($response); Same for the request object.
Although I see that my example uses Zend_Loader_Autoloader and Zend_config_Ini which Padraic notes incur performance hits. The next step would be to address those by using arrays for config, stripping require_once calls from the framework, registering a different autoloader, etc, an exercise left for the reader... ;-)
Hi I disagree somewhat with the not using Zend_Application in bootstrap and no I have yet to see a concrete example of this technique.
Personally I don't see the benefit in not using Zend_app for bootstrapping your application, assuming a) Your doing things 'the Zend way' and b) your project is either big enough or just simply warrants using the Zend framework (or any for that matter).
While Zend_App is great for creating consistent complex bootstraps
within a standardised structure, it doesn’t come without a significant
performance hit to baseline performance. A more direct bootstrap
(typical of ZF until Zend_App arrived) is far faster and can also be
done without configuration files.
Taken from Pádraic Brady link.
Well to me the above does not make sense, he basically just said Zend_App is great for complex bootstraps, but adds a performance hit. But isn't that the premise for ANY framework / framework component? I know Padraic is a very clever guy and I'm sure he has his reasoning, but I too would love to see examples / evidence of this suggestion.
Perhaps in answer to your question, you could benchmark a basic app using the latest Zend framework and then use Zend framework from < 1.10 using the old non Zend_App way, but I would say although clearly not perfect Zend_App is clearly faster to get most app's up and running, so whether this is worth 'the performance hit' is I guess up to the developer(s).
Here is a link which somewhat goes into what you may be after but makes reference to a modular approach (still interesting, none the less):
http://www.osebboy.com/blog/zend-framework-modules/

Categories