Module based application.ini in Zend Framework - zend-framework

I want to have module based application.ini in my application.
Is it possible?
Basic requirement arises because I am having multiple databases depending on modules.
Please guide.

You can use multiple Db in application.ini:
resources.db.master.adapter = "PDO_MYSQL"
resources.db.master.default = false
resources.db.master.params.dbname = "db1"
resources.db.master.params.host = "127.0.0.1"
resources.db.master.params.username = "root"
resources.db.master.params.password = ""
resources.db.slave.adapter = "PDO_MYSQL"
resources.db.slave.default = true
resources.db.slave.params.dbname = "db2"
resources.db.slave.params.host = "127.0.0.1"
resources.db.slave.params.username = "root"
resources.db.slave.params.password = ""
And initialize in your bootstrap:
public function _initDatabase() {
$config = $this->getApplication()->getOption('resources');
$dbArrays = array();
foreach($config['db'] as $name => $dbConf){
// Set up database
$db = Zend_Db::factory($dbConf['adapter'], $dbConf['params']);
$db->query("SET NAMES 'utf8'");
$dbArrays[$name] = $db;
if((boolean)$dbConf['default']){
Zend_Db_Table::setDefaultAdapter($db);
}
unset($db);
}
Zend_Registry::set("db", $dbArrays);
}
In my case I always save each adapter in the registry so I can use them separately later.
I also made a new class which extend Zend_Db_table where I have My own getAdapter($name) like so:
public function getAdapter($name = null){
if($name !== null){
$dbAdapters = Zend_Registry::get('db');
return $dbAdapters[$name];
}
return parent::getAdapter();
}
With that in each model I can do:
$this->getAdapter('slave')->fecthAll($sql);
$this->getAdapter('master')->fecthAll($sql);

The application.ini is read long before the module is determined. I'd suggest you forget about application.ini and instead try and write a controller plugin that will load in some additional configuration depending on which module was selected.

Related

ZF2 best practice for loading modules dynamically

I'm trying to create a service, that helps the user to loading modules dynamically from system administration panel. That is my code:
if(!$this->isModuleInstalled($moduleName)) {
$appConfigService = $this->getServiceManager()->get('ApplicationConfig');
$appConfig = new Config($appConfigService, true);
$modules = $config->modules->toArray();
end($modules);
$nextModuleKey = (key($modules) + 1);
unset($modules);
$config->modules->{$nextModuleKey} = $moduleName;
$writter = new Writer\PhpArray();
$writter->toFile(
__DIR__ . '/../../../../../config/application.config.php',
$config->toArray()
);
}
I think that is not the best practice for loading modules dynamically.
Try this
$configuration = $serviceManager->get('ApplicationConfig');
$configuration['modules'][] = 'ModuleName';
$serviceManager->setService('ApplicationConfig', $configuration);
$serviceManager->get('ModuleManager')->loadModules();

How to use extensions in Zend Framework Routing

I'd like to use an extension like .htm in my URLs. Is there a way to accomplish that?
I've defined the following rule:
frontend.route = '/:standort/:id'
When I use the following
frontend.route = '/:standort/:id.htm'
then the name of the variable is id.htm like in $params["id.htm"].
How can I tell the Zend Framework what to use as variables?
Greetings
//Edit
my full config looks like this now:
frontend.type = 'Zend_Controller_Router_Route_Regex'
frontend.route = '/(.?)/(\w+?\.htm)'
frontend.defaults.module = 'frontend'
frontend.defaults.controller = 'index'
frontend.defaults.action = 'index'
frontend.defaults.standort = 'national'
frontend.map.1 = 'standort'
frontend.map.2 = 'id'
this is how I load the config
$file = APPLICATION_PATH . '/modules/' . $module . '/configs/routing.ini';
if(Zend_Loader::isReadable($file)){
$config = new Zend_Config_Ini($file);
$router = Zend_Controller_Front::getInstance()->getRouter();
$router->addConfig($config);
}
You can do this with regex routes:
frontend.type = "Zend_Controller_Router_Route_Regex"
frontend.route = '/(.?)/(\w+?\.htm)'
frontend.map.1 = "standort"
frontend.map.2 = "id"
but unless you're trying to preserve an existing URL structure, I'd just leave the .htm out - it serves no purpose.

PDO_Mysql adapter - data type comparison (identical comparison)

I have a few problem when I use PDO_Mysql adapter with Zend.
application.ini
resources.db.adapter = mysqli
resources.db.host = localhost
resources.db.dbname = myproject
resources.db.username = root
resources.db.password = 123456
resources.db.profiler.enabled = true
resources.db.profiler.class = "Zend_Db_Profiler_Firebug"
DB init in bootstrap.php
$database = $config['resources']['db'];
$db = Zend_Db::factory($database['adapter'], $database);
$db->setFetchMode(Zend_Db::FETCH_OBJ);
$db->query("SET NAMES 'utf8';");
$db->query("SET CHARACTER SET 'utf8';");
Zend_Db_Table::setDefaultAdapter($db);
Zend_Registry::getInstance()->set('db', $db);
return $db;
Ok, when I do a simple fetchAll() and check the loop:
foreach ($rows as $row) {
if ($row->id === 1) {
echo 'first id';
} else {
echo 'other rows';
}
}
Exists a row in table with "ID" = "1" (integer), but, for any reason... when I use PDO_Mysql, I cant do data type comparison ("===" or "!=="), but if I use "Mysqli" adapter works fine.
With PDO_Mysql adapter, each column of each row are "string" (when I check with var_dump).
Somebody knows the reason ?
Thanks.

How to call a ".ini" file in a PHP Class?

I'm building a Postgresql "driver" for a project. I have used an ".ini" file to store the database details. Now I'm a little bit confused on how to call the ".ini" file.
I have this code. But give me an error.
<?php
class Postgresql {
// Parse Config.ini
$ini_array = parse_ini_file("../Config.ini", true);
print_r($ini_array);
public function __construct($hostname, $port, $username, $password, $database) {
// Connection String
$conn_string = "host=sheep port=5432 dbname=test user=lamb password=bar";
// Connect to Database
$db_conn = pg_connect($conn_string);
}
}
?>
What is the best place to put this lines of code?
// Parse Config.ini
$ini_array = parse_ini_file("../Config.ini", true);
print_r($ini_array);
Best Regards,
Well, you cannot put code in a class body like this:
class Foo {
echo 'bar'; // Parse error
}
You have to put it either in a method, or before/after the class declaration. For your current issue, it would make a lot more sense to do:
class Postgresql {
public function __construct($hostname, $port, $username, $password, $database) {
// Connection String
$conn_string = "host=sheep port=5432 dbname=test user=lamb password=bar";
// Connect to Database
$db_conn = pg_connect($conn_string);
}
}
// Parse Config.ini
$ini_array = parse_ini_file("../Config.ini", true);
$postgres = new Postgresql(
$ini_array['hostname'], $ini_array['port'],
$ini_array['username'], $ini_array['password'],
$ini_array['database']
);

Registering Zend Database Adapter in Registry

I am looking to register a reference to the main Database Adapter in the Registry during Bootstrapping so it can be used elsewhere in my site (specifically the Authorisation action).
I have implemented an ugly fix where i create a Database Table object and call the getAdapter() method on it and pass through that. However, this is a bad way of doing it and I would like it to be available via the registry.
Does anyone know how to do this? Any help or pointers in the right direction are appreciated!
I'm using Zend Framework 1.8.
If you're using Zend Framework 1.8+, and created your project with the command line tool, then it's as simple as registering your database settings in your application.ini config file.
resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "your.database.host"
resources.db.params.dbname = "database_name"
resources.db.params.username = "username"
resources.db.params.password = "password"
resources.db.isDefaultTableAdapter = true
If your database settings are preceded by resources.db you won't even need to do anything in your Bootstrap.php file because it will do it for you. Also, by setting the isDefaultTableAdapter setting to true, you can get an instance of your database adapter anywhere in your application.
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
Thanks for the replies. Ive decided to change the accepted answer and post the solution I finally used - which is insanely simple in the end!!
This is basically based on Dcaunt's comment...
In the bootstrap class..
protected function _initDb()
{
$resource = $bootstrap->getPluginResource('db');
$db = $resource->getDbAdapter();
Zend_Registry::set("db", $db);
}
Then access that elsewhere with...
$dbAdapter = Zend_Registry::get("db");
Thanks for the help and hopefully this helps someone else.
Your missing the best thing :)
If you use the Zend_Db_Table models (you should be) etc then you can set up a default adaptor - this way when you instantiate a model the DB connection it taken care off - this way you dont really need to save it in the registry or bother about connection before running a query through the model.
I do save it in the registry for later use if needed though - but I may remove this
protected function _initDB()
{
// Check that the config contains the correct database array.
if ($this->_config->db) {
// Instantiate the DB factory
$dbAdapter = Zend_Db::factory($this->_config->db);
// Set the DB Table default adaptor for auto connection in the models
Zend_Db_Table::setDefaultAdapter($dbAdapter);
// Add the DB Adaptor to the registry if we need to call it outside of the modules.
Zend_Registry::set('dbAdapter', $dbAdapter);
}
}
My 2 cents...
How to grab the default DB Adapter:
From Bootstrap:
<?php
$dbResource = $this->getPluginResource('db');
db = $dbResource->getDbAdapter();
var_dump($db);
?>
From a Controller there are two methods:
<?php
// Method 1
$bootstrap = $this->getInvokeArg('bootstrap');
$dbResource = $bootstrap->getPluginResource('db');
$dbAdapter = $dbResource->getDbAdapter();
var_dump($dbAdapter);
// Method 2
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
var_dump($dbAdapter);
?>
Check the zend-documentation at :
15.5.3.3. Storing a Database Adapter in the Registry
http://framework.zend.com/manual/en/zend.db.table.html
$db = Zend_Db::factory('PDO_MYSQL', $options);
Zend_Registry::set('my_db', $db);
// Later...
$table = new Bugs(array('db' => 'my_db'));
something like that you're looking for?
Edit:
to load your configuration from an ini-file, use:
parse_ini_file($inifile)
;configuration.ini
host = 127.0.0.1
user = username
password = blabla
;yourfile.php
$options = parse_ini_file('configuration.ini');
$db = Zend_Db::factory('PDO_MYSQL', $options);
I have a method in my bootstrap to add the adapter to the registry. I'd prefer a cleaner solution, but it works:
protected function _initRegistry(){
$this->bootstrap('db');
$db = $this->getResource('db');
$db->setFetchMode(Zend_Db::FETCH_OBJ);
Zend_Registry::set('db', $db);
}
Here is what i do:
Inside the bootstrap:
define('CONFIG_FILE', '../config/general.ini');
define('APP_MODE', 'development');
Inside the Initializer:
/**
* Initialize data bases
*
* #return void
*/
public function initDb ()
{
$options = Zend_Registry::get('conf');
$db = Zend_Db::factory($options->database);
$db->query(new Zend_Db_Expr('SET NAMES utf8'));
Zend_Registry::set('db', $db);
}
public function initConfig ()
{
if (file_exists(CONFIG_FILE) && is_readable(CONFIG_FILE)) {
$conf = new Zend_Config_Ini(CONFIG_FILE, APP_MODE);
Zend_Registry::set('conf', $conf);
} else {
throw new Zend_Config_Exception('Unable to load config file');
}
}
And finaly my config file looks like this:
[production]
database.adapter = pdo_Mysql
database.params.host = db.example.com
database.params.username = dbuser
database.params.password = secret
database.params.dbname = dbname
; Overloaded configuration from production
[development : production]
database.params.host = localhost
database.params.username = root
database.params.password =
Take a look at:
Zend_Db::Factory()
Zend_Config_Ini
Zend_Registry
If you are using Zend Framework 1.8 just do something like this in your controller/action:
class CreateorderController extends Zend_Controller_Action
{
public function testAction()
{
//more code
$users_obj = new Default_Model_Users(); //this would load the model using the Default namespace
//more code
}
}
My Defaul_Model_Users class would look something like this:
<?php
/**
* application/models/Users.php
*/
class Default_Model_Users extends Zend_Db_Table
{
protected $_table;
public function getTable()
{
if(null === $this->_table) {
$this->_table = new Default_Model_DbTable_Users();
}
return $this->_table;
}
public function fetchAll()
{
$result = $this->getTable()->fetchAll();
return $result;
}
}
And the part of the model which "interacts" directly with the database tables is found inside DbTable directory will look like this:
<?php
/**
* application/models/DbTable/Users.php
*/
class Default_Model_DbTable_Users extends Zend_Db_Table_Abstract
{
/** Table name */
protected $_name = 'users';
public function init()
{
$this->_db->setFetchMode(Zend_Db::FETCH_OBJ);
}
}
Then I would have the same application.ini generated by Zend Framework with this small addition:
resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.dbname = "mydb"
resources.db.params.username = "root"
resources.db.params.password = "password"
That is how I did without without having to change the bootstrap files.
I didn't want to use the registry to store an object that I should be able to access, so I did a little digging. It turns out that the bootstrap is registered as the front controller parameter "bootstrap", which is accessible from any of your controllers as explained in this manual page for Zend_Application.
So in your controller classes you can get the db adapter that has been defined in your ini file like this:
$bootstrap = $this->getInvokeArg('bootstrap');
$resource = $bootstrap->getPluginResource('db');
$db = $resource->getDbAdapter();