I've just started to look into MVC and I'm pretty new. I would like to port procedural code across to it but I'm struggling (please no-one suggest to use a Framework).
I can understand how it works, but understanding is different to doing. In my procedural code, I have several functions such as message(). These are called if the user does not have permission to view the current page, for example.
My problem is adding this into MVC. I've added Twig so far and I've managed to render some Twig on the index page but using functions such as message before was as easy as this:
message('Message Text');
Adding it to the controller directory would allow it to be accessed as a web page, which I don't want. And through the model, I'm not sure how to do this without requiring the file first. I could use a function, but I don't want globals and this is partly why I'm changing.
How can I properly place commonly used functions?
Edit
What I'm using is a modified version of this: http://www.phpro.org/tutorials/Model-View-Controller-MVC.html
I tend to think of traditional MVC like this:
A controller is my business logic to implement my product.
A model is the code to represent data.
A view is what represents my product.
Under this paradigm, what represents my product is what an end-user sees.
So if it's a UX component, it's part of the view.
In this way, it's pretty easy to figure out how to use it:
You could use path/to/notifications.php and then $notifications = new Notifications(); where notifications.php is a class facilitating messages like you reference.
You could extends Notifications on your view (or even a base view!) so that ANY view you instantiate immediately has access to your notifications class.
You could (though probably shouldn't) require_once( 'path/to/notifications.php' ); and then the class or functions therein would be available. Again, you probably shouldn't do it this way
The bottom line is this:
Place your old procedural code in a well organized class. It might be named something like Notifications if that's what the code does. The important thing is to organize well, name well, and do not try to force too much code into one thing.
Use that class in your code. You can explicitly use it's namespace and new an instance of it, or you can extend it to bring it along as the parent class of your view.
Related
I have an object oriented framework that uses a page design, where each page extends a view of the framework. So, for instance, my index page for a site is actually a class that implements the abstract class View provided by the framework. I hook the framework by including a startup script at the top of the page and after some processing the framework creates an instance of the page and processes its view data. To add flexibility to the system, I don't require the class name to be the name of the file itself. This allows me to create something like a support class and have it behave as the index for the /support/ subdomain.
I was initially passing the page's class name into the framework via the framework's constructor, but this added a few more steps to the top or bottom of the page. I currently obtain the class name via a pages table in the database identified by a filtered requested URI. I use this table to build navigation and adding an extra table column was practically free. This works OK as long as I have a database connection, but I'm trying to implement static page support for status messages and error reporting, and I need another method for creating an instance of the page's class. If I use the standard convention of naming the class the file's name, then I know I have a dependable way of extrapolating the class name. I don't really want to name all my classes index just for presentation reasons. What is some advice or some standards for how object oriented frameworks are initialized?
View.inc
<?php
abstract class View
{
abstract function getView();
}
?>
Startup.inc
<?php
require_once("View.inc");
require_once("CoreController.inc");
$Framework = new CoreController();
$Framework->Initialize();
exit;
?>
index.php
<?php
require_once("Startup.inc");
class Index extends View
{
public function getView()
{
echo "<pre>View Data</pre>";
}
}
?>
Within my framework I have a TemplateController that processes the page. The page class is known because it is mapped via another class. Without a database however, I would like to discover the class within, say, index.php without changing the way it's currently set up. Here is the actual code within the TemplateController.
//Get the View Class from Page
$view = $page->getPageClass();
//We need to catch View creation failure
$this->Page = new $view($this->Framework);
//Initialize the Page View
$this->Page->Initialize();
//Cache the Page View
$this->cacheView($this->Page, $page->getPageName(), $this->SiteID.TCS_PAGE_SORTID);
In the snippet above $view is the actual name of the class that was mapped from another controller. I'm passing a reference to the framework to the view's constructor and the rest is really irrelevant. I'm trying to come up with a similar mapping technique to identify the page class in the event the database is down. I like the one include line for the framework startup and would like to keep it that simple.
At the top of the TemplateController I have to also reinclude the actual page, since my startup script is at the top, the actual class is not included even though it is the requested page.
include($_SERVER['SCRIPT_FILENAME']);
Please review Stack Overflow question Identifying class names from $_SERVER['SCRIPT_FILENAME'] for more information on what I'm attempting to do.
Here is my checklist of page routing:
Adding new page must be quick
You must not be able to add page unintentionally
Application with million pages should not be slower or more bloated than application with 2 pages
Provide simple way and let people enhance it if they want
Allow easy re-factoring, such as moving several pages into different location
Make framework detect everything. Don't force user to specify base URL, etc.
Create simple to understand page names (hello/world).
Clean illegal characters from the URL
Make it possible to add static pages easy
Provide a way to generate URLs from page names.
Allow user to use pretty URLs by changing what appears before and after the page in the URL
And most importantly
- Stop copying, think about the best approach.
All of those suggestions I have used in the PHP UI framework - Agile Toolkit where I am a contributor.
Relevant sources: Agile Toolkit - a PHP Framework with jQuery, Agile Toolkit - PageManager.php, Agile Toolkit - URL.php and Agile Toolkit - PathFinder.php.
We wanted to make it really simple for developers. And secure too. And flexible. Therefore the "page" class is selected based on the URL. How? Quite easy:
/hello.html -> page_hello
/hello/world.html -> page_hello_world
Class then is mapped into filename. page/hello/world.php
Then there are cases when we want to use dynamic URLs too, such as: /article/234
Many frameworks implement a complex techniques here (arrays, regular expressions, front-controllers). We don't. There is mod_rewrite for this. Just rewrite this into page=article&id=234 and it works. And scales.
Apart from pages, there are other classes, but those classes can't be accessed directly. Therefore pages live under the /page/ folder, do distinguish them and maintain security.
Then comes the designer saying - "I won't write PHP". So we introduce static pages. If class page_hello_world is not defined, we'll look into template/skin/page/hello/world.html. That's a easy shortcut for designers and non-developers to add a new page.
What if a page is not found? Api->pageNotFound() is called. Feel free to redefine and load pages from SQL or display 404 page with a picture of a pink elephant.
And then there are some pages which come from add-ons. We don't want to enable them by default, but instead let users add them to their app somewhere. How?
class page_hello_world extends Page_MegaPage
Next question, is how we handle sub-pages of that page, since sometimes all the functionality can't fit on single page. Well, let's add support for page_edit() method (or any page_XX) as an alias for a sub-page inside those classes. Now add-on developer can include a multifunctional page which can be extended, customized and placed anywhere in the application.
Finally there are hackers, who want to do something really fast. For them we apply same technique to the API. You can define function page_hello_world in the API, and you don't need class.
Some might say that there are too many ways to do a simple thing. Oh well.
I hope that this was helpful.
Use __autoload(). Most major PHP frameworks use autoloading to streamline class loading.
You need some way to map a URL to an object, which is usually handled by a routing component in most frameworks. Might want to take a look at libraries such as https://github.com/chriso/klein.php, or the routing components of the major Frameworks out there (Zend, Symfony, etc.).
Why not to use information from URL to detect correct class? Since you won't use database for static pages, you have to somehow store mapping between URL and class in file. I.e. you will have a file mapping.php:
return array(
'about' => 'AboutView',
'copyright' => 'CopyrightView',
);
Here, about and copyright are URL components and values represent appropriate child classes of View. You can have URL's like http://example.com/index.php?page=about and use rewriting capabilities of webserver to make them look good.
You will change implementation of Page::getPageClass() in order to return correct view class. Depending on URL it will use static mappings from the file above or use database.
What's the problem with this approach?
Hi i'm a PHP developer trying to convert to Django and im having a bit of a hard time understanding where to put things and how to use the new language. Basically what i want to know is for example in codeigniter i would make classes and functions in my controllers. Where do i do that in django?
I believe the 'view' in django is more like the controller in an MVC framework but all the examples i can find of the view are very simple and just call a template and pass it some data.
I currently have an index view and a 'rates' view in my current project. The index page will call rates via JS and pass it some GET variables. In my php version i used these to instantiate my rates class which when had all the needed functions in it. I want to do this in Django.
The reason that it is called, "MVT" instead of "MVC" is that "View" to Django means, "presentation of data (according to given logic)" and "Template" means, "display of data presented." In a traditional MVC paradigm, "Controller" means "executer of logic" and "View" is "presentation of the result of the executed logic". (They are almost the same idea, but not quite).
So, what does this mean? Basically, if I were building something in Symfony, I would put all of the logic in the sfAction components. In CodeIgniter, it would be in the CI_Controller. In Django, I will place all of the logic in the "Views".
Just like CI (and Zend and others) will then call a "View" from the Controller descendant, the Django view will also call a "Template" from its "View". (Symfony's views are often called in a different syntax, so I will leave that to the reader to research if so desired).
Looking at your example, it looks like you want to call a method in the "View" (which view is configured in urls.py) which simply instantiates another object which has "all of your logic in it". Something like:
def ratesHandler(request):
rate = MyRatesClass(request.GET)
return HttpResponse("Insert something here. ") #or render_to_response
The logic always belongs in the view. You can put whatever logic you like there - no need to put it into a class, unless you want to. If the logic is related to a specific model, though, it is best to make it a method of the model or the model's Manager.
In django: "models" go in models.py, "controllers" go in views.py and "views" go in templates.
Models tend to be classes that subclass django.db.models.Model
Controllers (in views.py) are often functions but you can use classes if you like.
Note that if you're just displaying data from the database you can often use generic views so you hardly have to do any coding at all.
I can't tell whether there is a question in the last 2 paragraphs of your post. If there is a question there, please edit your post so it's clear.
I’m fairly new to CodeIgniter and have a question. I’m a bit confused about Classes, Libraries and Objects.
Does CodeIgniter replace the normal PHP way of usings objects i.e. $var = new car(); with libraries i.e. $this->load->library('some_library'); $this->some_library->some_function(); ?
If both are valid, is there a difference? If so, what are the differences and when do I use one over the other? Which is more common/proper?
I am asking because I created a class, but I'm not certain what is the correct manner in which to instantiate it.
Thanks in advance
I am not familiar with CodeIgnitier. But familiar with other PHP frameworks. Most of frameworks use this way for performance improvements, registering things, executing certain events, and making things simpler for developer...
For example if you want to create class "car" with is somewhere in library directory you would have to include the file first before you can create object of that class (miltiple lines of code, more room for error). The framework will create the class and includes related files in 1 line of code (easier and safer).
Framework way also works as a factory. Instead of recreating an object, it will create object only once and every time you call the method again it will return the reference to existing object.
More things are happening behind the scenes when you use framework. Things are getting registered, etc...
CI doesn't replace class behavior per se, it simply adds functionality that allows access to custom libraries/models/views as singleton objects via the core object for simplicity.
Nothing is stopping you from creating (as I have in one of my projects) additional files with classes for non-singleton entities and require them in a model for further use. On hindsight, I should probably have used helpers for this.
What the loader ($this->load) class does, among other things, is it creates a single object of the specified class (model, library or view - not helpers though, see below) and attaches it as a property of the core class that is normally accessible via $this.
Helpers are a bit different. They are not attached, but instead simply 'read' into the global namespace from the point where they are loaded.
To answer your question, it would be more proper to use the loader class in instances where you don't need more than one instance of a class created. If you need 'entity' classes, your best CI-compliant bet would be to create them as helpers.
Given only this context, this looks like Inversion of Control (maybe I'm wrong, I haven't looked too closely at CodeIgniter).
You don't want to rely on the type car as in new car(). What if later you want to make $var a racecar? $var can still do the same things, but it is forced to be a car because you constructed it directly. Or what if you are testing this class, but car is some complex object which calls some external service. You want to test your logic, but don't care if the car service isn't working. So you should be able to change $var to actually load a mockcar. You can't do that if you do $var = new car().
What is Inversion of Control?
I've got a class Widgets. Widgets are made up of Doohickies. I'm never going to need to access Doohickies directly via url -- they're essentially a private class, only used by Widgets. Where do you put your code to define the Doohicky class? In /app/controllers/doohicky.php? in app/controllers/widget.php? somewhere else? Obviously, the former seems cleaner, but it's not obvious to me how to make the Doohicky class available to Widget.
It sounds like your Widgets and Doohickies are probably Models in MVC architecture.
In which case, your paths would be:
app/models/widget.php
app/models/doohickies.php
I see the question has been answered already, but there are a few things to bear to expand on it.
You could put widgets and doohickies in the libraries folder, if they are there to do a job rather than provide a data service.
Also, take a look at HMVC, which favours the idea that you can have mini-apps that look after various parts of your website (e.g. messages panels, search box/results, doohickies...). This enables you to have smaller view partials dedicated to their widget controllers; and then the main controller calls in widgets but doesn't need knowledge of how they came about.
http://codeigniter.com/wiki/Modular_Extensions_-_HMVC/
straight to the point :
I am using Kohana, and I am looking at another script written in plain PHP. In the script, I have a class ShoppingCart. If I am to convert the script to Kohana, where am I to put the class, its methods and its properties?
Is it in my existing default controller? Or should I put it in a separate controller? Or as noobie as it may sound, will I put it in the model?
That depends on the specifics of the class I suppose. To be honest I don't know anything about Kohana, but there's probably a place for "vendor files" somewhere. Maybe it's best to place it there and write wrapper functions for it in your controller. If the class already integrates well with Kohana you may instead choose to use it as a controller or model directly. Or you might want to take the time to rewrite it to make it work as a controller...
Only you can evaluate the best place for it, there's no hard and fast rule here.
Kohana has a folder for 3rd party libraries. The main one is under system/vendor, you can put it in you application/ as well.
Many PHP class loaders require details like your filename should be the same as the class name (at least that's what I read in the Kohana documentation) if you want the classes to be automatically loaded.
If you need to use 3rd party code in your app it's recommended that you create a folder in your app / module folder called 'vendor' and place all of that code there.
You can then include the files by calling:
include kohana::find_file('vendor', 'filename');
If needs be you can also create a wrapper for the external library, a good example of this is the email helper which uses the 3rd party Swift email library.
If you're porting your own class to kohana then you need to work out what the class will be doing and categorise it accordingly.
If the class will be fetching items from some kind of database then you should make it a model. Libraries are usually sets of code that you want reuse across controllers / models, such as authentication, calendar generation etc. Controllers are used for passing data from models to your views / libraries.
See the docs for more info
As per kohana convention, you should place custom classes in application/libraries folder. However for this, you need to know how to get the class to work after putting it there. If you can't figure that out, you can do anything like putting it in your controller or making another controller of it, etc.