Registering Zend Database Adapter in Registry - zend-framework

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();

Related

zfcuser add user role after registration

I'm using Zend Framework 2 with ZfcUser, BjyAuthorize and Doctrine for the database. Registration etc. works very well so far. My problem is, that registered users have no role assigned, so i want to add the role "user" to the user during registration.
I think i could attach this to the "register" event, but i don't know how to do that.
I hope someone can help me ...
(i used this tutorial for setting up zfcuser etc. http://samminds.com/2013/03/zfcuser-bjyauthorize-and-doctrine-working-together/)
public function onBootstrap(MvcEvent $e)
{
$zfcServiceEvents = $e->getApplication()->getServiceManager()->get('zfcuser_user_service')->getEventManager();
$zfcServiceEvents->attach('register', function($e) {
$user = $e->getParam('user');
// probably the role must be added here, with $user->addRole();
// but how do i get the user Role Entity to add from DB?
});
Building on DangelZM's answer, and using another reference (see link at end of my post) about the Event Manager, I came up with this solution which organizes the potential ZfcUser event listeners out into a user listener object.
Note: I created my own user module called NvUser, so depending on the name of your module you'll have to replace all references of NvUser to your user module name.
Summary
I created an NvUserListener object that can itself attach event listeners to the shared event manager, and house the event listener callbacks.
Inside NvUser/Module.php:
<?php
namespace NvUser;
use Zend\Mvc\MvcEvent;
use NvUser\Listener\NvUserListener;
class Module
{
public function onBootstrap(MvcEvent $mvcEvent)
{
$em = $mvcEvent->getApplication()->getEventManager();
$em->attach(new NvUserListener());
}
}
Inside NvUser/src/NvUser/Listener/NvUserListener.php:
<?php
namespace NvUser\Listener;
use Zend\EventManager\AbstractListenerAggregate;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\Event;
class NvUserListener extends AbstractListenerAggregate
{
public function attach(EventManagerInterface $events)
{
$sharedManager = $events->getSharedManager();
$this->listeners[] = $sharedManager->attach('ZfcUser\Service\User', 'register', array($this, 'onRegister'));
$this->listeners[] = $sharedManager->attach('ZfcUser\Service\User', 'register.post', array($this, 'onRegisterPost'));
}
public function onRegister(Event $e)
{
$sm = $e->getTarget()->getServiceManager();
$em = $sm->get('doctrine.entitymanager.orm_default');
$user = $e->getParam('user');
$config = $sm->get('config');
$criteria = array('roleId' => $config['zfcuser']['new_user_default_role']);
$defaultUserRole = $em->getRepository('NvUser\Entity\Role')->findOneBy($criteria);
if ($defaultUserRole !== null)
{
$user->addRole($defaultUserRole);
}
}
public function onRegisterPost(Event $e)
{
$user = $e->getParam('user');
$form = $e->getParam('form');
// Do something after user has registered
}
}
Inside NvUser/config/module.config.php:
<?php
namespace NvUser;
return array(
'zfcuser' => array(
'new_user_default_role' => 'user',
),
);
References:
Understanding the Zend Framework 2 Event Manager
Maybe it's not the best solution, but it works for me.
Add user_role_id option in config scope.
public function onBootstrap(MvcEvent $mvcEvent)
{
$zfcServiceEvents = $mvcEvent->getApplication()->getServiceManager()->get('zfcuser_user_service')->getEventManager();
$zfcServiceEvents->attach('register', function($e) use($mvcEvent) {
$user = $e->getParam('user');
$em = $mvcEvent->getApplication()->getServiceManager()->get('doctrine.entitymanager.orm_default');
$config = $mvcEvent->getApplication()->getServiceManager()->get('config');
$defaultUserRole = $em->getRepository('SamUser\Entity\Role')->find($config['user_role_id']);
$user->addRole($defaultUserRole);
});
}
Maybe someone will offer better solution.
This work too.
public function onBootstrap(MvcEvent $mvcEvent)
{
$zfcServiceEvents = $mvcEvent->getApplication()-getServiceManager()->get('zfcuser_user_service')->getEventManager();
$zfcServiceEvents->attach('register', function($e) use($mvcEvent) {
$user = $e->getParam('user');
$em = $mvcEvent->getApplication()->getServiceManager()-get('doctrine.entitymanager.orm_default');
$defaultUserRole = $em->getRepository('SamUser\Entity\Role')-find('id_of_your_role_on_table_role_for_example: '2'');
$user->addRole($defaultUserRole);
});
}
I just used a MySQL trigger
DROP TRIGGER IF EXISTS `user_role_after_insert_trig`;
DELIMITER //
CREATE TRIGGER `user_role_after_insert_trig` AFTER INSERT ON `user`
FOR EACH ROW begin
insert into user_role_linker (user_id,role_id) values (new.user_id, 5);
end
//
DELIMITER ;

Module based application.ini in 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.

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']
);

How do I pass _SESSION('userName') from this Zend_Auth method to the layout?

I'm having a difficult time understanding how Zend_Session_Namespace is integrated with Zend_Auth. I have this method I'm using as the action to Authenticate my login page-it is working correctly and redirecting to the /monthly view:
public function authAction(){
$request = $this->getRequest();
$registry = Zend_Registry::getInstance();
$auth = Zend_Auth::getInstance();
$DB = $registry['DB'];
$authAdapter = new Zend_Auth_Adapter_DbTable($DB);
$authAdapter->setTableName('users')
->setIdentityColumn('UserName')
->setCredentialColumn('Password');
// Set the input credential values
$uname = $request->getParam('UserName');
$paswd = $request->getParam('Password');
$authAdapter->setIdentity($uname);
$authAdapter->setCredential($paswd);
// Perform the authentication query, saving the result
$result = $auth->authenticate($authAdapter);
// TRYING TO SET THE NAMESPACE
$this->session = new Zend_Session_Namspace('UserName');
if($result->isValid()){
$data = $authAdapter->getResultRowObject(null,'password');
$auth->getStorage()->write($data);
$this->_redirect('/monthly');
}else{
$this->_redirect('/login');
}
}
But I need to be able to store UserName as a Zend_session and call it from monthly controller. I'm not doing things right because I just get a blank screen when I try and do this:
public function indexAction()
{
$this->view->userName = Zend_Session_Namespace('UserName');
}
With the lines:
$data = $authAdapter->getResultRowObject(null,'password');
$auth->getStorage()->write($data);
You're writing all the user's information, except the password, which is OK. Where ever you need to access the logged in user's details, you can do something like (updated as per your comment):
public function indexAction() {
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()) {
$userData = $auth->getIdentity();
$this->view->user = $userData;
}
}
in the view file (index.phtml) just: echo $this->user->firstname
That's it. If one day you decide to change the storage for Zend_Auth from session, to, for example, database, this piece of code will still work.
Youre not useing the correct namespace. Zend_Auth use the Zend_Auth namespace. The namespace is the structure, not the key for a value. so your session looks something like this:
Array('Zend_Auth' => array ('UserName' => 'myname')
Well thats not accurate exactly because you havent stored the user name unless youve provided for this directly in your adapter. youll need to do something like:
$auth->getStorage()->UserName = 'myusername';
Then you can access with $authData = new Zend_Session_Namespace('Zend_Auth'); $username = $authData->UserName;.
Take a closer look at how the Zend_Auth_Adapter_Db works.
This is my approach and it s working nice:
1-i start by defining an init function in the bootstrap
protected function _initSession()
{
$UserSession = new Zend_Session_Namespace('UserSession');
$UserSession->setExpirationSeconds(/* you may fix a limit */);
Zend_Registry::set('UserSession', $UserSession);
}
/* in the Login action,after correct username & pwd */
// Create session
$UserSession = Zend_Registry::get('UserSession');
// Get the user from database or just from fields
//you have to make sure that the psswd is encrypted use MD5 for example..
$db = Zend_Db_Table::getDefaultAdapter();
$user = $db->fetchRow("SELECT * FROM user_table WHERE user_email = '".$user_email."'");
//then you assign to $user to $UserSession variable :
$UserSession->user = $user;
//finaly don't forget to unset session variable in the Logout action ...

Get Loaded Config In Controller

How do i get the already loaded options in the controller file in a zend framework installation without creating a new Zend_Config([ ** ]); instance.
Once Zend_Application reads application.ini, the values are stored in bootstrap.
You may access them anywhere, without accessing the disk, or using the registry:
$front = Zend_Controller_Front::getInstance();
$bootstrap = $front->getParam('bootstrap');
if (null === $bootstrap) {
throw new My_Exception('Unable to find bootstrap');
}
$options = $bootstrap->getOptions();
In the controller you may also use $this->getInvokeArg('bootstrap');
I am not sure at all what you are asking but are you asking how to use configs set in application.ini from a controller? If so you should load that config in Zend_Registry in your bootstrap and then retrieve it in your controller.
So in bootstrap.php
protected function _initConfig() {
$config = new Zend_Config_Ini("../application/configs/application.ini");
Zend_Registry::set('config', $config);
}
The in your Controller
$myConfig = Zend_Registry::get('config');