PHP Yii: Database connect in runtime - php

I would like to connect to a second database with Yii at runtime. The database name would come from a database table after the user to login.
I saw in a tutorial I should do this:
$db2 = Yii::createComponent(array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => $emp['database']
));
Yii::app()->setComponent('db2',$db2);
But in my controler when I access Yii::app()->db2 get the error:
Property "CWebApplication.db2" is not defined
What am I doing wrong?

The following works for me:
Yii::app()->mongodb->setActive(false);
Yii::app()->mongodb->setServer('mongodb://localhost:27017');
Yii::app()->mongodb->setDb('db1');
Yii::app()->mongodb->setActive(true);

UPDATED: Try, instead instance, pass configurations:
Yii::app()->setComponent( 'db2', array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => $emp['database']
)
);
Or, you may create special index on params in configurations, such as:
...
'params' => array(
'db2' => null,
),
And the use Yii::app()->params['db2'] = $db2

From this comment:
My problem is not with the creation of the component. Soon after
creating if I access Yii::app()->db2 its works, but when I try to
access via another model or controller I get the error
I think you are setting this component only once somewhere, and then making subsequent requests to different controllers.
You need to put the code, somewhere it is being called EVERYTIME, on every Request. thats how PHP works, there is no "global application state"
by default Yii comes with protected/components/controller.php has base controller for the rest of the app.
my suggestion would be to put your code on the init() method of that controller, so that it always gets called.
You mentioned the database name comes from a table once the user logs in, so you need to save that value in the session, in other to be able to access it in the other requests:
<?php
// After login in
Yii::app()->user->setState('db_name', $db_name);
// in protected/components/controller.php
public function init()
{
if (!Yii::app()->user->isGuest) {
$db2 = Yii::createComponent(array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => Yii::app()->user->getState('db_name')
));
Yii::app()->setComponent('db2',$db2);
}
}
Hope it helps, I am assuming many things here :)

Related

How to set a value to $_SERVER['var'] on a functional testing?

I have an action to make an 'autologin' based in a id that the system gets from $_SERVER['AUTH_USER']. In my business server that value is always set for authenticated user. Now, I am trying test my autologin (and so many other things that depends the autologin to work) so I need to set some user to that global (just a string).
What I tryed
$_SERVER['AUTH_USER'] = 'someUser';
$I->amOnPage('some-route'); // this page redirects to autologin action where $_SERVER is used to get the user logged.
But when the action autologin is loaded that value is no more inside $_SERVER global and my test crashes.
What I would like to know
Where or how I can set that global value so that my page could behave normally, reading the value and just going on.
I will appreciate any help.
Thank you.
It looks like lack of proper abstraction. You should avoid accessing $_SERVER['AUTH_USER'] directly in your app and do it in at most in one place - in component which will provide abstraction for this. So you should probably extend yii\web\Request and add related method for $_SERVER['AUTH_USER'] abstraction:
class MyRequest extends \yii\web\Request {
private $_myAuthUser;
public function getMyAuthUser() {
if ($this->_myAuthUser === null) {
$this->_myAuthUser = $_SERVER['AUTH_USER'];
}
return $this->_myAuthUser;
}
public function setMyAuthUser($value) {
$this->_myAuthUser = $value;
}
}
Use new class in your config:
return [
'id' => 'app-web',
// ...
'components' => [
'request' => [
'class' => MyRequest::class,
],
// ...
],
];
And use abstraction in your action:
$authUser = explode('\\', Yii::$app->request->getMyAuthUser())[0];
In your tests you can set value using setter in MyRequest:
Yii::$app->request->setMyAuthUser('domain\x12345');
Or configure this at config level:
return [
'id' => 'app-test',
// ...
'components' => [
'request' => [
'class' => MyRequest::class,
'myAuthUser' => 'domain\x12345',
],
// ...
],
];
UPDATE:
According to slinstj comments, Codeception may loose state of request component, including myAuthUser value. In that case it may be a good idea to implement getMyAuthUser() and setMyAuthUser() on different component (for example Yii::$app->user) or create separate component for that:
return [
'id' => 'app-web',
// ...
'components' => [
'authRequest' => [
'class' => MyRequest::class,
],
// ...
],
];
For now, I am using a workaround because there is only one place where that variable value it is checked:
//Inside my action autologin:
$authUser = explode('\\', ($_SERVER['AUTH_USER'] ?? (YII_ENV_TEST ? 'domain\x12345' : 'domain\xInvalid')))[1];
The only relevant point here is YII_ENV_TEST that is true when testing. Using this I can set get an specific value that is enough to that simple test.
However I hope to see any other better idea here!
Thanks.

How do call a method inside a component in OctoberCMS?

I don't know if this is possible or if it's a complete madness but I'm trying to execute a PHP method from AJAX call using OctoberCMS Ajax Framework(I assume that this uses jQuery behind it) and is not working because I never get redirect to PayPal site. The PHP code I'm trying to get working is this one:
protected function onExecutePurchaseMethod()
{
Omnipay::gateway('PayPal_Express');
$params = [
'username' => $this->username,
'password' => $this->password,
'signature' => $this->signature,
'testMode' => $this->sandboxMode,
'amount' => Session::get('amountToReload'),
'cancelUrl' => url( 'payment/step4', "", $secure = null ),
'returnUrl' => url( 'payment/step2', "", $secure = null ),
'currency' => 'USD'
];
$response = Omnipay::purchase($params)->send();
if ($response->isSuccessful()) {
var_dump($response);
} else {
var_dump($response->getMessage());
}
}
What is happening since none redirect to PayPal is executed and page is getting stuck many times forcing me to close the browser and reopen again, no method is executed and no visible errors. It's possible to do what I'm trying to do? Is not a madness? If it's possible where is my error?
As extra info I'm using Barryvdh Laravel-omnipay package for handle Omnipay from within Laravel.
After looking briefly through the documentation, my best guess is that you're missing a required field for the purchase() method. I believe you need a card parameter (even if it's an invalid one) to get it to process.

Using Zend_Form_Element_Captcha - session has already been started

I am trying to add a Captcha as part of a big application form.
Getting the following error:
session has already been started by session.auto-start or session_start()
How can I get around this as behind the scenes it uses:
// Process metadata specific only to this namespace.
Zend_Session::start(true); // attempt auto-start (throws exception if strict option set)
I instantiate it in the Controller:
$this->view->captcha = new Zend_Form_Element_Captcha('captcha', array(
'captcha' => array(
'captcha' => 'Figlet',
'wordLen' => 6,
'width' => 300,
'height' => 100,
)
)
);
In the View:
<?php echo $this->captcha; ?>
I can't tamper with current session as it holds a lot of information. Is there a workaround?
Help would be appreciated.
You can do one thing in this case, try starting your Zend session in bootstrap file in below way and set that session object in registry:
protected function _initSession() {
$userSession = new Zend_Session_Namespace('user_session');
Zend_Registry::set('userSession', $userSession);
}
After this you will be able to get session object anywhere from registry.
$userSession = Zend_Registry::get('userSession');
Since you will start your Zend Session before session_start() so it might not produce any error.

MongoDB running command in lithium

I'm trying to run a full text search against some data that is stored in mongoDb using Lithium.
Here is how I am trying to do it in my controller:
$mongodb = Connections::get('default')->connection;
$results = Page::connection()->connection->command(array("text" => "Page", 'search' => "term" ));
I've also tried:
$results = Page::connection()->connection->command(array("text" => "Page", 'search' => "term" ));
However, both of these return: Fatal error: Call to a member function command() on a non-object
What am I doing wrong?
EDIT:
I should add that a simple query on Page is working just fine. For instance:
$results = Page::find('all');
Does return an array with all of the documents in the pages collection like I would expect it to.
UPDATE 2:
I was running all of this from WAMP server. I tried today running it from a linux server, but still got the same exact error. I am really stumped by this and could use some help. Anyone have any ideas?
here is the Page model as it sits now:
<?php
namespace app\models;
use lithium\data\Connections; //added during debugging
use lithium\data\source\MongoDb; //added during debuging
class Page extends \lithium\data\Model {
}
?>
Here is my connection:
Connections::add('default', array(
'type' => 'MongoDb',
'host' => '192.168.48.128',
'database' => 'my_collection'
));
I'm doing it this way:
$plugins = Plugins::connection()->connection->command([
'text' => 'plugins',
'search' => $this->request->query['q']
]);
return compact('plugins');
so I'd recommend checking your configuration - is your model returning other data normally? Is the connection configuration correct?
Got help to figure it out... posting here for others to reference.
proper way of calling it is:
$conn = Model::connection();
$db = $conn->selectDB('db');
$result = $db->command(array(...
Works perfectly when done this way.

CakePHP log in system

I am editing a website which someone has made in CakePHP, but I don't have any previous experience in Cake. I'm reading the manual but finding it quite hard to understand so thought I would post a question on here to see if I can get any quick answers.
I think that this code is being used to display a login box, and you can only log in with username test and password 123123
var $components = array("Auth", "Acl");
function beforeFilter(){
$this->Security->loginOptions = array(
'type' => 'basic',
'realm' => 'Authenticate Emergency Response Center'
);
$this->Security->loginCredentials = array(
'test' => '123123'
);
$this->Security->requireLogin();
$this->_bindToSite();
parent::beforeFilter();
}
I want the log in box to appear still, but I want to fill the loginCredentials array automatically with information from the database. I have a table called 'operators' which contains the fields 'user_id' and 'password'.
Could someone tell me how I would alter the code above to allow any of the usernames/passwords stored in the operators table to log in?
Thanks for any help
Build an array from the database and set $this->Security->loginCredentials equal to your array.
You can leave most of the hard work up to CakePHP's Auth component, but if you want to use a model other than the default 'User', you'll just need to set this in beforeFilter(). The best place to do this is probably app_controller.php in your app\ directory.
function beforeFilter(){
$this->Auth->userModel = 'Operator';
$this->Auth->fields = array(
'username' => 'user_id',
'password' => 'password'
);
);

Categories