When using dependency injection for database handlers etc instead of singleton - where is it best to keep the configs I.e. Username password host etc. Keep inside the class, use a container class or use a static configs class or use a file?
I generally keep them in a file outside of the webroot.
External config file that returns an array is a quick solution:
config.php:
<?php
return array(
'database'=> array(
'host'=> 'localhost',
'dbname'=> 'name_of_db',
'username'=> 'myusername',
'password'=> 'mypassword',
),
);
test.php:
<?php
$config = include('config.php');
mysql_connect($config['database']['host'], $config['database']['username'], $config['database']['password']);
....
Ideally, store the config file in a directory that can be read by the anonymous web user (but not written).
This is difficult to get 'right' because it depends on the exact use-case. But here's what I did when I had a very similar problem.
I had setup a shared library system for a small number of websites. Initially, it provided just a database handler, but there was quickly added an ORM layer. Most of the growth after that was additional objects as one of the websites was rewritten away from direct SQL into object-based access. There was also a configuration library used to define how the objects and other elements in the shared library were collected together into 'modules' as well as default settings for things like database settings. It also supported loading a configuration file outside the code-tree, which was used to per-host settings.
Since the objects in the ORM layer had to configure themselves (there was a static call to do that as they were declared), it was trivial for it to be extended to request a particular database by name, too. Then it was a matter of making sure that all these database definitions were declared as well (and were overridable thanks to the generic configuration mechanism).
(It took a while, but when we did reach the point of having to split the database, it was very easy to point the relevant objects off to another database and everything just kept working.)
To answer your question, though: the configuration was split. Database hostnames, usernames and passwords were all named and defined in one place in the in-code configuration area. But they could be overridden on a per-host basis. Per object settings were where the objects were declared. And that was also where the database configurations were specified by name.
Related
In Zend Framework 2 I wrote a module with custom configuration options.
The options are obtained using the service locator and are then passed to the object that is being initialized inside a factory.
Since my configuration is in PHP array format, I could just pass the array, or I could first create a new instance of Zend\Config\Config and pass this to the new object.
I tried both ways & they both work, but what is the recommended way of doing this inside ZF2 & why? Does it has any advantages to use Zend\Config\Config?
Especially since I just noted it's possible to cast the Config back to an array using toArray() I am curious of possible benefits.
By using the object you would be keeping with the OOP inherent to Zend, plus it has functionality not available to a basic array, and it can be extended to use custom business logic if the need arises.
IE, maybe a condition comes up that will change one of the configuration options, but the rest are the same.
If I'm developing a project for others, I like to give them a certain level of access to the configuration so that they do not have any reason to delve into the code themselves. I'll create a table in the database called something like 'settings' or 'config' that the admin can access through a form, and the data populates a php configuration array. In order to do this, the PHP array format is the way to go.
("a" recommendation, not necessarily "the" recommended way)
Most of the modules just add to the global config, that is accessible via $serviceManager->get('config')
This way your config can be cached later on via config_cache_enabled in application.config.php and users can override config options using their local configurations.
If your's module config isn't related to the global config mechanism it's really up to you on how you store/manage it. Keeping it as an array is simpler, whereas using it as Zend\Config\Config lets you use various tools for config (ini writers, database etc).
In my application I have my constants:
define('APP_PATH', WEB_ROOT . APP_DIR);
define('LIBS_PATH', APP_PATH . LIBS_DIR);
define('MODELS_PATH', APP_PATH . MODELS_DIR);
define('VIEWS_PATH', APP_PATH . VIEWS_DIR);
define('CONTROLLERS_PATH', APP_PATH . CONTROLLERS_DIR);
etc...
because they will never be changing once my application starts and they are simple to access from within any class/method.
I have a config file too with other settings which gets imported into a $config object that I pass around my application and retrieve them like:
$this->config->setting('some.setting');
I have never had to change a config value at the end or in the middle of my application so wouldn't it be easier to just define them as constants so I can access them anyway in my code easily?
I don't want to be statically retrieving settings either i.e
Config::setting('some.setting');
I have looked at the code of a few PHP frameworks and they all define paths as constants but then have other config settings in some sort of Config class even though as far as I can see they never change those config settings throughout the code (they might though as I have not read through every line of the tens of thousands) and lots of those frameworks seem to love doing static calls to all sorts of methods from within methods in different classes and people say they are good frameworks but I've read and experienced more bad than good when it comes to static calls within classes/methods.
What do you think is best to do with the config settings? What do you do?
Wrapping constants in objects makes your code more portable.
This way you can load constants at application bootstrap from a file for example, so you can reuse your code in an arbitrary number of apps, each with a different configuration file.
To another extent, loading stuff from a class acts as a façade: you can move settings from a file to a database, to hardcoding them even, and the whole application won't notice.
You can go with define for very little projects of course.
Wrapping settings in a config object provides encapsulation, which allows better coexistence.
For instance, suppose you have a framework for database access. If you used global settings for this, you couldn't easily access multiple databases in a single program. Putting the settings into an object allows you to use a particular config object for the corresponding database.
How is it possible to provide global information (paths, DB passwords, Timezone, ...) in a PHP Application? I know, that global variables are unsafe, but how do common CMS handle this problem? I already looked at Wordpress, but WP isn't famous for it's high security standards.
I've read a little bit about Dependency Injection, but is this the common way to handle this?
All in all I want to provide a type of global (but controlled*) information.
*Is it possible to control the provided data in a way that only authorized objects get the required information?
You can use configuration files (.ini), it's easy to use with this PHP function parse_ini_file.
You can use it like that :
config.ini
[global-information]
path : your_path
DB_passwords : your_password
Timezone : your_timezone
In your php file you can get global information like that
$ini_array= parse_ini_file("config.ini",true);
$path = $ini_array['global-information']['path'];
Dependency injection has nothing to do with security. It is a design pattern, a strategy to solve a common problem in a well-structure way.
I typically prepare a class CSettings, which provides method for all types of information, but all in a generic way by means of methods.
Then, when used in a specific application, I subclass CSettings in such a way, that it returns the correct / concrete values for the specific application.
Another way to promote information, could be e.g. the registry pattern.
There are many schools of thought on this. The most basic implementation is probably a global configuration file that sets constants using define()
I once worked with a framework that used this method extensively, coupled with singletons for Database Access and domain settings. It is still widely used, but generally deeper dependency injection, where definitions for configuration are made class specific is now considered more modern and reusable, since the single package contains all the definitions to make it work in the same file.
http://misko.hevery.com/2009/01/14/when-to-use-dependency-injection/
This is a great article about the finer points of dependency injection. The key thing to remember is that objects should only instantiate or hand off other objects if they are directly needed within the current scope. The author gets in to great detail.
There are also alot of more famous libraries like HTMLPurifier that use a configuration object that gets handed to the constructor of the object instance when it is created. This is a good approach if your object has highly complicated and nested config.
I'm writing my first basic bare bones MVC patterns setup in PHP. I know global variables are bad, and I aslo know I don't want all of my classes to have access to all of my config vars.
I have a settings.php file that I would like to define a bunch of constants in, like my db connection info, directory structure info, email addresses and so on. It will be one centralized location that holds all of my important information.
What's the best way to implement a config class so that each of my base classes for my controller and model only have access to the config vars they need? For example, my model base class should have access to by db connection info.
Basically I am just asking how anybody whole rolls their own MVC setup handles config information without declaring global variables, like we used to back in the procedural days.
Thanks.
You're going to get a bunch of answers on this as it basically boils down to preference.
Personally, ive used a config array. example:
$conf['db']['username'] = "username";
$conf['db']['password'] = "password";
Then just pass byref the pieces you need into where they need to go.
I rolled my own MVC setup. (Still going strong. Might open source it). The way I do it is to have an init script that passes all those constants to a controlling class.
The controlling class is a Singleton. So anytime another class needs access to it, it just gets the existing instance of the controlling class and all the variables are available from it.
Background
I need to design a set of utility classes that will ease out file system access to several types of remote services (Local, FTP, WebDAV, SVN, SSH), and I cannot seem to get a "perfect" design mostly because of a language barrier - I feel that every design path I have chosen was scraped because PHP did not have support for a specific feature.
I find this frustrating and I'm out of ideas.
Requirements
A base abstract class or interface for FileSystem which every other file system type inherits. The FileSystem class (and it's subclasses) are a 'driver' that implement basic FS operations such as 'move', 'remove', 'create' and so on.
Those driver operations should not be exposed to the class user, instead, FileSystem is also a factory that fetches file info records upon request.
A file is also based on an abstract class or interface File and Directory, which the implementors of a FileSystem subclass may or may not subclass. Users of a FileSystem class do not 'care' about the type of a File (SshFile and SvnFile should work the same).
The File (and Directory) class should be the one to talk to the file system driver that created it in some way without the user being able to do it manually through the FileSystem driver.
What I have tried
Naturally I made FileSystem an abstract class, then proceeded to code the class File and turns out that PHP has no friend support, so File cannot have access to FileSystem's protected driver methods.
Another idea that got scraped was a class inside a class - FileSystem and FileSystem::File - PHP does not have nested classes.
Divide FileSystem into FileSystemDriver and FileSystemFactory, but that gets me into the same original problem.
300 Reputation points in bounty reward
To a solver of an original idea to PHP's lack of programming utilities needed for encapsulation.
Why can't you separate FileSystemDriver from FileSystem? For example:
class SSHFileSystem {
private $driver = new SSHDriver();
function getFile($path)
{
return new SSHFile($this->driver, $path);
}
}
Documentation problem, not code problem.
Leave the FileSystem's methods as public but document that they should only be used by internal File and Directory objects.
This is very common in languages. Python has magic methods, or the _function notation, etc.
If I'm a user, I don't just look at every available method and start using it if it sounds fun, I read the docs and do what they say.