How to avoid bloat in Zend_Navigation? - php

I've been researching using Zend_Navigation in combination with Zend_Acl to manage navigation and access permissions in a new app I'm working on.
One thing that really bothers me, is the examples I have seen end up making an enormous XML file that contains every possible nav item in the application. Loading this file on every request seems like major performance bottleneck and there has to be a better way. I realize I could alleviate much of that with the use of memcached or another caching mechanism, but I feel like the application itself should be written in the most optimal way and, only then, do you add caching. It doesn't make sense to make something slow and bloated and rely on caching to clean up my dirty work.
I'm using a modular setup in this ZF app, so each module has a unique bootstrap. I've considered creating module specific nav XML files and loading the specific one, but I'm not sure if that's the best way either.
What is the suggested method of using Zend_Navigation in large application with potentially hundreds of navigation paths?

I wouldn't call this the suggested method it's just how I work with it when I basically had the same question two years ago. In a nutshell: I have all the paths in the XML I need on each and every single page. All other paths are added at run time. Only then I add the ACL.
First, be aware that ACL in Zend_Navigation only manages the presentation of the navigation. It doesn't provide or better guarantee access control to your application. A certain link will be missing in the menu but if the user knows the correct path s/he may access the resource nevertheless. Of course, you can use the ACL information in the navigation object to bolt down your application but I believe there are smarter ways mainly to incorporate ACL directly into controllers and models.
Second and to your main question, my navigation's XML file only contains the most basic structure up to the second level which is the menu I always need. It's also more or less what I have controllers and actions for. Any paths resulting from params are added at run time. Because of that I don't even include the ACL into the XML but inject it at run time. Simply because only then do I have the full extended current branch with all its paths.

I've not used XML to generate navigation. It is possible to add your pages at run-time in php using array notation.
Using modules, you could set up the navigation object in the registry, in each module have a model that adds its pages, and a plugin that calls each modules' navigation model at preDispatch.

Related

Two step layout for multiple modules in php?

I am creating a web application in PHP. It is built with multiple independent modules. For the sake of example, let's say there is an email module and file explorer module. Each of them have physically separate folders with different libraries etc. However, in the frontend they both have the same interface (navigation is the same and content in the center is changing).
I want to centralize my interface in the backend. How could I create some kind of two step layout so whatever app is called on the backend, the content of it is merged with outer interface and then sent back.
I want to make this because if there is a change in the outer interface, I have to copy code in all of the modules.
Below is the example mockup to show you what I mean. Content interface is changing and static outer interface is always the same no matter the app that is chosen.
How could I achieve something this elegant?
It could be worthwhile spending some time seeing how likes of Laravel 4 and other similar frameworks achieve this (if you haven't already that is).
For example in Laravel 4 it is reasonably easy to separate an application's business logic into modules, and share certain parts of the views across these modules using layouts, eg. you can create a master layout template that includes the master static outer interface as you show above, and then each of the individual module templates can extend this with a simple
#extends('layouts.master')
at the top of each of the content interface views. More details here - http://laravel.com/docs/templates
I am not suggesting that you use Laravel, but it is likely that you can find the answer to your question in one of the existing php frameworks - even if you copy their solutions rather than adopting the framework it may be quicker than reinventing the wheel :-)
Glen

What should a bundle in Symfony2 represent

This might be an obvious thing to you but - even after reading through a lot of manuals and blogs - I'm still not sure what exactly should a bundle in Symfony2 represent in a webpage. And it's hard to guess it from the simple demo applications.
For example: I have a site which is divided into two parts (one is just a 2nd level domain like example.com and another is dom2.example.com). Each of these two parts has some sections of it's own - sometimes the same (like news) sometimes different.
What would the correct representation of this in symfony2? Should I have
a MySite\site1 and MySite\site2 bundle and do the different sections via different controllers, or
bundles Site1\News and Site2\News, or
bundles MySite\Site1News and MySite\Site2News etc.
...or am I getting all wrong at this?
I am also new to Symfony and will follow the results of this question with interest, but for what it's worth, my take on it is:
A bundle is just that: a group of files, assets, PHP classes and methods, tests, etc. The logic of the grouping can be anything you like. In some cases, it's really obvious what the grouping is and why it's been done -- for instance, if I wrote a blog system for Symfony2 and wanted to release it, I'd make it into a bundle. That's the sort of example used most in the documentation.
But you'd also use bundles for anything you wanted to release as one little feature. Say for instance, this bundle which creates default routes for all your controllers. It's not a fully developed plugin/feature like a blog or forum, but it's a bit of code that I can easily import into my project, it stays totally separate from everything else, it's a bundle.
Finally, you'd also use bundles internally to your project, in absolutely any way which makes sense to you.
My take on your specific situation:
Quick and easy:
MySite\MyCode -- gets the job done, and maybe you don't have any logical way to break up the code you're going to write.
If there's some more unique features between the two sites and you want to separate them out for clarity:
MySite\SharedFeatures
MySite\Site1Features
MySite\Site2Features
If you really like everything in its place, or if you have a complex project, maybe:
MySite\MySiteMain (shared features and catch-all miscellany that doesn't deserve its own bundle)
MySite\News
MySite\Site1FeatureSomethingOrOther
MySite\Site2FeatureSomethingOrOther
I definitely think you want to stick to logical groups of code -- so I think your example "bundles Site1\News and Site2\News" and "MySite\Site1News and MySite\Site2News" wouldn't be the best way to go. Site1 and Site2 are implementations, so making a separate bundle for each site's news page would seem to be counterproductive to me; you'd want to make one news component and build it to be used in two different ways.
As for your two-domains question, you can either point both domains at the same code, and test within your code for what domain is being requested, or you can check out two copies of the same code and change the configuration files slightly (this doesn't necessarily violate the idea of DRY because you'd still edit the code in one place, then update both copies.)
The way I understand a bundle is that it is similar to what CMS like e.g. Typo3 or Drupal call a "plugin". So it should be ideally self-contained and written in a way that it can be used on other projects too.
E.g. in your case I'd create a "staticHtmlBundle" that contains all the static pages of your website, divided within by site.com and dom2.site.com.
Then I would create a "newsBundle" that contains all the news-articles, maybe even database-driven with a little admin-section where you can edit them and assign them to different channels (in your case that is site.com, dom2.site.com). A static page from within staticHtmlBundle would call newsBundle and display its data (like e.g. a listView of the news or a detailView and so on).
If you keep everything as abstract and reusable as possible then you could even publish the newsBunde in the Symfony 2 Bundle repository and share it with the community!
The way I perceive Symfony2 bundles is that they are provide a modular system which allows you to not only extend and override the php code, but also any resources they may or may not include.
Having said that, consider you have an API and you would like to transfer an object.
How would you do that?
Of course, you can do that manually, but wouldn't it be nice if Symfony can do it for you?
My way of doing this would include 3 bundles, JMSSerializerBundle and FosRestBundle.
One bundle for the client side - MyCompany/ClientBundle
One bundle for the server side - MyCompany/ServerBundle
One bundle housing all the data transfer objects I would like to be able to transfer - MyCompany/CommonBundle.
Inside my MyCompany/CommonBundle I would have the classes I would use for my data transfer objects along with the serialization rules I would have to provide the JMSSerializerBundle with. They may be in the form of xml, yml or php annotations.
Once you have an object filled up with the data, you can just use return and FosRestBundle would serialize it for you. Serialization would depend on the routing, so you can have the object serialized in XML for one system and in JSON for another. Key point is you have different serialization formats and versioning you can utilise at later point.
On the client side, you can use simple param converter to convert the received JSON or XML to an object right in the controller with no additional hassle. You can also type in some validation rules, so you can verify if the object is populated as you expect it to be.
In my example, the MyCompany/CommonBundle has objects that would be used by multiple applications and would be identical. Having that as a separate bundle helps you avoid code duplication and makes long term maintenance a lot easier.
I hope I managed to explain this. Any questions?
Ask in the comments. Will update the answer accordingly.

Why should MVC for websites require a single point of entry?

I see many MVC implementations for websites have a single-entry point such as an index.php file and then parses the URL to determine which controller to run. This seems rather odd to me because it involves having to rewrite the URL using Apache rewrites and with enough pages that single file will become bloated.
Why not instead just to have the individual pages be the controllers? What I mean is if you have a page on your site that lists all the registered members then the members.php page users navigate to will be the controller for the members. This php file will query the members model for the list of members from the database and pass it in to the members view.
I might be missing something because I have only recently discovered MVC but this one issue has been bugging me. Wouldn't this kind of design be preferable because instead of having one bloated entry-file that all pages unintuitively call the models and views for a specific page are contained, encapsulated, and called from its respective page?
From my experience, having a single-entry point has a couple of notorious advantages:
It eases centralized tasks such as resource loading (connecting to the db or to a memcache server, logging execution times, session handling, etc). If you want to add or remove a centralized task, you just have to change a singe file, which is the index.php.
Parsing the URL in PHP makes the "virtual URL" decoupled from the physical file layout on your webserver. That means that you can easily change your URL system (for example, for SEO purposes, or for site internationalization) without having to actually change the location of your scripts in the server.
However, sometimes having a singe-entry point can be a waste of server resouces. That applies obviously to static content, but also when you have a set of requests that have a very specific purpose and just need a very little set of your resorces (maybe they don't need DB access for instance). Then you should consider having more than one entry point. I have done that for the site I am working on. It has an entry point for all the "standard" dynamic contents and another one for the calls to the public API, which need much less resources and have a completely different URL system.
And a final note: if the site is well-implemented, your index.php doesn't have to become necessarily bloated :)
it is all about being DRY, if you have many php files handling requests you will have duplicated code. That just makes for a maintenance nightmare.
Have a look at the 'main' index page for CakePHP, https://github.com/cakephp/cakephp/blob/master/app/webroot/index.php
no matter how big the app gets, i have never needed to modify that. so how can it get bloated?
When deeplinking directly into the controllers when using an MVC framework it eliminates the possibility of implementing controller plugins or filters, depending on the framework you are using. Having a single point of entry standardizes the bootstrapping of the application and modules and executing previously mentioned plugins before a controller is accessed.
Also Zend Framework uses its own URL rewriting in the form of Routing. In the applications that use Zend Framework I work on have an .htaccess file of maybe 6 lines of rewriterules and conditions.
A single entry point certainly has its advantages, but you can get pretty much the same benefit from a central required file at the top of every single page that handles database connections, sessions, etc. It's not bloated, it conforms to DRY principles (except for that one require line), it seperates logic and presentation and if you change file locations, a simple search and replace will fix it.
I've used both and I can't say one is drastically better or worse for my purposes.
Software engineers are influencing the single point of entry paradigm. "Why not instead just to have the individual pages be the controllers?"
Individual pages are already Controllers, in a sense.
In PHP, there is going to be some boilerplate code that loads for every HTTP request: autoloader require statement (PSR-4), error handler code, sessions, and if you are wise, wrapping the core of your code in a try/catch with Throwable as the top exception to catch. By centralizing code, you only need to make changes in one place!
True, the centralized PHP will use at least one require statement (to load the autoloader code), but even if you have many require statements they will all be in one file, the index.php (not spread out over a galaxy of files on under the document root).
If you are writing code with security in mind, again, you may have certain encoding checks/sanitizing/validating that happens with every request. Using values in $_SERVER or filter_input_array()? Then you might as well centralize that.
The bottom line is this. The more you do on every page, the more you have a good reason to centralize that code.
Note, that this way of thinking leads one down the path of looking at your website as a web application. From the web application perspective, a single point of entry is justifiable because a problem solved once should only need to be modified in one place.

MVC large websites, use one controller...or many?

I have a pretty large site, and I am looking for the most time efficient way to manage it (I am the sole coder).
I am trying to devise a very simple MVC structure (i don't want to use a framework) to help keep all my code in order.
For a huge site, is it better to have only one controller to handle all the pages, or is it better and easier to split them up?
If just one, what is a good example of a non-framework controller?
I would split any logical divisions into different controllers - if it's all static pages, then serve it up with all the same 'static page' controller.
If you have some static pages, a FAQ page (or section), a product list - use a controller for each different section. So the static pages would be pulled from flat files or a database by one controller, the FAQ pages would be generated from a FAQ table by another controller, the products and info would be generated by whatever the source for that is.
Every time the way a page is generated or the data is accessed, use a different controller.
Of course, class inheritance can be used to create the base class with the code needed by any controller.
Not sure what you mean by a non-framework controller - I'd checkout the Zend (gasp) 'Framework', the MVC pattern, and even the controller itself, can be used apart from the rest of the framework.
I tend to split the controllers up based on their responsibility to a specific section of a site/application. This makes maintaining the code so much easier. Furthermore, I group controllers (and views, models) within modules (folders). Here's an example from a current project I'm working on:
Blog
Posts
Comments
Categories
Settings
Posts
Users
The more complex a site, the more modules I use. Although most of my modules only contain one 'Index' controller, I do like the organization they provide.
Then I use a router (front controller) that maps a REST style URI to the proper module / controller / action. Ex: mysite.com/blog/posts/view/7 would call Controller_Posts::view(7) from the "blog" module. An added benefit of using modules is I can have more specific URIs than if I didn't have modules. Although I suppose that could be remedied by using a router that supports defining custom routes, but I'm not too fond of that.
As many other things, it boils down to what you're comfortable with as a developer, but we can probably agree that more organization you have, the better off you are, so long as you don't over complicate things.
As a quick aside, I would recommend you look into using a framework. I understand if you don't want to use one of the ones out there already, as I avoided those too. I ended up writing my own which for the past year has served me very well. It was a great learning experience and it only contains what I want / need. That being said, you might want to look into Kohana and CakePHP - they're not overly bloated IMO and they will definitely save you time should you decide not to write your own.
Typically people split up controllers into controllers focused on specific areas of functionality.
Then they stick a "front-controller" in front of it all, so there's only one entry point to the application. The front-controller's only job is to route incoming requests to the appropriate controller.
Look at the way the Zend_Controller component is set up. It may provide everything you need, and you're free to use it without buying into the complete Zend Framework.
It depends how you other parts will work. If you only have one model file then it's probably not worth splitting up the controller. If you can split up the model into sections as well as the controller, then do that.
However, I often find that there's too much overlap between models to separate them. You might have a model for articles, but if you want to display the top 20 articles in a sidebar on other pages, that code should be in the article model - and you're going to need that on every page.
Honestly though, the only way to do it is try it and see. Start with a single entry point, and if it gets too, unwieldy, refactor it into smaller chunks.
One router/dispatcher, many controllers would be my advice. Controllers ought to map to URLs, which means differing functionality. A controller will collaborate with different services to accomplish each use case, so one controller for your entire app would become too unwieldy if your app has more than a handful of use cases.

How Drupal works? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
Could someone provide a architectural overview of the Drupal 7 control flow? Perhaps in the sense of a flowchart about how a page gets generated. What additional resources would you suggest consulting with regards to how Drupal works?
Drupal can be confusing on this front, partially because it has a relatively deep function stack. Although it's procedural PHP it's purely event/listener driven in its architecture, and there's no simple "flow" in the main PHP script for you to look though. I recently did a presentation on this very subject, and the slides are posted on slideshare, but a quick high-level summary may be useful.
Drupal's index.php file functions as a frontside controller. All page are piped through it, and the "actual" url/path the user requested is passed to index.php as a parameter.
Drupal's path router system (MenuAPI) is used to match the requested path to a given plugin module. That plugin module is responsible for building the "primary content" of the page.
Once the primary page content is built, index.php calls theme('page', $content), which hands off the content to Drupal's theming/skinning system. There, it's wrapped in sidebars/headers/widgets/etc..
The rendered page is then handed back to apache and it gets sent back to the user's browser.
During that entire process, Drupal and third-party plugin modules are firing off events, and listening for them to respond. Drupal calls this the 'hook' system, and it's implemented using function naming conventions. The 'blog' module, for example, can intercept 'user' related by implementing a function named blog_user(). In Drupal parlance, that's called hook_user().
It's a bit clunky, but due to a PHP quirk (it keeps an internal hashtable of all loaded functions), it allows Drupal to quickly check for listeners just by iterating over a list of installed plugins. For each plugin it can call function_exists() on the appropriately named pattern, and call the function if it exists. ("I'm firing the 'login' event. Does 'mymodule_login' function exist? I'll call it. Does 'yourmodule_login' exist? No? How about 'nextmodule_login'?" etc.) Again, a touch clunky but it works pretty well.
Everything that happens in Drupal happens because of one of those events being fired. The MenuAPI only knows about what urls/paths are handled by different plugin modules because it fires the 'menu' event (hook_menu) and gathers up all the metadata plugin modules respond with. ("I'll take care of the url 'news/recent', and here's the function to call when that page needs to be built...") Content only gets saved because Drupal's FormAPI is responsible for building a page, and fires the 'a form was submitted' event for a module to respond to. Hourly maintenance happens because hook_cron() is triggered, and any module with mymodulename_cron() as a function name will have its function called.
Everything else is ultimately just details -- important details, but variations on that theme. index.php is the controller, the menu system determins what the "current page" is, and lots of events get fired in the process of building that page. Plugin modules can hook into those events and change the workflow/supply additional information/etc. That's also part of the reason so many Drupal resources focus on making modules. Without modules, Drupal doesn't actually DO anything other than say, 'Someone asked for a page! Does it exist? No? OK, I'll serve up a 404.'
To understand how Drupal works, you need to understand Drupal's page serving mechanism.
In short, all the calls/urls/requests are served by index.php which loads Drupal by including various include files/modules and then calling the appropriate function, defined in module, to serve the request/url.
Here is the extract from the book, Pro Drupal Development, which explains the Drupal's bootstrap process,
The Bootstrap Process
Drupal bootstraps itself on every request by going through a series of bootstrap phases. These phases are defined in bootstrap.inc and proceed as described in the following sections.
Initialize Configuration
This phase populates Drupal’s internal configuration array and establishes the base URL
($base_url) of the site. The settings.php file is parsed via include_once(), and any variable or string overrides established there are applied. See the “Variable Overrides” and “String Overrides” sections of the file sites/all/default/default.settings.php for details.
Early Page Cache
In situations requiring a high level of scalability, a caching system may need to be
invoked before a database connection is even attempted. The early page cache phase lets
you include (with include()) a PHP file containing a function called page_cache_
fastpath(), which takes over and returns content to the browser. The early page cache
is enabled by setting the page_cache_fastpath variable to TRUE, and the file to be included
is defined by setting the cache_inc variable to the file’s path. See the chapter on caching
for an example.
Initialize Database
During the database phase, the type of database is determined, and an initial connection is
made that will be used for database queries.
Hostname/IP-Based Access Control
Drupal allows the banning of hosts on a per-hostname/IP address basis. In the access control
phase, a quick check is made to see if the request is coming from a banned host; if so,
access is denied.
Initialize Session Handling
Drupal takes advantage of PHP’s built-in session handling but overrides some of the handlers
with its own to implement database-backed session handling. Sessions are initialized
or reestablished in the session phase. The global $user object representing the current user
is also initialized here, though for efficiency not all properties are available (they are added by an explicit call to the user_load() function when needed).
Late Page Cache
In the late page cache phase, Drupal loads enough supporting code to determine whether or
not to serve a page from the page cache. This includes merging settings from the database into the array that was created during the initialize configuration phase and loading or parsing module code. If the session indicates that the request was issued by an anonymous user and page caching is enabled, the page is returned from the cache and execution stops.
Language Determination
At the language determination phase, Drupal’s multilingual support is initialized and a decision is made as to which language will be used to serve the current page based on site and user settings. Drupal supports several alternatives for determining language support, such as path prefix and domain-level language negotiation.
Path
At the path phase, code that handles paths and path aliasing is loaded. This phase enables
human-readable URLs to be resolved and handles internal Drupal path caching and
lookups.
Full
This phase completes the bootstrap process by loading a library of common functions, theme
support, and support for callback mapping, file handling, Unicode, PHP image toolkits, form
creation and processing, mail handling, automatically sortable tables, and result set paging. Drupal’s custom error handler is set, and all enabled modules are loaded. Finally, Drupal fires the init hook, so that modules have an opportunity to be notified before official processing of the request begins.
Once Drupal has completed bootstrapping, all components of the framework are available.
It is time to take the browser’s request and hand it off to the PHP function that will
handle it. The mapping between URLs and functions that handle them is accomplished using
a callback registry that takes care of both URL mapping and access control. Modules register
their callbacks using the menu hook (for more details, see Chapter 4).
When Drupal has determined that there exists a callback to which the URL of the browser
request successfully maps and that the user has permission to access that callback, control is handed to the callback function.
Processing a Request
The callback function does whatever work is required to process and accumulate data needed to fulfill the request. For example, if a request for content such as http://example.com/
q=node/3 is received, the URL is mapped to the function node_page_view() in node.module.
Further processing will retrieve the data for that node from the database and put it into a data structure. Then, it’s time for theming.
Theming the Data
Theming involves transforming the data that has been retrieved, manipulated, or created
into HTML (or XML or other output format). Drupal will use the theme the administrator
has selected to give the web page the correct look and feel. The resulting output is then sent to the web browser (or other HTTP client).
Eaton's answer provides a good overview. (I'm new here so I can't mod him up, thus the comment.)
The brutal "aha" moment for me was realizing everything happens through index.php, and then through the waterfall of modules (core first, then by site). To extend core functionality don't rewrite it. Instead copy the module into /sites/all/modules/ or /sites/[yoursite]/modules and extend THAT, or create a new module in those places. Same for themes. Module directories can contain display code as well, in the form of tpl, css etc.
If you're used to stricter MVC type frameworks like Rails, Django etc. all this gets a little confusing. Modules can mix in a lot of display code, and if you're looking at someone else's modules or templates you'll eventually wind up walking backwards through the stack. That's the beauty/pain of working in PHP.
Ironically, "just build an app" might be the worst way to learn this. Drupal does so much out of the box that's simply obscure until you figure out the control flow. There's nothing in a tpl file that tells you where a function with a fun name like l() comes from, for example.
It depends on how deep an understanding you're looking for; if you have a good knowledge of php, I would suggest reading through the code itself, starting with index.php, and then going on to the includes/bootstrap.inc, and then some of the other scripts in that directory.
The key include files:
menu.inc is very important to understanding how the overall system works, as it handles a lot of the implicit mapping of URLs to content.
common.inc has most of the otherwise-mysterious functions that form the basis of the API.
module.inc handles the hook invocations that Eaton mentioned
form.inc deals with form display, submission and processing
theme.inc handles presentation.
There's also some key functionality in the modules/ directory; in particular, modules/node/node.module forms the basis of the node system, which is in general what's used to encapsulate site content.
The code is, in general, very well-commented and clear. The use of Doxygen markup within the commenting means that the code effectively is the canonical documentation.
It also helps to do this using an editor that can quickly jump to the definition of a function. Using vim in combination with ctags works for me; you do have to tell ctags to index .inc, .module, etc. files as php files.
This (for Drupal 6) & this (for Drupal 7) is a pretty good architectural overview of drupal. If you want more detail then I would start writing something most of the documentation is good. Trying to learn it at a high level of detail without something concrete to achieve will be much more difficult that trying something out.
I learned loads by importing the drupal .php code into a NetBeans project.
You can then run the netbeans debugger and watch the different phases of the page come together.
The best books on the subject are "Pro Drupal Development" and "Using Drupal."
"Pro Drupal Development" includes several nice flowcharts and thorough summaries of each of Drupal's APIs (forms, theming, etc.). It's intended to be especially instructive to people making their own modules and themes, but has lots of value to the average PHP-savvy developer who wants to understand Drupal. Besides which, I've created a custom module for every site I've built, just to gain the extra control over things like selectively hiding fields on various forms (which you generally want to do for the sake of simplifying node forms for end-users), so it's good to have this knowledge under your hat.
"Using Drupal" is aimed at the site developer who wants to know how to build the good stuff like galleries, blogs, and social networking sites. It goes through several use-cases and shows how to configure existing modules to do each job. In the process it familiarizes you with the essential add-on modules "Content Construction Kit" (CCK) and "Views," how to make custom blocks and templates, and the ins-and-outs of maintaining a Drupal site. I recommend this book especially for those who want to get up to speed and actually USE Drupal right away. In the process you gain an understanding of the internal organization of Drupal.
New contributor here, 2 years late on the conversation ;-)
Replying to https://stackoverflow.com/a/1070325/1154755
To extend core functionality don't rewrite it. Instead copy the module
into /sites/all/modules/ or /sites/[yoursite]/modules and extend
THAT, or create a new module in those places. Same for themes.
Actually, I never had to copy a core module to update it. Drupal Hooks should be all you need.
For themes, yeah, sometimes it's the only way to go, but often, you can build a subtheme to get the result you need.

Categories