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?
Related
Really not sure if the title of the question suits the question overall. But here goes.
What I have currently is an existing SaaS project. That we want to roll out a new template over time. Think of how google introduces new features. Or some other sites might with "Try our new Beta Version".. type of thing. Well we want to do the same, and then we will eventually phase out the old look and feel.
With that, this application is built on top of Zend Framework, so looking through docs I can figure out how to override the template on a given controller. But what I want to basically do, is likely going to make use of the sessions. If it exists, use this template. If not, use the old one.
Is it possible to override the default template in such a fashion? Right now for example, the default loaded file, is "tops.phtml" if the session exists I'd like to load "tops_v2.phtml" for example. So it can use that as the template instead of "tops.phtml" when the session is found.
Zend Framework 1.x solution:
You can disable ViewRenderer plugin in the action, and choose template manually:
public function indexAction(){
$this->_helper->viewRenderer->setNoRender(true);
echo $this->view->render("path/to/template/template.phtml");
}
I think that layouts are the thing you probably want to use, as was briefly touched on by Richie. Based on the question, I'm guessing you aren't already using them. Ultimately you can design a layout that defines the overall website look and then each of your action templates will only then render a fragment of the page (which will be dynamically placed in the content portion of the layout).
Using whatever logic you choose, you can then assign one of any number of layouts to be used on a given page load and of course you could store this as a user preference or something.
I have searched the web and found only styling code posts. I want to write site using Code Igniter and I wonder how should I maintain my code.
For example:
Should I use one class for static pages and methods for each page or separate file for every static page. Should I use the same file to load dynamic pages or different one?
Can I use some common code and include it automatically to every class?
How can I have lets say header_view footer_view etc and then just load->view('whatever') and footer, header and other files would load automatically. Maybe there is better way to do that?
In generall what are the best practices when coding using CodeIgniter.
You can use one single class for static pages (and use one method for each page).
You can use the same one to load dynamic pages, but it is better IMO to load them with a separate class. It will be easier to maintain later.
Using common code: You can always override the CI_Controller with your own, and instantiating controllers from yours. Here is an example about how to do it.
You can load multiple views in a single controller function. A view doesn't have to be a full html document. You can also load the same view multiple times (for example in a loop).
Best practices: CodeIgniter is an MVC framework. IMO, MVC is a best practice. Always use the framework's documented features if they are suitable for what you want to achieve (CodeIgniter's documentation is very good. That link is momentarily offline, so please try this one).
Codeigniter is a MVC based framework, MVC is basically used for organizing your code, so at last its up to you how you are going to use it so ease you on the long term.
Basically when I design large projects in codeigniter I tried to to make unit of functionality at one place lets take example of any simple users, messages based project.
I tried to make functionality by grouping main topics, in this example user will be a controller, in that controller there will be methods like login, register, edit, listing, forgot_password now I'll create single model with all the methods which will give data for these above methods. by using this methods our urls will be also meaningfull like /user/login, /user/register etc
like that if its messages I will create controller message and add all related methods in it so that my related functionality will be in a single group.
as far as the question of static pages you can also group them in a single controller if they can be a part of group.
you can also use codeigniter's caching technique for static pages so that your pages will load faster
I'm trying to think of a way to create a plugin architecture for my own framework. I've read numerous topics and post here and on other sites. And basically i've came to the following solution which seems to be the only good option in PHP (currently).
The idea is that every class extends a sort of observer like class. So a Template class, BaseController etc. always extend a Plugin class.
class BaseController extends Plugin
{
public function __construct()
{
// Plugin check, notify all loaded plugins
$this->checkForEarlyHooks();
// Init some standard stuff
$this->view = new Template();
$this->baseLayout = 'layout.html';
$this->something = new Something();
// Plugin check, notify all loaded plugins
$this->checkForLateHooks();
}
}
So what basically happends here is that when an indexController extends a baseController a plugin check is done. In this case for the constructor. This can be convenient when you want to do a some sort of login check with a plugin, before an Action method is actually invoked.
The Plugin class can resolve from what class is got called from and knows for what functions to look for in the loaded plugins.
Also note that it checks the loaded plugin list 2 times. One before anything is loaded (early) in the constructor, and one when all vars are loaded (late).
I can also add variables to the "checkForLateHooks()" function. So the hook functions can manipulate those too, like the 'baseLayout' variable.
A hook function would look like this:
public function hookConstruct ( &$baseLayout )
{
$baseLayout = 'login.html';
}
Now basically my question is, is this approach any good? I know there are probably alot of other ways to do it too. But i mainly don't want to run into design problems later on. It seems like a good idea now, but you never know how things work out later on...
If i remember it right (from all the posts the i've read), this is kinda like WordPress does it (and some other frameworks).
UPDATE: answer now reflects the up-to-date links and better description.
There are certainly many different ways to design a plugin system and perhaps asking on https://softwareengineering.stackexchange.com/ would give you more ideas, but I'll try to help by sharing my ideas and experience.
I'll share some of my own experiences which I've learned through a series of my own frameworks. Currently Agile UI and Agile Data both support many wasy to be extended, but I'll focus on the "Components"
HOOKS
When you look to inject code into the existing object, a hook is a standard way to go. It's the best option for extending the application or flow with an established structure.
While refactoring my frameworks, I've separated hook implementation into a separate trait and documented it here: http://agile-core.readthedocs.io/en/develop/hook.html
Host application:
... some code here ..
$this->hook('beforeInit');
$this->init();
$this->hook('afterInit');
... code goes on ..
Plugin:
$host_app->addHook('beforeInit', function($object) {
echo "About to execute init of $object";
});
UI COMPONENTS
Components present a different design pattern, which is suitable for the User Interfaces. You start with the page/app layout which is then broken down into Menu, Header, Footer, Content.
A component is an object which can be associated with Layout or the other component. Each component is capable of rendering and passing extra HTML/JS to its parent. Most of components would also be an interractive objects.
This approach is called "Render Tree" and application execution goes through 2 stages - "initialization of a render tree" and then "rendering".
Host Application:
$layout->menu = new \atk4\ui\Menu();
$layout->add($layout->menu, 'TopMenu');
The above code show how a new Component (Menu) can be initialized and inserted into the $layou. Furthermore the HTML output of $menu is directed into {$TopMenu} tag, which is defined in the HTML template of Layout.
Plug-in can interact with the render tree by:
adding more components anywhere in the tree
affecting existing components (e.g. add new menu item)
destroying any of the existing components
When those approaches are combined, you can use something like this:
$app->addHook('afterInitLayout', function($app) {
$app->layout->menu->destroy(); // remove default menu
$app->layout->menu = new \plugin\SuperMenu();
$app->layout->add($app->layout->menu);
});
This can be used to replace standard menu with a more powerful implementation from your add-on.
My implementation of components is documented here:
http://agile-ui.readthedocs.io/en/latest/view.html#initializing-render-tree
UI / DATA SEPARATION
Although perhaps not so much answer for a question, but another powerful way to extending is a separation of concerns. All of the UI components in Agile UI do not know how to do anything with data.
While many UI generators require developer to manually build them up and link up with data, I am injecting "Model" object like this:
$form->setModel(new User($db)); // populates name, surname and gender fields
Demo: http://ui.agiletoolkit.org/demos/form2.php (2nd form)
In this approach object User contains enough meta-data for the Form to populate it's fields, captions perform validation and also save/load data.
Since "User" class can also be declared in an add-on it makes a pretty powerful way to extend existing functionality by adding support for new data entities.
OTHER APPROACHES
Some other approaches to extend with add-ons include:
Factory:
The ability to resolve class specified as a string into namespace / file:
$api->add('MyClass');
Gives ability for add-on to re-route standard classes but is not very friendly with type-hinting in IDEs.
New types / Traits:
Add-on can provide new classes adding Persistences, Table Columns, Form Fields, Actions etc.
CONCLUSION
I think add-on deign boils down to:
simplicity of installation and use
does add-on need to operate out-of-the-box?
avoiding conflicts between add-ons
defining different add-on types - authentication, UI, behaviour
can add-on extend another add-on
will add-on fit application design, data and architecture?
give a lot of power to add-ons without sacrificing performance
Have a look at PHPPlugin on https://github.com/gheevel/PHPPlugin. A simple PHP plugin framework inspired by eclipse and jira plugin architectures. Basically, your application can define extension points and plugin instances can register on those extension points for providing extra functionality. Works well in combination with composer and/or symfony.
I'm thinking of re-working my MVC before I get to far along with it. At the moment it uses a sinle controller which takes the user input and determines the model. The model has maby differ methods which I call actions, because one is called automatically. The model loads its view file, which again holds many different methods. The model can set properties which can be used in the view. Then the controller calls th template classwhich parses the output for display.
Is this the bst way to do it?
Or should each different part (news, contact, about) have its own controller, which loads a specific model and view. Essentially, instead of grouping methods into a single file, it uses multipe files.
I'm kind of lost as to how I should do it.
Cheers
Start using a MVC that works and is well-known like in Symfony or Cake. From that you will decide:
what do to in your own, knowing the best practices;
to drop your own if you feel like you can save time by using theses.
If you are thinking of advancing your own MVC model, like #e-satis have said, you will need to experience what is happening in already developed systems. However, as based on my experience in designing MVC model and determining what is there in opensource community, I stick back to my own MVC for two good reasons. One reason is the flexibility of customization and the other is own MVC privacy.
I used the following approach for MVC design pattern.
A Router.php file identifying user-request urls. This router will be able to fetch controllers and include the file and call the controller default method.
The loaded controller is also able to load other controllers if required to function. This is done using a global method, where all controller Class will extend to a MainController Class which is able to call to other controllers.
I do use a global registry to set and get variables from one controller to the other.
The Models are used to get the Data from Table, and most of my Models will represent Database functions which includes CRUD (Create Read Update Delete). So that a controller can easily manipulate database table data using a model.
Naming conventions in all controller, models, and views is also important, if you want to system to be more intelligent to identify the required action knowing the file name.
I use the Views separately for each type of controller. And these views will be sent to a Master Template View file.
Same as models, the controller will be able to set Views to Master View.
There are other customizations which you can do, like applying security methods before calling a class, or after calling a class/controller/model/view etc.
This is done by the MainController, which it will always look into a folder with autoload class which states what files should be loaded before and after of different actions during the process of building the content and delivering the output.
MVC is not a small scale idea, but it is a design idea which can always be developed. There are so many PHP MVC open source frameworks to be found if you know how to search the major search engines like google.com
But I do advice you that, MVC is not a good solution if you are simply developing a small dynamic website, as it will consume more time in developing compared to developing small websites. MVC is ideal, if you have business logic and needs system automation in order to avoid most routine tasks of developing, and like that I would say MVC is most ideal for larger applications.
The model loads its view file
The Controller should act as a Mediator between the Model and the View.
The Model shouldn't be aware of the way the view renders it, and also the View shouldn't be aware of any kind of logic of the Model.
In theory, if your MVC is well structured, you should be able to represent the same Model with different types of Views (HTML, XML, JSON for example).
Build FrontController which parses request uri and decides which controller to load and which method to run. With .htaccess rewrite all request to index.php
//index.php
class FrontController{
function run(){
//parse request uri here /comment/new
//load controller comment
//run controllers method new and pass some request attributes
}
}
// ../controllers/comment.php
class Controller_Comment extends Controller{
function new($request){
//do stuff here
}
}
I'm starting to write a application in php with one of my friends and was wondering, if you have any advice on how to implement module support into our application.
Or is there a way how to automatically load modules written in php by a php application? Or should i just rely on __autoload function?
And we don't need plugins that are installable via a web interface, we just need some clever way to associate web pages of our project to some classes (they will render the page) so index.php can call the right class and retrieve it's generated sub-page.
And we are not using any kind of framework, for now at least.
Re your comment: Autoloading in conjunction with strict file naming would be totally enough in this case IMO.
You could define a specific namespace (not in the new PHP 5.3 namespace way, just in the sense of a common prefix to names), e.g. Module_* for module class names.
You could then organize your modules in directories with class files that contain exactly one class definition, for example:
/modules/Mail/index.php // defines class Module_Mail
/modules/Database/index.php // defines class Module_Database
/modules/Image/index.php // defines class Module_Image
Your autoloader function would then, whenever a Module_* class is requested:
$Database = new Module_Database("localhost", .....);
include the correct file from the right directory.
That's the way e.g. the Zend Framework does it, and does so pretty well.
Consider choosing a more specific namespace than Module_ to assure interoperability with other scripts and applications if that is an option in the future.
Slightly related: In a PHP project, how do you organize and access your helper objects?
It sounds like you are looking for a way to organise the different tasks that each page needs to carry out. In this case, take a look at the MVC pattern. It provides a simple way to seperate your data access (models) and how you render/present information (views).
You can map pages to functions with ease. If you store the information in an array of mapped values, and then use a function to compare the requested URL with each of the URLs in the array. Such an array could look like this:
$urls = array(
'/' => 'index',
'/aboutus/' => 'aboutUs',
);
There are several articles that discuss how to implement it in PHP in a couple of hours. This article is a very simple guide. I am not a fan of their use of the registry pattern but reading through should provide you with enough information as to how you can implement it yourself.
Regarding autoloading, you can also use spl_autoload_register, to define several (more than one) autoload functions, so each module can set up it's own implementation of autoloading.
All you need here is an MVC architecture, with one Controller class associated with each "module".
If you are not against using a framework, go for Zend MVC
It allows you to have the following principle :
An URL like this : http://yoursite.com/my-module/edit
Will more or less automatically call the editAction method in the MyModuleController class.