CakePHP shell: Switch CAKE_ENV on the Go - php

I have a little problem in here. I'm new at cakephp and now have to developing a cakephp shell script to saving data into its database. The problem is, I work on default environment and need to save data into another environment. I'm using this code to switch environment:
ConnectionManager::alias($env, 'default');
It seems good since I've got right output when try to get database.
$this->out($datasource->config()['database']);
And then I load my model:
$model = $this->Model;
But It's load the model data from default environment. Is my approach wrong? Or, there is another method to switch environment on the go with cakephp?

That should work just fine, and a quick test shows that it does. You'd probably have to show a little more context, but I guess you are loading the model (what you're showing there isn't loading but accessing) before the connection alias is being created, hence the model will use the original connection that it received when it has been instantiated.
So either make sure that you load the model afterwards, respectively that you create the alias before the model is being loaded (that is when TableRegistry::get() is being invoked), or change the connection of the specific model on the fly in case applicable:
$connection = ConnectionManager::get($env);
$model->setConnection($connection); // use connection($connection) in CakePHP < 3.4

Related

Phalcon pdo excpetion model first

I have problem with phalcon framework namely with models methods...
As you know models has included methods find() and findFirst()
I have generated model with phalcon-dev tools and now I am trying to do Model::find on it but I am getting an exception but dont know why...
There is some more informations (e.g stacktrace) :
http://exception.mateuszmarzecki.pl/
You can try change methods in model file
public static function find($parameters = array())
{
return self::find($parameters);
}
Does not look like your passing it the right parms.
SELECT FROM `nacionality`
Notice that your not selecting any fields from the database, and that is why your getting the Exception.
So... after some time of debugging I've found the problem...
For the next generation... if you don't want to lose a week as I did. Just read carefully your application config.
Problems occurs because I missed table and column annotations as well.
In my application config I have something like:
$metaData->setStrategy(new \Engine\Db\Model\Annotations\Metadata());
so Phalcon was looking for annotations in my model files, more info about this you can find there:
https://forum.phalconphp.com/discussion/1933/column-types-for-model-annotations
Happy New Year

Changing the behaviour of view in Codeigniter

I am using codeigniter for a project that is used by a variety of companies.
The default version of our software is up and running and works fine - however some of our customers want slightly different view files for their instance of the system.
Ideally what I would like to do is set a variable (for example VIEW_SUFFIX) and whenever a view file is loaded it would first check if there was a suffix version available if there was use that instead.
For example if the system had a standard view file called 'my_view.php' but one client had a VIEW_SUFFIX of 'client_1' - whenever I called $this->load->view('my_view') if the VIEW_SUFFIX was set it would first check if my_view_client_1 existed (and if it did use that) or if not use the default my_view.php.
I hope that my question is clear enough... If anyone has done this before or can think of a way to do it I would really appreciate it.
EDIT:
Ideally I would like a solution that works without me changing every place that I am calling the view files. Firstly because there are a few files that may want different client versions and also because the view files are called from a lot of controllers
I had a similar requirement for which I created a helper function. Among other things, this function can check for a suffix before loading the specified view file. This function can check for the suffix and check if the file exists before loading it.
Unfortunately, the file checking logic would be a bit brittle. As an alternative, you can implement a MY_Loader class that will override the basic CI_Loader class.
Something like this in your application/core/MY_Loader.php:
class MY_Loader extends CI_Loader {
protected function _ci_load($_ci_data)
{
// Copy paste code from CI with your modifications to check prefix.
}
}
Could you not do this
// some method of creating $client
// probably created at login
$_SESSION['client'] = 'client_1';
$client = (isset($_SESSION['client'])) ? $_SESSION['client'] : '';
$this->load->view("your_view{$client}", $data);

How will one make an unit test in PHP if an ORM layer is used?

I have a class let's say Person. The ORM layer has generated based on the sql structure the corresponding objects. The class person has a method: Get($id). In the Get method, the object Person is called and the field from the table are retrieved.
I basically want to make the following unit test: create a new person and check if the Get method is returning the right information.
How is the unit testing supposed to work in this condition ?
Do I need to create a separate database ( just the structure ), and make the creation/selection from that database?
Should the boostrap file load the same configuration as the framework I'm using but change the configuration file so It works with the fake database ?
Should I clean the new database each after each test ?
I was also wandering after seeing your responses if simulating an ORM response without actually building a new database is not the way to go ?
How is the unit testing supposed to work in this condition ?
Generally, you should split your unittests mentally in two parts:
one part of your code is testable without the database, so you can stub or mock the methods that do the database access
the other part of your tests needs to work with the database, since it tests if the ORM is used correctly.
Do I need to create a separate database
This depends on your needs. Rails apps generally have testing/development/production "environments" - database, configuration, storage directories.
Testing is for running unit tests, dev for developing things and production for running the live server. While developing, you run against the dev configuration and thus your development database. For unit tests, the testing env is used which has the benefit that i.e. users in the database are not deleted or broken.
I like that concept; in my phpunit tests I often do have a switch in the bootstrap that changes which configuration file is loaded. Just remember that your development database often contains more data than a single unit test needs, and you probably hand-crafted that data and do not want to lose. Also, another database does not cost money.
Should I clean the new database each after each test?
I mostly clean the tables only that will be used in the test. Cleaning your database makes sure you don't get side-effects from previous tests.
Check out Phactory. I prefer it over the database extensions included in PHPUnit and it makes it really easy to insert records into your test db.
require_once 'Phactory/lib/Phactory.php';
Phactory::setConnection(new PDO('sqlite:test.db'));
Phactory::define('user', array('name' => 'Test User',
'email' => 'user#example.com'));
$user = Phactory::create('user'); // creates a row in the 'users' table
print("Hello, {$user->name}!"); // prints "Hello, Test User!"
Your System Under Test (SUT) will need to connect to your test database. The idea is that you populate just the records you need for the method you are testing. The orm layer shouldn't matter if the test db has all the same tables and fields as your production database.
PHPUnit also provides some help with this, have a look at Database Testing.
Essentially you can write you Test classes so that they extend PHPUnit_Extensions_Database_TestCase and then use the getConnection() and getDataSet() functions to load up data for the test.
require_once 'PHPUnit/Extensions/Database/TestCase.php';
class PersonTest extends PHPUnit_Extensions_Database_TestCase
{
protected function getConnection() {
$pdo = new PDO('mysql:host=localhost;dbname=application_test', 'root', '');
return $this->createDefaultDBConnection($pdo, 'application_test');
}
protected function getDataSet() {
return $this->createMySQLXMLDataSet('person.xml');
}
Then you can define exactly what you want to test in the database in the XML.
You can also assert that the resulting DataSet from your tests is equal to what you expect with:
public function testCreate() {
// Execute some code with your ORM to create a person.
$actual = new PHPUnit_Extensions_Database_DataSet_QueryDataSet($this->getConnection());
$actual->addTable('person');
$expected = $this->createMySQLXMLDataSet('person_create_expected.xml');
$this->assertDataSetsEqual($expected, $actual);
}
In this example, we are only comparing the resulting person table... So person_create_expected.xml should only contain the person table as well.
To create the XML's you can use mysqldump.
mysqldump --xml -t -u root -p application_test > person.xml

Codeigniter Datamapper save() not actually saving to database

I'm running CodeIgniter 1.7.3, Datamapper DMZ 1.7.1 (and no, upgrading is not an option), MySQL 5.1, and the Cron Job Boostrapper for an application I'm building. I'm attempting to extract information from an XML file and save it into a database. Getting the data works just fine, as does getting data from the database, so I know it's neither an issue with the database connection, nor the XML file.
$this->site = $this->site->get_by_short_name('site');
//Load the XML files into variables so we can do stuff with them.
$doctors = simplexml_load_file(realpath('../xml/doctors.xml'));
foreach ($doctors->children() as $doctor) {
$dr = new Doctor();
$attrs = $doctor->attributes();
/* See if the Doctor already exists. If so, update it.
* Datamapper won't update fields that don't change, so if nothing's
* changed, then the DB call won't be made.
*/
$dr->get_by_drkey($attrs['Key']);
$dr->drkey = $attrs['Key'];
$dr->first_name = $doctor->FirstName;
$dr->middle_name = $doctor->MiddleName;
$dr->last_name = $doctor->LastName;
$dr->long_name = $doctor->LongName;
$dr->degrees = $doctor->Degrees;
$dr->pic = $doctor->ImageURL;
$dr->save($this->site);
}
I've checked the return value of $dr->save($this->site) and it's coming back as true ("successful save"), but the data isn't saving, and there's no error. I've tried without the relation (removed the requirement for it in the database), so it should save without error, but it still doesn't save. I also double-checked the relationship setup in the models and they're fine.
I also tried bypassing Datamapper and doing a straight $this->db->insert('doctors',$data) with the data converted to an array, but the data still doesn't save. I've also tried running it from the browser (bypassing the bootstrapper) to see if the issue had to do with running from the command line, but that also didn't work. I'm also not autoloading any session or authentication libraries, so that known issue with the bootstrapper isn't being triggered.
Does anyone have any insight into why this might not be working?
I've found what was going on. It turns out that the attributes of the SimpleXML objects (the individual records) weren't getting picked up by Datamapper as strings, so they weren't getting escaped, and MySQL was choking. Typecasting them when setting the model object's values ($dr->first_name = (string)$doctor->First_Name;) fixed this problem.
I was able to get the insert query through $dr->check_last_query() after the object attempts to save.

Disable Cakephp's Auto Model "feature"

In cake 1.2 there is a feature that allows the developer to no have to create models, but rather have cake do the detective work at run time and create the model for you. This process happens each time and is neat but in my case very hazardous. I read about this somewhere and now I'm experiencing the bad side of this.
I've created a plugin with all the files and everything appeared to be just great. That is until i tried to use some of the model's associations and functions. Then cake claims that this model i've created doesn't exist. I've narrowed it down to cake using this auto model feature instead of throwing and error! So i have no idea what's wrong!
Does anybody know how to disable this auto model feature? It's a good thought, but I can't seem to find where i've gone wrong with my plugin and an error would be very helpful!
There's always the possibility to actually create the model file and set var $useTable = false.
If this is not what you're asking for and the model and its associations actually do exist, but Cake seems to be unable to find them, you'll have to triple check the names of all models and their class names in both the actual model definition and in the association definitions.
AFAIK you can't disable the auto modelling.
Cake 1.2
It's a hack and it's ugly cus you need to edit core cake files but this is how i do it:
\cake\libs\class_registry.php : line 127ish
if (App::import($type, $plugin . $class)) {
${$class} =& new $class($options);
} elseif ($type === 'Model') {
/* Print out whatever debug info we have then exit */
pr($objects);
die("unable to find class $type, $plugin$class");
/* We don't want to base this on the app model */
${$class} =& new AppModel($options);
}
Cake 2
Costa recommends changing $strict to true in the init function on line 95 of Cake\Utility\ClassRegistry.php
See Cake Api Docs for init
ClassRegistry.php - init function
Use
var $useTable = false;
in your model definition.
Delete all cached files (all files under app/tmp, keep the folders)
In most cases where models seem to be acting in unexpected ways, often they dont include changes you've made, it is because that cake is useing an old cached version of the model.
Uh...where do we start. First, as Alexander suggested, clear your app cache.
If you still get the same behaviour, there is probably something wrong with the class and/or file names.
Remember the rules, for controller:
* classname: BlastsController
* filename: blasts_controller.php
for model:
* classname: Blast
* filename: blast.php
Don't foget to handle the irregular inflections properly.

Categories