11

iam using zend framework to build a REST web service and i am using modules to separate my api versions.

Now, i want to have a separate configuration file for each of my module (v1 and v2), mainly for specifying separate database connections.

I had a directory structure like this:

- application
      - modules
            - v1
                  - controllers
                  - models
                  - views
                  - configs
                    - module.ini         
            - v2
                  - controllers
                  - models
                  - views  
                  - configs
                    - module.ini
      - configs
            - application.xml   
- library

I already have the database connection mentioned in my "application.ini" inside application/configs. I read here about module specific confurations and tried it.

I removed these database params from application.ini and put it in module.ini:

[production]
resources.db.adapter = PDO_MYSQL
resources.db.params.host = 127.0.0.1
resources.db.params.username = myuser   
resources.db.params.password = mypwd
resources.db.params.dbname = my_db
resources.db.params.profiler.enabled = "true"
resources.db.params.profiler.class = "Zend_Db_Profiler_Firebug"

.....

But i got an error saying "No adapter found..." when i accessed database in my module's controller. Please help...

7
  • need more information - at which line you get the error? Is it a PHP fatal error? Commented Mar 4, 2011 at 12:43
  • I think it is just a normal error message. But the execution halted after the error. Commented Mar 4, 2011 at 13:05
  • Could you like add this in the /public/.htaccess file: SetEnv APPLICATION_ENV "development" Then tell us the error details. Commented Mar 4, 2011 at 15:02
  • 1
    Can't you just use module-specific bootstraps? Commented Mar 5, 2011 at 0:02
  • @Perfection: I am getting an error such as "No adapter found..." Commented Mar 7, 2011 at 10:00

3 Answers 3

6
+50

In the bootstrap, you can set your database connections:

protected function _initDb () {
    $config['my_db1'] = new Zend_Config_Ini(APPLICATION_PATH . '/configs/my_db1.ini');
    $config['my_db2'] = new Zend_Config_Ini(APPLICATION_PATH . '/configs/my_db2.ini');

    $my_db1 = new Plugin_Replication($config['my_db1']->toArray());
    $my_db1->query("SET CHARACTER SET utf8;");

    $my_db2 = new Plugin_Replication($config['my_db2']->toArray());
    $my_db2->query("SET CHARACTER SET utf8;");

    Zend_Db_Table::setDefaultAdapter($dmy_db1);
    Zend_Registry::set('my_db1', $my_db1);
    Zend_Registry::set('my_db2', $my_db2);
}

Each connection is specified in a separate .ini file in my case. I find this pretty intuitively organised. A database ini file does not require the resources.db.whatever names. Mine go like this:

[Master]
host = "xxx"
username = "xxx"
password = "xxx"
dbname = "xxx"
charset = utf8

[Slaves]
first.host = "xxx"
first.username = "xxx"
first.password = "xxx"
first.dbname = "xxx"
first.charset = utf8

second.host = "xxx"
second.username = "xxx"
second.password = "xxx"
second.dbname = "xxx"
second.charset = utf8

Once you have multiple databases set up like this, when creating a model (in any module you wish), you can inform ZF about the database you would like to use:

protected function _setupDatabaseAdapter() {
    $this->_db = Zend_Registry::get('my_db1');
}

This will be your default adapter. In case you need to use two databases in the same query, start your model's function with:

public function myAwesomeSqlQuery () {
    $db1 = $this->getAdapter()->getConfig(); //default adapter
    $db2 = Zend_Registry::get('my_db2')->getConfig(); //additional adapter

Now, you can write your query using the two databases this way:

$sql = $this
    ->select()
    ->setIntegrityCheck(false)
    ->from(array('col1' => $db1['dbname'].'.some_column'))
    ->join(array('col2' => $db2['dbname'].'.some_other_column')),'col1.id = col2.id')
;

As I suggested in a comment, you can also use module-specific bootstraps. The structure would go like this:

/application/
  -- /modules/
    -- /v1/
        -- /controllers/
        -- /views/
        -- /Bootstrap.php
    -- /v2/
        -- /controllers/
        -- /views/
        -- /Bootstrap.php

The module-specific bootstraps are constructed pretty much like any other bootstrap, but they affect the module in question. The class names are typically prefixed with the modules names, e.g.:

<?php
class V1_Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
    ...
}

I generally try not to use module-specific bootstraps because they are all launched with each request (Zend Framework 2 is supposed to correct this), running functions that aren't necessary for your current module. Anyway, I found a module-specific bootstrap in one of my modules, which contains something like this:

class MyModule_Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
    protected function _initLoggers () {
        $my_db1 = Zend_Registry::get('my_db1');
        $my_db2 = Zend_Registry::get('my_db2');
        $my_db1->setProfiler(new Zend_Db_Profiler_Firebug())->getProfiler()->setEnabled(true);
        $my_db2->setProfiler(new Zend_Db_Profiler_Firebug())->getProfiler()->setEnabled(true);

        $auth = Zend_Auth::getInstance();
        $columnMapping = array('priority' => 'priority' , 'message' => 'message' , 'timestamp' => 'timestamp' , 'username' => 'username');
        $logger = new Zend_Log(new Zend_Log_Writer_Db($my_db1, 'logs', $columnMapping));
        print_r($auth->getIdentity());
        if ($auth->hasIdentity())
            $logger->setEventItem('username', $auth->getIdentity()->username);
        Zend_Registry::set('logger', $logger);
    }

That's pretty much it. I hope it helps.

Sign up to request clarification or add additional context in comments.

6 Comments

Mingos, i want to try your solution, but i am confused with the model part of the modules... can you post the code related to model and how to query from model or controller
It's all there in the answer. What are you having problems with, specifically?
I have written the initDb() method in my application bootstrap, and also added 2 separate db config files as mentioned. But i could not understand where to write the _setupDatabaseAdapter() method. Is it inside the modules/my_module/models/bootstrap file ?
No no no, it goes inside your models :). It tells the model which database to use as default :)
Yeah :). Sorry, it's just I'm using a more complex setup, with a master server and two slave servers. The replication is used to replicate all changes on master to the slaves. You can get rid of these lines. I shouldn't have copied them at all.
|
2
+50

The solution (My_App) you refer to in your question does not require any additional configuration for module specific database connections, or any other module specific configuration (except for routes). All you need to do is to declare a MultiDb resource in the application.ini as db1. Then you can declare any module specific database resource in the requested module's respective module.ini as db2, db3, db4... etc... you do not need any additional configuration. I placed an example in the download file at my github. Not to disrespect the response by "mingos" above but there's no need for any additional code in My_App.

Here's the exact verbage taken from the download (application.ini):

...if this resource is declared here, then it
will be available to all modules. If different
db resources need to be used for different
modules then MultiDB resource can be
initiated. Example: A general db resource can be
defined here and a module specific db can be
declared in its corresponding module.ini.
The db resource declared in the module will not
be available to other modules but the db resource
in this application.ini will be available to all
modules...

Then it declares a single db resource as an example in the download. Just change it to a multi db resource. Declare the application wide needed db resource in application.ini, and any additional db resource that is needed for any specific module in their respective module.ini files. It's straightforward. That's all you need to do. Once you understand the logic behind My_App, you will see it's very powerful.

7 Comments

Thanks for the kind answer osebboy. Its great of you. Can you mention the line that i need to write in my application.ini to declare a MultiDb resource ?
#resources.multidb.db1.adapter = "pdo_mysql" #resources.multidb.db1.host = "localhost" #resources.multidb.db1.username = "webuser" #resources.multidb.db1.password = "XXXX" #resources.multidb.db1.dbname = "db1" The above is the initial declaration of a multiDb resource. You can declare that in the application.ini. Since it's declared in application.ini, it will be available to all modules. Now, if you need any additional Db resource in a specific module, then you can declare that resource in its respective module.ini as db2, db3...
This way you can have an application wide db resource and module specific db resources. No code is needed. Remember that My_App creates completely isolated modules. I suggest that you try to understand the logic behind My_App.
Thanks, that worked. I specified separate database configs in the module.ini files for each of my modules, including default module. It worked awesome.
Great... you can also declare module specific layouts, controller plug-ins and other resources. There's so much to do with it if you can get deeper in the subject matter.
|
1

osebboy's solution is not configured to have a configuration file other than .ini. You have application.xml. It seems like the initial setup is incorrect depending on osebboy's solution.

I suggest that you download the source from his github and set it up that way. Also read his blog post about it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.