I have already seen this question:
CakePHP PHPUnit Fixtures Drop Database Table Every Time
Creating multiple fixtures in cakePhp
CakePHP Test Fixtures Drop My Tables Permanently After Running A Test Case
But this links are old I think.
I would like to create test where Im'loading fixtures so test drop tables and create it with records.
My problem is that: Tests drop taboles btu it doesn't recreate it.
This is my model where I'm loading fixtures:
App::uses('Post', 'Model');
class PostTest extends CakeTestCase {
public $fixtures = array('app.post');
public function setUp() {
parent::setUp();
$this->Post = ClassRegistry::init('Post');
}
public function testSetTemplate() {
$this->assertEquals('1', '1');
}
}
And this is my fixture file:
class PostFixture extends CakeTestFixture {
public $import = array('model' => 'Post', 'records' => true);
public $name = 'Post';
public $table = 'posts';
public $fields = array(
'id' => array('type' => 'integer', 'length' => 36, 'key' => 'primary'),
'created' => array('type' => 'datetime'),
'modifed' => array('type' => 'datetime')
);
public $records = array(
array(
'id' => '1',
'created' => '2014-01-17 12:31:41',
'modified' => '2014-07-22 09:50:42'
),
);
}
I have also tried with:
public $import = array('model' => 'Post', 'records' => false);
Same thing tests drop tables but doesn't create it.
I need to create it after drop with my records.
Where s the error? Why tests doesn't recreate it table posts but only drop it?
Thanks
Related
I have 3 tree like connected tables. Their schemas as follows:
Member{
//Some column
}
Transactions{
member_id :: foreign key of member table
//Some other column
}
TransactionItems{
transaction_id :: foreign key of Transaction table
//Some other column
}
I define models like this:
class Members extends AppModel {
public $primaryKey = 'id';
public $hasOne = array(
'Transactions' => array(
'className' => 'Transactions',
'foreignKey' => 'member_id',
'dependent' => true
)
);
}
class Transactions extends AppModel {
public $primaryKey = 'id';
public $belongTo = array('Members');
public $hasOne = array(
'TransactionItems' => array(
'className' => 'TransactionItems',
'foreignKey' => 'transaction_id',
'dependent' => true
)
);
}
class TransactionItems extends AppModel {
public $primaryKey = 'id';
public $belongTo = array('Transactions');
public $belongsTo = array(
'Transactions' => array(
'className' => 'Transactions',
'foreignKey' => 'transaction_id'
)
);
}
I have a Data Array which I want to save into database. My scheme is:
Array(
[Members] = [],//Array
[Transactions] = [],//Array
[TransactionItems] = []//Array
)
The problem is that whenever I run $this->Members->saveAll($data). It save data in Member and Transactions table. But do not create data in TransactionItems table. I want to save in all 3 tables at a time.
Any help would be grateful.
Second level (and above) associations must be nested, ie the data structure needs to be:
array(
'Members' => array(),
'Transactions' => array(
'TransactionItems' => array()
)
)
A bit awkward, but that's how it works in 2.x. You can always refer to the structure that is being returned when reading data, it needs to be the same when saving it.
Furthermore you must set the deep option to true in order to be able to save second level and above associations (by default only first level associations are being saved):
$this->Members->saveAll($data, array('deep' => true));
See also
Cookbook > Models > Saving Your Data > Model::saveAssociated()
Unable to locate in the SilverStripe Documentation how to have a DataObject Model inject a collection of default records on /dev/build
Anybody able to point me in the right direction
This is what I currently have, and obviously I would like to inject pre-configured options into this aptly named Configuration model for my Module.
class Configuration extends DataObject
{
private static $db = array(
'Option' => 'Varchar',
'Value' => 'Varchar'
);
private static $summary_fields = array(
'Option' => 'Option',
'Value' => 'Value',
);
}
Thanks in advance for any direction/pointers.
UPDATE
I was turned onto SiteConfig by #Barry below
However in following his practice, requireDefaultRecords() is not injecting defaults
Note: I have since revisited /dev/build?flush
class RMSConfiguration extends DataExtension
{
private static $db = array(
'username' => 'Varchar',
'password' => 'Varchar',
'agent_id' => 'Varchar(15)',
'client_id' => 'Varchar(15)',
'testMode' => 'Int(1)',
'timezone' => 'Varchar',
'apiUrl' => 'Varchar(255)'
);
public function updateCMSFields(FieldList $fields)
{
$fields->addFieldsToTab(
"Root.RMSConfig",
array(
TextField::create('username', 'RMS Username'),
TextField::create('password', 'RMS Password'),
TextField::create('agent_id', 'RMS Agent ID'),
TextField::create('client_id', 'RMS Client ID'),
TextField::create('apiUrl', 'API Url'),
CheckboxField::create("testMode", 'Toggle Test Mode'),
DropdownField::create("timezone", 'Timezone', static::$timezones)
)
);
}
public function requireDefaultRecords()
{
parent::requireDefaultRecords();
$arrOptions = array(
'timezone' => 'Australia/Sydney',
'apiUrl' => 'https://api.example.com.au/',
'testMode' => 0
);
foreach ($arrOptions as $strOption => $strValue) {
if (!$configuration = self::get()->filter('Option', $strOption)->first()) {
$configuration = self::create(array( 'Option' => $strOption ));
}
$configuration->Value = $strValue;
$configuration->write();
}
}
/**
* List of timezones supported by PHP >=5.3.x
*
* #var array
*/
public static $timezones = array(
"Africa/Abidjan",
"Africa/Accra",
"Africa/Addis_Ababa",
"Africa/Algiers",
...
...
"Zulu"
);
}
Using the function requireDefaultRecords in the DataObject - this is called during every dev/build.
Note: First check if the option exists to prevent duplicates as this will be called every time you dev build.
class Configuration extends DataObject {
private static $db = array(
'Option' => 'Varchar',
'Value' => 'Varchar'
);
private static $summary_fields = array(
'Option' => 'Option',
'Value' => 'Value',
);
function requireDefaultRecords() {
parent::requireDefaultRecords();
$arrOptions = array(
'Option1' => 'Value1',
'Option2' => 'Value2',
'Option3' => 'Value3',
);
foreach ($arrOptions as $strOption => $strValue) {
if (!$configuration = Configuration::get()->filter('Option',$strOption)->first())
$configuration = Configuration::create(array('Option' => $strOption));
$configuration->Value = $strValue;
$configuration->write();
}
}
}
One final comment is that there is a module for SiteConfig which is used by SilverStripe, most modules and where I would recommend you put configuration values like this instead.
If you do choose SiteConfig then please see the function populateDefaults and documentation for it's use, this is an example...
/**
* Sets the Date field to the current date.
*/
public function populateDefaults() {
$this->Date = date('Y-m-d');
parent::populateDefaults();
}
(if the above is used in an extensions it might need $this->owner->Date instead of $this->Date)
The above function isn't needed if all the values are static, instead it will read them just from this array (again within DataObject)
public static $defaults = array(
'Option1' => 'Value1',
'Option2' => 'Value2'
);
This works on any DataObject as well, but as SiteConfig manages one record and this populates that record once upon creation this is much more convenient for to use instead of requireDefaultRecords.
I'm Using cakePHP 2.3.8
I have two tables: application, computer_application. The relationship is one application hasMany computer_application, foreign key is application_id
in my ComputerApplication model:
class ComputerApplication extends AppModel{
public $name = "ComputerApplication";
public $useTable = "computer_application";
var $belongsTo = array(
'Computer' => array(
'className' => 'Computer',
'foreignKey' => 'computer_id',
'dependent' => true
),
'Application' => array(
'className' => 'Application',
'foreignKey' => 'application_id',
'dependent' => true
)
);
}
In my ComputerApplication controller. HERE I INITIALIZE THE POPULATION OF DROPDOWN in **add** function
public function add($id=null) {
if (!$id) {
throw new NotFoundException(__('Invalid post'));
}
$this->set('computerApplications',
$this->ComputerApplication->Application->find('list',
array('fields' => array('description') ) ) );
}
Now In my Add View
echo $this->Form->create("computerApplication");
echo $this->Form->input('application_id',array('empty'=>''));
echo $this->Form->end('Save Post');
My problem is that it won't populate the select input. This is the first time I used 2 words in table [computer_application] using cake since I don't have problem populating other table with just one word. Just help me identify which I need to tweak for it to populate.
$this->set('applications', ...
and not
$this->set('computerApplications', ...
I have a table, TableModule, with 2 foreign keys, let's say fk1 and fk2.
fk1 goes to pk1 in table Table 1
fk2 goes to pk2 in table Table 2
I created a module. let's say, Module, which uses the TableModule (the one with the fk's)
I want to create 4 filters for those fk: 2 input text and 2 dropdowns. In particular, I want to create two filters per fk. This is:
For fk1 I would get:
-InputText
-Dropdown (choice in propel)
For fk2 I would get:
-InputText
-Dropdown (choice in propel)
Of course, this would show the results of Table1 and Table2.
Now, in my config.yml I got:
...
filter:
display: [fk1, fk1TextFilter, fk2, fk2TextFilter]
...
This is: fk1 and fk2 would be filtered as dropdowns, The partials fk1TextFilter and fk2TextFilter must be customized for filtering using a text input.
Why I created those partials? Because I can't duplicate the fk in the config.yml!!
In lib/filter/table1/ModuleFormFilter I did (notice that is in table1):
public function configure()
{
$this->setWidgets(array(
'fk1' => new sfWidgetFormPropelChoice(array('model' => 'table1', 'add_empty' => true,)),
'fk1TextFilter' => new sfWidgetFormInput(),
'fk2' => new sfWidgetFormPropelChoice(array('model' => 'table2', 'add_empty' => true,)),
'fk2TextFilter' => new sfWidgetFormInput(),
));
$this->setValidators(array(
'fk1TextFilter' => new sfValidatorPropelChoice(array('model' => 'table1', 'column' => 'id', 'required' => false)),
'fk1' => new sfValidatorPropelChoice(array('model' => 'table1', 'column' => 'id', 'required' => false)),
'fk2TextFilter' => new sfValidatorPropelChoice(array('model' => 'table2', 'column' => 'id', 'required' => false)),
'fk2' => new sfValidatorPropelChoice(array('model' => 'table2', 'column' => 'id', 'required' => false)),
));
$this->validatorSchema->setPostValidator(
new sfValidatorPropelUnique(array('model' => 'table2', 'column' => array('fk2')))
);
$this->widgetSchema->setNameFormat('model[%s]');
$this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
}
This is: created 2 textInput and 2 dropdowns as stated earlier.
If I use -could be the inputtext or the dropdowns- just the fk this will work OK. the problem is that I can't duplicate the fk's. I can't do:
$this->setWidgets(array(
'fk1' => new sfWidgetFormPropelChoice(array('model' => 'table1', 'add_empty' => true,)),
'fk1' => new sfWidgetFormInput(),
'fk2' => new sfWidgetFormPropelChoice(array('model' => 'table2', 'add_empty' => true,)),
'fk2' => new sfWidgetFormInput(),
));
If I run the page I get:
You must define a "filterByfk1TextFilter" method in the ModelQuery class to be able to filter with the "fk1TextFilter" field.
I found some links (1, 2) but is not working for me. I don't have in the symfony docs concrete examples.
What I must created and how?
By now I have, in the same lib/filter/table1/ModuleFormFilter:
public function getFields()
{
$fields = parent::getFields();
$fields['fk1TextFilter'] = 'fk1TextFilter';
$fields['fk2TextFilter'] = 'fk2TextFilter';
return $fields;
}
public function addModelfk1TextFilterQuery($query, $field, $value)
{
//add your filter query!
//for example in your case
$rootAlias = $query->getRootAlias();
$query = ModelQuery::create()
->filterByfk1TextFilter()
->find();
//remember to return the $query!
return $query;
}
Is not working for me. Could you help me please??
For those of you using Doctrine, this is a simple extension on my 'User Profile' model to allow filtering by fields on the sfGuardUser model from sfDoctrineGuardPlugin.
My 'profile' class was called Member, and referenced sfGuardUser via a User relation via a user_id column.
Hope someone finds it useful!
class MemberFormFilter extends BaseMemberFormFilter {
public function configure() {
$this->setWidget('first_name', new sfWidgetFormInputText());
$this->setWidget('last_name', new sfWidgetFormInputText());
$this->setWidget('email_address', new sfWidgetFormInputText());
$this->setValidator('first_name', new sfValidatorString(array('required' => false)));
$this->setValidator('last_name', new sfValidatorString(array('required' => false)));
$this->setValidator('email_address', new sfValidatorString(array('required' => false)));
}
public function getFields() {
return array_merge(parent::getFields(), array(
'first_name' => 'Text',
'last_name' => 'Text',
'email_address' => 'Text'
));
}
public function addFirstNameColumnQuery(Doctrine_Query $query, $field, $value) {
$rootAlias = $query->getRootAlias();
return $query->leftJoin($rootAlias.'.User u')
->where('u.first_name LIKE ?', "%$value%");
}
public function addLastNameColumnQuery(Doctrine_Query $query, $field, $value) {
$rootAlias = $query->getRootAlias();
return $query->leftJoin($rootAlias.'.User u')
->where('u.last_name LIKE ?', "%$value%");
}
public function addEmailAddressColumnQuery(Doctrine_Query $query, $field, $value) {
$rootAlias = $query->getRootAlias();
return $query->leftJoin($rootAlias.'.User u')
->where('u.email_address LIKE ?', "%$value%");
}
}
Black Magic:
There are many different ways. None worked for me, at least those in the links I posted.
Nevertheless, using: add[VirtualColumnName]ColumnCriteria allows you to customize filters.
In this case, after all the code I wrote (and changing addModelfk1TextFilterQuery()) just add:
public function addfk1TextFilterColumnCriteria($query, $field, $value)
{
//Here just put a query in propel, for ex:
$query = $query->useTableModel()
->filterByName("*$value*")
->endUse()
->find();
return $query;
}
Hoping that this will help some others!
Mini Edit: do some echoes to $field and $values for clarification
I think it would be better putting addWhere instead of where on each of the "addXColumnQuery functions, because this way will preserve and combine the other filters set.
I seem to be having a problem with fixtures in Yii. The problem seems to be the following,
public $fixtures=array('projects'=>'Project');
The model Project exists and I have the fixtures in a file name tbl_project.php in the fixtures folder of tests and my table name is called tbl_project. Inside the fixtures file is the following.
return array(
'project1' => array(
'name' => 'Test Project 1',
'description' => 'This is test project 1',
'create_time' => '',
'create_user_id' => '',
'update_time' => '',
'update_user_id' => '',
),
'project2' => array(
'name' => 'Test Project 2',
'description' => 'This is test project 2',
'create_time' => '',
'create_user_id' => '',
'update_time' => '',
'update_user_id' => '',
),
'project3' => array(
'name' => 'Test Project 3',
'description' => 'This is test project 3',
'create_time' => '',
'create_user_id' => '',
'update_time' => '',
'update_user_id' => '',
),
);
This is actually from the book "Agile Web Application Development with Yii". When I run the test case I get the following with no test result information.
PHPUnit 3.6.10 by Sebastian Bergmann.
Configuration read from ETC/protected/tests/phpunit.xml
If I remove the fixtures array from the top I get the following.
Time: 0 seconds, Memory: 9.25Mb
There was 1 error:
1) ProjectTest::testRead
Exception: Unknown method 'projects' for class 'ProjectTest'.
Which obviously makes sense. I dont know what Im doing wrong.
Make sure the test class looks like this
class ProjectTest extends CDbTestCase{
protected $fixtures = array(
'projects' => 'Project',
);
public function testRead(){
$receivedProject = $this->projects('Project1');
$this->assertTrue($receivedProject instanceof Project);
$this->assertEquals($receivedProject->name,'test 1');
}
...`
Check the fixture configuration in protected/config/test.php ... Should look like ...
...
'components'=>array(
'fixture'=>array(
'class'=>'system.test.CDbFixtureManager',
),
'db'=>array(
'connectionString' =>'mysql:host=localhost;dbname=your_db_name',
'emulatePrepare' => true,
'username' => 'username',
'password' => 'passwd',
'charset' => 'utf8',
),
....
Ultimately check the permissions on the fixture file making sure it can be read
Also be sure you are calling parents setUp() method in your own setUp()
class SomeTest extends CDbTestCase {
public $fixtures = array(
'somes' => 'Some',
);
protected function setUp() {
parent::setUp();
// your code....
}
// your tests .......................
}
Is your test class deriven from CDbTestCase instead of CTestCase?
your Test Class should look something like this:
class ProjectTest extends CDbTestCase{
protected $fixtures = array(
'projects' => 'Project',
);
public function testRead(){
$receivedProject = $this->projects('Project1');
$this->assertTrue($receivedProject instanceof Project);
$this->assertEquals($receivedProject->name,'test 1');
}
class ProjectTest extends CDbTestCase
{
public function testCreate()
{
//CREATE a new Project
$newProject=new Project;
$newProjectName = 'Test Project Creation';
$newProject->setAttributes(array(
'name' => $newProjectName,
'description' => 'This is a test for new project creation',
'createTime' => '2009-09-09 00:00:00',
'createUser' => '1',
'updateTime' => '2009-09-09 00:00:00',
'updateUser' => '1',
)
);
$this->assertTrue($newProject->save(false));
//READ back the newly created Project to ensure the creation worked
$retrievedProject=Project::model()->findByPk($newProject->id);
$this->assertTrue($retrievedProject instanceof Project);
$this->assertEquals($newProjectName,$retrievedProject->name);
}
public function testRead()
{
$retrievedProject = $this->projects('project1');
$this->assertTrue($retrievedProject instanceof Project);
$this->assertEquals('Test Project 1',$retrievedProject->name);
}
public function testUpdate()
{
$project = $this->projects('project2');
$updatedProjectName = 'Updated Test Project 2';
$project->name = $updatedProjectName;
$this->assertTrue($project->save(false));
//read back the record again to ensure the update worked
$updatedProject=Project::model()->findByPk($project->id);
$this->assertTrue($updatedProject instanceof Project);
$this->assertEquals($updatedProjectName,$updatedProject->name);
}
public function testDelete()
{
$project = $this->projects('project2');
$savedProjectId = $project->id;
$this->assertTrue($project->delete());
$deletedProject=Project::model()->findByPk($savedProjectId);
$this->assertEquals(NULL,$deletedProject);
}
public function testGetUserOptions()
{
$project = $this->projects('project1');
$options = $project->userOptions;
$this->assertTrue(is_array($options));
$this->assertTrue(count($options) > 0);
}
public $fixtures=array(
'projects'=>'Project',
'users'=>'User',
'projUsrAssign'=>':tbl_project_user_assignment',
);
}
make sure that setup come with its parent
<i>public function setUp() {
parent::setUp();
}</i>