Need to modify the existing 'default' connection in cakePHP 3 - php

I need to modify the existing 'default' connection.
I tried to write it like this:-
ConnectionManager::config('default',$consoptions);
It gives an error telling me that we cannot reconfigure existing key "default".
Is there any way to achieve what I want?

The example shown in the CakePHP Cookbook is wrong and causes the error
Cannot reconfigure existing key "default"
You actually need to drop the default database connection configuration before replacing it with a new one.
In addition, the ConnectionManager::config() methos is deprecated in favour of ConnectionManager::setConfig()
This is a working example that modifies the default database connection:
use Cake\Datasource\ConnectionManager;
$dsn = 'mysql://root:password#localhost/my_database';
ConnectionManager::drop('default');
ConnectionManager::config('default', ['url' => $dsn]);

It gives an error telling me that we cannot reconfigure existing key "default" Is there any way to achieve what I want?
Drop the config then configure it again.
Spend some time checking the API, it's almost all there.

Related

using sfMailer and Dispatcher inside a task

I created a task in symfony 1.4, and I want to create a mailer based on the app.yml config.
this is my PHP code :
$config = sfConfig::get('app_mailers_mailer_a');
$this->_mymailer = new sfMailer($this->dispatcher, $config['param']);
when I execute the task, and vardump the $config variable, I get my config information (host, port, etc..).
The problem is in the second line, It stops their, without any error messages, so I think that the way I use the dispatcher (or $config['param']) is incorrect.
Thanks
I found the solution, the problem was not $config or $this->dispatcher, but the problem was that I forgot to initialize the sfMailer, so I added those lines before;
Swift::registerAutoload();
sfMailer::initialize();
Cheers ;)

Laravel 4 Redis Session Connection

I'm trying to use the Laravel Redis session driver,
Problem is - It seems to always assume usage of the "default" connection. Does anyone know if its possible to use a different connection ?
For example "session" ? So all my session would be on one server?
Also, whenever I don't have a "default" key in the redis array, i get exceptions all over the place. Must I declare a "default" connection ? What's wrong with having my own names?
e.g.
It doesn't look like there's an easy way of doing what you want. The Redis based session driver uses the Redis based cache driver:
http://laravel.com/api/source-class-Illuminate.Cache.RedisStore.html#5-155
Unfortunately that doesn't provide any way to specify which connection to use - it just uses the default connection:
http://laravel.com/api/source-class-Illuminate.Redis.Database.html#3-96
(magic method calls to the above class go straight to the default connection)
A possible way to get what you want might be to write your own class that extends RedisStore with a constructor that takes in a connection name and sets $this->redis to whatever Redis::connection($name) returns. You'd also need to figure out how to get the session handler to use your own cache driver though. I don't know how easy it would be or how you'd do that - it might be difficult to try and wire it all up.
There are a few ways to go about this:
I will outline why you were getting errors and how to fix this the simple way (incase someone else has the same issue):
open at vendor/laravel/framework/src/illuminate/Redis/Database.php
create a $name variable for your connection at the top of the class
class Database {
/**
* The host address of the database.
*
* #var array
*/
protected $clients;
protected $name;
change the connection function to expect your own 'default' fallback and 'set the name' of your current connection.
on the command method you will need to provide your 'new connection name' ($this->name) instead of the default one.
that's it!
now from anywhere in the application you can use the 'Redis' facade to access your connections just like this:
REDIS::CONNECTION('small');
REDIS::CONNECTION('large');
REDIS::CONNECTION('session');
REDIS::CONNECTION('etc');
Change the session driver in Config\session.php from native to redis

Renaming a Mongo Collection in PHP

PHP's Mongo driver lacks a renameCommand function. There is reference to do this through the admin database. But it seems more recent versions of the Mongo driver don't let you just "use" the admin database if do don't have login privileges on that database. So this method no longer works. I've also read this doesn't work in sharded environments although this isn't a concern for me currently.
The other suggestion people seem to have is to iterate through the "from" collection and insert into the "to" collection. With the proper WriteConcern (fire and forget) this could be fairly fast. But it still means pulling down each record over the network into the PHP process and then uploading it back over the network back into the database.
I ideally want a way to do it all server-side. Sort of like an INSERT INTO ... SELECT ... in SQL. This way it is fast, network efficient and a low load on PHP.
I have just tested this, it works as designed ( http://docs.mongodb.org/manual/reference/command/renameCollection/ ):
$mongo->admin->command(array('renameCollection'=>'ns.user','to'=>'ns.e'));
That is how you rename an unsharded collection. One problem with MR is that it will change the shape of the output from the original collection. As such it is not very good at copying a collection. You would be better off copying it manually if your collection is sharded.
As an added note I upgraded to 1.4.2 (which for some reason comes out from the pecl channel into phpinfo() as 1.4.3dev :S) and it still works.
Updates:
Removed my old map/reduce method since I found out (and Sammaye pointed out) that this changes the structure
Made my exec version secondary since I found out how to do it with renameCollection.
I believe I have found a solution. It appears some versions of the PHP driver will auth against the admin database even though it doesn't need to. But there is a workaround where the authSource connection param is used to change this behavior so it doesn't auth against the admin database but instead the database of your choice. So now my renameCollection function is just a wrapper around the renameCollection command again.
The key is to add authSource when connecting. In the below code $_ENV['MONGO_URI'] holds my connection string and default_database_name() returns the name of the database I want to auth against.
$class = 'MongoClient';
if( !class_exists($class) ) $class = 'Mongo';
$db_server = new $class($_ENV['MONGO_URI'].'?authSource='.default_database_name());
Here is my older version that used eval which should also work although some environments don't allow you to eval (MongoLab gives you a crippled setup unless you have a dedicated system). But if you are running in a sharded environment this seems like a reasonable solution.
function renameCollection($old_name, $new_name) {
db()->$new_name->drop();
$copy = "function() {db.$old_name.find().forEach(function(d) {db.$new_name.insert(d)})}";
db()->execute($copy);
db()->$old_name->drop();
}
you can use this. "dropTarget" flag is true then delete exist database.
$mongo = new MongoClient('_MONGODB_HOST_URL_');
$query = array("renameCollection" => "Database.OldName", "to" => "Database.NewName", "dropTarget" => "true");
$mongo->admin->command($query);

MongoDb PHP Driver - Aggregate query with readPreference?

Using php driver 1.3.2 and mongodb 2.2, I am trying to use readPreference to direct an aggregate query to one of the secondaries in my replica set. Seems whatever I try, the aggregate query is executed on the primary server.
Basic example:
$db = new \MongoClient('rs1.example:27017,rs2.example:27017,rs3.example:27017', array('replicaSet' => 'myRs') );
$db->setReadPreference( \MongoClient::RP_SECONDARY );
$results = $db->tracking->sessions->aggregate( array( ... ) );
I enabled MongoLog and got the following results:
The aggregate method shows: REPLSET INFO: - connection: type: PRIMARY
If I use find instead, it shows: REPLSET INFO: - connection: type: SECONDARY
Is this a bug with the php driver? Anyone else run into this? Thought I would toss it on SO before adding it as a bug in their Jira.
All command queries through the PHP driver are currently directed to primary servers. We have several old tickets related to this, originating with requests to direct count commands to secondaries, but it was a non-trivial change that requiring checking the command against a whitelist to ensure it is read-only. The current ticket tracking this fix is PHP-535, which I linked to the issue you opened, PHP-662.
If you need an immediate work-around, you can call find() on the $cmd collection directly, passing the same $command array argument that you'd typically pass to MongoDB::command() as the argument to find(). Kristina documented this solution in this JIRA comment, and although she used slaveOkay() in that example, it should also work with read preferences.

Conditional Component Loading in CakePHP

I'm using the DebugKit component in my project but I want to turn it on only on the staging server and have it not load when running from the production server.
I know I can turn it off with the debug config value but I want to keep that value at 1 for both servers.
I tried conditionally defining a contstant 'DEBUG_KIT' in bootstrap.php as either the component name (ie. 'DebugKit.Toolbar') or null. Then using that constant in the var $component definition at the top of the app_controller file. Well, Cake doesn't like having a null in the component array and barfs. Doesn't like an empty string either.
I feel like I'm missing something but can't quite see the forest for the trees. Thanks in advance!
I think the fundamental purpose of DebugKit is tied to being in debug mode, so I can understand that the tools don't provide the capacity to be disabled without also disabling debug mode.
That said, if you absolutely must do this, I think your best bet is to directly modify app/plugins/debugkit/controllers/components/toolbar.php, supplementing the existing debug-mode check in ToolbarComponent::initialize with a check against your constant.
(For what it's worth, I think you'd be better off turning debug-mode off on your production server, and using errors/warnings logged in /app/tmp/logs/error.log to identify issues that have slipped through your testing.)
I do something similar in my apps: I would use the __construct method to detect the presence DEBUG_KIT and add it to the $components array. This function gets called before the $components array is processed, so you can add/remove components transparently.
In your app_controller
function __construct(){
if(DEBUG_KIT){
$this->components[] = 'DebugKit.Toolbar'
}
parent::__construct();
}
If you have a _construct function in any or your individual controllers, remember to include parent::_construct(); otherwise you'll 'break the chain'.
Hope this helps
First, thanks to Adam Giles for a great answer. I hadn't thought to look at the __construct() callback. That just may be a better way than I found. And to Daniel Wright, point made sir. I'll probably change my production server to 0 debug soon and start watching the error logs.
I found my own answer shortly after posting this question. The DebugKit has an 'autoRun' parameter that will turn it on and off. So, I first set a global constant in bootstrap.php like this:
define( 'IS_DEV', ($_SERVER['SERVER_NAME'] == 'staging.example.com') );
Then in app_controller.php, I use it to set the 'autoRun' parameter in the $components statement.
var $components = array( 'DebugKit.Toolbar'=>array('autoRun'=>IS_DEV) );
This seems to work pretty well so far.

Categories