Page 2 of 9
Posted: Tue Apr 10, 2007 7:32 pm
by Christopher
As for fluent interfaces, it sounds like there is general agreement to use them were it makes sense. I would like to see some benchmarks, especially for something like the Front Controller in index.php that is called every request. I am fine with what ever style you guys like best.
Maugrim_The_Reaper wrote:Zend_Config allows division of a single config file - easy enough to categorise configuration categories. The development vs production difference is slightly different - one is defunct and even a little dangerous if allowed in production. Admittedly I'm a fan of ant and Phing so you can guess my answer involves dual files, one with the notorious .dist extension part, the other being deleted before being pushed to a production server. Outside that - separate files and manual replacement should be enough. Plus a sprinkling of hard-coded controls to prevent errors (triggered by the production server's IP perhaps).
This raises the question of whether ant or phing should be used as part of this project. I don't use them, but if shown the advantages I will jump on board. It may be too complex for a basic example -- perhaps we could show examples of plain and with phing sauce.
Maugrim_The_Reaper wrote:Zend_Config doesn't care whether the file is PHP, INI or XML. YAML support is outstanding (I'm pushing for it). Someone benchmarked which was faster recently - I'll try digging up the reference. INI is the simplest though. I'd start as simple as possible - let it evolve as needed and we can re-visit a cleaner method if required.
I'd be interested to see the benchmarks. I don't think simplest is necessarily best. I think we want something that follows a clear convention, and is flexible and powerful enough. Maybe our simplest case is not the simplest implementation, but it should be clear what is going on and you can do anything you want config wise.
Maugrim_The_Reaper wrote:Path to config files? I prefer convention where possible for a single Path. Easier for Phing to work it's magic

. In general I always prefer convention and automation to most other options for these decisions - I know "building" PHP sounds OTT, but it's a simple exercise in defining what's supposed to happen to turn subversion tags into production ready code, automating those steps, using the automation to integrate frequently (testing) and continuing to celebrate your obvious laziness as a programmer

. A basic Phing config file is only a few lines long for a config replacement/renaming task.
I think the reason I asked is that there was an example of selecting config by IP address. That is outside the capabilities of the Zend Confg system. As is doing things other things, that's why I suggested using a PHP file rather than one of the data file formats. It also means you only need to load Zend_Config rather than the other config classes. And you could always load a data file from the config.php. It also means that there would probably be a config var that could be accessed directly in index.php -- rather than the overhead of fetching back from a config object. I am just trying to get to a solution that is performant, works in the most cases, and is easy to understand.
The same idea goes for where the bootstrap config file lives. If it is outside the application directory that may make code updates easier. I'm just trying to find a solution that follows a straightforward convention, is flexible, and allows as much config information as possible to be bootstrapped for use in index.php and beyond.
Posted: Tue Apr 10, 2007 11:40 pm
by dreamscape
arborint wrote:The same idea goes for where the bootstrap config file lives. If it is outside the application directory that may make code updates easier. I'm just trying to find a solution that follows a straightforward convention, is flexible, and allows as much config information as possible to be bootstrapped for use in index.php and beyond.
What I've been doing for awhile is to place the main config *somewhere* outside of the application. It doesn't matter where exactly as long as it is located in a higher directory. The leaves it open for a degree of flexibility on location (setting it just one level out may leave an non PHP config file open for public browsing on certain setups) without too much overhead, as you simply ascend the directory structure until you reach the root level of the system or have located the config, whichever comes first.
I use this function in all the index.php sort of front ends to locate the app config... just an idea:
Code: Select all
/**
* Locate application config file
*/
function find_app_config($configFile = 'app_config.php', $directory = false)
{
if ($directory === false)
{
$directory = dirname(__FILE__);
}
/**
* supress errors; we don't know what we might hit that could throw a warning,
* but we're just searching for a certain file.
*/
if (@file_exists($directory . DIRECTORY_SEPARATOR . $configFile) === true)
{
return $directory . DIRECTORY_SEPARATOR . $configFile;
}
//! reached root level. stop here and throw exception
if ($directory === DIRECTORY_SEPARATOR)
{
throw new Exception(
'Unable to locate the application configuration file, ' . $configFile
);
}
return find_app_config($configFile, realpath($directory . DIRECTORY_SEPARATOR . '..'));
}
Posted: Tue Apr 10, 2007 11:53 pm
by dreamscape
I also wanted to add, that if choosing a "deployment" or "config" based on the site being accessed, I personally prefer to base it on HTTP HOST rather than IP address, as this allows having different "setups" for different subdomains using a single base install of the application. The only way to do that basing it on IP address would be to have a dedicated IP for each subdomain.
Posted: Wed Apr 11, 2007 12:44 am
by Christopher
Well it is interesting that you use both a PHP config file and put it outside the application directory.
As I understand it your function it searches the directory of the current script and if not found it then searches up until found. How often do you have the config file in a different directory that the current directory?
So some bootstraps using a PHP file (data files would work the same):
Code: Select all
// Maugrim's defined path
$applicationPath = '/path/to/application/directory';
require $applicationPath . '/config.php';
$config = new Zend_Config($configArray);
// dreamscape's search for file
require find_app_config('config.php');
$config = new Zend_Config($configArray);
// simplest convention
require 'config.php';
$config = new Zend_Config($configArray);
Following
sikes code and your comment, a PHP config file could look like this for IP based configuration:
Code: Select all
switch($_SERVER['HTTP_HOST'])
{
case 'client.com':
$configArray = arrray(
// config values here
);
break;
case 'staging.client.com':
$configArray = arrray(
// config values here
);
break;
default:
$configArray = arrray(
// dev config values here
);
break;
}
Or you could break the config into sections like this:
Code: Select all
$configArray = arrray(
'live' => array(
// config values here
),
'staging' => array(
// config values here
),
'dev' => array(
// config values here
),
);
// and do this in index.php:
$config = new Zend_Config($configArray['staging']);
Though we still have not really resolved whether to use a PHP file or a text file for configuration.
Posted: Wed Apr 11, 2007 3:10 am
by Ollie Saunders
HTTP_HOST is the way to go. I've used this function in the past
Code: Select all
function initializeEnvironment(array $devMachines, $errorReporting = null)
{
if ($errorReporting === null) {
$errorReporting = E_ALL | E_STRICT;
}
$isDevelopment = in_array($_SERVER['HTTP_HOST'], $devMachines, true);
// These are the settings people should be using
ini_set('display_errors', $isDevelopment);
ini_set('log_errors', !$isDevelopment);
if ($isDevelopment) {
error_reporting($errorReporting);
ini_set('error_prepend_string', '<div style="font-size:9pt;border:1px '
. 'solid #a00;margin:4px;padding:4px;color:#a00;background:#fff5f5;'
. 'font-family:Trebuchet MS,Arial,Tahoma">');
ini_set('error_append_string', '</div>');
ini_set('docref_root', 'http://uk2.php.net/manual/en/');
ini_set('docref_ext', '.php');
}
return $isDevelopment;
}
$_ENV['IS_DEV'] = initializeEnvironment(array('192.168.0.2', 'nitrogen.dev'));
I'm just trying to find a solution that follows a straightforward convention, is flexible, and allows as much config information as possible
Why do you need something so flexible if we are going to practise convention or configuration. Other than database credentials and a few flags what else do we need?
Posted: Wed Apr 11, 2007 6:15 am
by dreamscape
arborint wrote:Well it is interesting that you use both a PHP config file and put it outside the application directory.
Actually, I don't use PHP for the config files, but just name the file "app_config.php" by default in the code as example.
Posted: Wed Apr 11, 2007 7:32 am
by Maugrim_The_Reaper
I would go with either INI or XML - both are textual, and a bit simpler than PHP's format. The goal of a configuration file should include being Human readable and editable, over being a specific language format. XML should be reserved for cases where nesting is required. That said, the format has little bearing on the data content - we should just select the easiest to implement until a clear motivation for any one option is more obvious - sort of viewing the big picture as constantly evolving towards a final best practice.
I also think working from a Phing point of view - even without mentioning it explicitly, is a good place to occupy. The problem I have with identifying a production server openly is that we're tying the application in too close to it's environment. The Zend Framework manual has a "staging" example I simply don't agree with too - DB credentials of one server should not be located in another. It's not that it's insecure per se - but it does increase security risk to one server unnecessarily. Why should I put my development environment credentials on the production server? Who says I only have one development environment anyway? I could be testing the same subversion export across a few virtualised environments or physical servers nobody is aware of.
The simplest solution is manual intervention - you just replace the configuration file.
The automation of the simplest solution is a tiny Phing task. Now, I agree Phing should not get mentioned at this stage (if ever in any detail) except in passing. But we shouldn't ignore the fact a build tool solves the problem without much difficulty or effort - I know PHP is behind the curve in some respects, but build tools are common place in other languages and essential for a number of practices. Ruby and RoR are jam-packed with them in comparison to PHP/ZF.
</rant> Sometimes my typing runs away with it...

.
Why do you need something so flexible if we are going to practise convention or configuration. Other than database credentials and a few flags what else do we need?
In a large application there could be more than a few configuration files. In the ZF, the common ones cover environment setup, database credentials, and controller routes. You could invent others depending on the application - e.g. caching setup for various needs. Convention removes a lot of the dead weight - but a lot of things still need defining, especially if they differ between dev/prod servers.
Code: Select all
// Maugrim's defined path
$applicationPath = '/path/to/application/directory';
Eeek

. Would be better to ignore that one, and use a configuration value. The path needs to be defined outside the application bootstrap - otherwise it's just another environment tie in. I really should have put that after the config loading stage...
Posted: Wed Apr 11, 2007 9:28 am
by Chris Corbyn
Did you guys ever get a subversion repository up like Maugrim sugested?
http://www.w3style.co.uk/devnet-projects/pet-store/ (Open-access for now)
Posted: Wed Apr 11, 2007 10:40 am
by Maugrim_The_Reaper
Code: Select all
/application
/config
/controllers
/models
/views
/filters
/helpers
/scripts
/Zend
/document_root
/images
/scripts
/styles
.htaccess
index.php
Back to the directory structure for a moment. Reason I added separate /user and /library directories previously was for categorisation. /user (pick another name even) holds all controllers/models/views. The other reason for /user was to separate controllers/models/views from other code - esp. given the modularisation approaches now possible in defining Module specific, and Default contollers for any given route.
In thinking about this I think a lot of the original recommendations in the ZF documentation are really only suitable for very small apps. What's above fits for a small non-modularised app - like this sample application to an extent.
In something more complex it's going to be necessary to categorise more though. Requiring a longer filesystem structure. A quick stab from me:
Code: Select all
/application ... Root directory
/library ... Parent directory for all libraries
/Zend ... Zend Framework library
/OtherPHPLibrary ... Other required PHP libraries
/extends ... Zend Framework subclasses and overloaded components
/config ... Configuration files
/data ... Non-configuration data including audit logs, cron dumps, other
/temp ... Potential temporary files including caches
/default ... Default controllers, models and views
/controllers ... Default controllers
/models ... Default Models
/views ... Assumed default Views (modularised view undocumented)
/filters
/helpers
/scripts
/module1 ... Application Module 1 (e.g. Admin mini-app)
/same_as_for_default
/module2 ... Application Module 2 (e.g. Blog Entry CRUD mini-app)
/same_as_for_default
/application.php ... index.php bootstrap source code (included by index.php)
Code: Select all
/document_root
/.htaccess ... Apache .htaccess (mod_rewrite setup and conditionals)
/index.php ... Index file (includes /path/to/application/application.php)
and handles other possible wrapping functions
/images
/scripts
/styles
The above adds some new items - Module directories (to assemble MVC groups of potentially re-useable modularised code), an "extends" directory to hold Zend Framework subclasses, overloads, and similar, and some writeable directories for caches, logs, and other stuff a larger application might conceivably also need.
Sidenote - going by ZF modularisation style, such a layout with numerous modules would quickly grow the filesystem. Not a pleasant thought but might be a necessary evil without the default module-controller lookup behaviour being overloaded.
Posted: Wed Apr 11, 2007 10:46 am
by Maugrim_The_Reaper
Did you guys ever get a subversion repository up like Maugrim sugested?
Not yet - still debating the bootstrap basics

. We will need one with public checkout/export access, and private write access. If you don't mind catering for the odd new account as other's want to contribute code I'd accept your offer - assuming arborint is agreeable.
Posted: Wed Apr 11, 2007 11:15 am
by Maugrim_The_Reaper
Since I have fat fingers from typing so much anyway - I decided to open a Wiki section somewhere so I don't spout too much unrelated stuff here

. That, and documenting the process into an organised tutorial. Wiki is the PFP site - so accounts are easily obtained for those wishing to randomly contribute as they wish. Initial aim is a haphazard unfocused collection of material - can be consolidated later into a tighter text and put somewhere as the pride and joy of the tutorials forum...

.
http://www.patternsforphp.com/wiki/ZF_Petshop_Demo
I might use this for now to put suggest requirements and other introductory material not needed to be pounded across two pages of forum posts...
Posted: Wed Apr 11, 2007 1:45 pm
by Chris Corbyn
Maugrim_The_Reaper wrote:Did you guys ever get a subversion repository up like Maugrim sugested?
Not yet - still debating the bootstrap basics

. We will need one with public checkout/export access, and private write access. If you don't mind catering for the odd new account as other's want to contribute code I'd accept your offer - assuming arborint is agreeable.
Yeah I can do that

Posted: Wed Apr 11, 2007 10:58 pm
by Christopher
ole wrote:I'm just trying to find a solution that follows a straightforward convention, is flexible, and allows as much config information as possible
Why do you need something so flexible if we are going to practise convention or configuration. Other than database credentials and a few flags what else do we need?
I am assuming that if we come up with several possible conventions, all equally clear/simple, then we would pick the one that provides the most flexibility and power.
Posted: Wed Apr 11, 2007 11:18 pm
by Christopher
Maugrim_The_Reaper wrote:I would go with either INI or XML - both are textual, and a bit simpler than PHP's format. The goal of a configuration file should include being Human readable and editable, over being a specific language format. XML should be reserved for cases where nesting is required. That said, the format has little bearing on the data content - we should just select the easiest to implement until a clear motivation for any one option is more obvious - sort of viewing the big picture as constantly evolving towards a final best practice.
The simplest solution is manual intervention - you just replace the configuration file.
I think I confused the issue as there are two. I think we should be free to use any kind of supported file type and the convention. My main question is what convention(s) we should establish as to were to put the config file(s).
In reading you post on directory structure, you now have another file that is included by index.php called application.php. I am getting confused on what is the purpose of multiple files. It seem like this issue of what to separate has to do with what gets updated. I have found from experience that the index.php file rarely gets changed, but the files in the application directory get changed frequently.
Maugrim_The_Reaper wrote:The automation of the simplest solution is a tiny Phing task. Now, I agree Phing should not get mentioned at this stage (if ever in any detail) except in passing. But we shouldn't ignore the fact a build tool solves the problem without much difficulty or effort - I know PHP is behind the curve in some respects, but build tools are common place in other languages and essential for a number of practices. Ruby and RoR are jam-packed with them in comparison to PHP/ZF.
I would rather not use a build tool, but we should get some sense of what others want. Is there a way for us to define with and without configurations?
Maugrim_The_Reaper wrote:Eeek

. Would be better to ignore that one, and use a configuration value. The path needs to be defined outside the application bootstrap - otherwise it's just another environment tie in. I really should have put that after the config loading stage...
That gets to my essential question -- how do we find the config file when we want all the paths in the config file?
Posted: Thu Apr 12, 2007 2:47 am
by Maugrim_The_Reaper
That gets to my essential question -- how do we find the config file when we want all the paths in the config file?
Manual labour. There really isn't any other way around it - unless all the files are located under the webroot then presumably the user has placed them below the webroot somewhere - given the variability across shared hosts, dedicated servers and development environments in terms of where the webroot is, and how it's managed, then that could be a number of places. If it's not by convention - e.g. just below the webroot (in which case it's a simple deduction of "dirname(__FILE__)" minus the relative REQUEST_URI path in index.php) - then the user selected it, and should update the configuration file for it - of course where is that particular config file?
Assuming all other configuration files can't be found without the path (where I think the main point is) then it's either a line in the index.php file (my original setup), or a relative path location the index.php file can access without guessing and the user has updated by some mechanism (install tool, manual edit, build parameter).
In reading you post on directory structure, you now have another file that is included by index.php called application.php. I am getting confused on what is the purpose of multiple files. It seem like this issue of what to separate has to do with what gets updated. I have found from experience that the index.php file rarely gets changed, but the files in the application directory get changed frequently.
I was thinking about this - why do we have the bootstrap in one location, and the application files in another? It would be more consistent for index.php to be nothing more than a shell. It's sole purpose is to become aware of the location of the "application" directory, and include application.php (or maybe bootstrap.php is clearer) which has all the normal bootstrap code. I know it sounds a bit gimmicky but it would make updating simpler having everything in one place. It's as simple as:
Code: Select all
<?php
/**
* Index.php file
*/
include '/path/to/application/application.php';
You can see here why a config file for one single path is likely overkill in this scenario - index.php now only has one variable. The rest can be accessed by application/bootstrap.php using relative paths and the normal include_path settings. An install tool or plain old editing can set this up - it's not overkill editing index.php for the path. Everything else that's variable can then reside in config files as usual.