Yii unit-tests fixtures not accessible in tests - php

config/test.php
'components'=>array(
'fixture'=>array(
'class'=>'system.test.CDbFxtureManager'
),
),
tests/unit/EntityTest.php (extends CDbTestCase)
public $fixtures = array('entities'=>'Entity'),
tests/fixtures/Entity.php
return array(
'entity1'=>array('slug'=>'slug1', 'title'=>'title1'),
'entity2'=>array('slug'=>'slug2', 'title'=>'title2'),
);
Now, in EntityTest class I try to get my entities
$entities = $this->entities;
$entity = $this->entities('entity1');
Output is 'Unknown property "entities" for class "EntityTest"'. Testing class is 'Entity', table name in database is 'tbl_entity', 'tablePrefix' option of 'CDbConnection' component is set to 'tbl_'

Let's go necroposting! :)
Your problem is the naming of the file in fixtures. You mention that it's a tests/fixtures/Entity.php, which should be after the name of your Model, class, but in fact, files in fixtures folder should be named after tableNames of your Models. I believe the real table name for your Entity model is entity (all in lower case), so just rename the file. I had the similar problem several times, and the solution is clearly stated in the documentation: "A fixture is represented as a PHP script whose name (without suffix) is the same as the table name (if schema name is needed, it should be prefixed to the table name)."

Also try this if you are using setUp() method. Just call parent::setUp(), when you are redefining it with your own method.

$entity = $this->entities['entity1']; // returns an array
$entity = $this->entities('entity1'); // returns an active record

Take a look on this solution Yii Fixtures Issue? I also came up with the same problem. I overlook the class to extend, make sure to extend the CDbTestCase.

Related

Multiple Fixture Classes results in Persist errors like Duplicate Entry and Entity not persisted Symfony 5

Versions:
PHP 8.1
Worked in Symfony 5.3 finding behavior in Symfony 5.4.
"doctrine/doctrine-fixtures-bundle": "^3.4"
"doctrine/doctrine-bundle": "^2.2"
"doctrine/orm": "^2.8"
General Problem:
Multiple Fixture classes causes errors with references from other fixture classes
Expectations from old 5.3 Project:
On the old project I am able to make tons of separate Fixtures classes and run them all with DependentFixturesInterface and use the references already created (persisted) to then create the relations needed for the other fixtures.
Example:
I create Users first and then Teams, for each Team these is a ManyToOne $createdUser column that relates to a User that creates it. But I can make a UserFixtures class and safe the references (as seen in symfony casts etc.) then runs the TeamFixtures class to use the references in UserFixtures for TeamFixtures (all standard understanding)
Behavior in new 5.4 project:
In the new project I am no way able to create multiple fixture classes. In the same exact example above when I try to create the same relationship I get the follow error
A new entity was found through the relationship 'App\Entity\Team#createdUser' that was not configured to cascade persist operations for entity: App\Entity\User#whateveruser. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'App\Entity\User#__toString()' to get a clue.
So then I listen to the exception and add cascade={"persist"} to the entity relation, run the fixtures again and I get the following error:
Duplicate entry *** for key ****
To me this means somehow it is not correctly persisting the Users in the first place or I am completely off as to how Doctrine works.
This is the loader in my main fixture class
public function loadData(): void
{
$this->generateMockIntervals();
// Users, Contacts
$this->setGroup(self::TEST, 3)->createMany('generateFakeUser', [$this->testPasswordHash, self::TEST_EMAIL_ITERATED]);
$this->setGroup(self::DUMMY, 500)->createMany('generateFakeUser', [$this->dummyPasswordHashed]);
$this->setGroup(self::teamGroupName(), 100)->createMany('generateTeams');
$configArray = array(
MemberInterface::MEMBERS => array(
self::GEN => [$this, 'generateUserMembers'],
self::RANGE => 20,
self::R => self::REF_TYPES[0],
),
);
if (!empty($configArray)) {
$this->groupForAll($configArray);
} else {
$this->pr("Class %s not configured yet", static::class);
}
}
The createMany function loops through each item and creates the new User references and saves it in the reference Repo (straight from SymfonyCasts).
groupAll does the same thing but loops through the references that is configured for each new reference key. I super enhanced symfony casts createMany function. If you have not seen it this is the function that EVERY entity is passed to.
protected function manageReference($entity, $groupName)
{
if (null === $entity) {
throw new \LogicException('Did you forget to return the entity object from your callback to BaseFixture::createMany()?');
}
$this->manager->persist($entity);
// store for usage later as App\Entity\ClassName_#COUNT#
$storage = sprintf('%s_%d', $groupName, $this->i);
$this->addReference($storage, $entity);
}
ONLY DIFFERENCE between 5.3 project and 5.4 project:
The only major difference I can see that is causing this problem is that in my old (5.3) project I had ALL Bidirectional variables built into the entity. In 5.4 I removed ALL/MOST of the Bidirectional relationships for my entities in theory to generate less queries.
Basically if I were to take out this part here
$this->setGroup(self::teamGroupName(), 100)->createMany('generateTeams');
$configArray = array(
MemberInterface::MEMBERS => array(
self::GEN => [$this, 'generateUserMembers'],
self::RANGE => 20,
self::R => self::REF_TYPES[0],
),
);
if (!empty($configArray)) {
$this->groupForAll($configArray);
} else {
$this->pr("Class %s not configured yet", static::class);
}
And put it into a new fixture I start getting the Duplicate Entry and "must persist" errors. But as you can see I am Persisting every single entity and I am flushing every 25 entities are Peristed

kohana 3.2 creating a model for a table with underscore in its name

I am having trouble in creating a model for a table named product_details, and after searching sometimes, I found this answer
Kohana 3.2: Calling model with underscore in name
acoording on the answer, I resorted to the following approach. I created Model_Product_Details then i declared protected $_table_name = 'product_details'; and then saved it in application/classes/models/product_detail.php
And the I called it in a controller with this code:
$product_details = ORM::factory(product_detail);
But damn, it didnt work. the error returned was ErrorException [ Fatal Error ]: Class 'Model_Product_detail' not found
I tried renaming the table, model and file name by removing the underscore and it worked. But the thing is the database im using is from legacy system so i cant change its name. I hope could give me help immediately.
The problem you describe is not a missing or misnamend table, but object name.
When underscores are used in the models name, after the Model_ part, every underscore is expected as a folder. For the class with name Model_Product_Details Kohana expects the file details.php to be in the folder models/product/details.php.
protected $_table_name = 'product_details';
should point to the table on a correct way
In this case you need to rename your model to productDetails. Kohana searching this model in the model/product sub directory. See this here: link.
"CamelCased class names should be used when it is undesirable to create a new directory level."
After analyzing the answer on the link I provided for the third time(I think), referring the approach I've done, I just have to remove the underscore from the file name and the model name only.
So this is the way how to fix it. Lets say you have a table named product_details. You have to create Model_ProductDetail then in the inside, declare protected $_table_name = 'product_details'; then save it as productDetail.php

Data can't save after alter the table in yii

I new in yii framework. i create an application in yii framework. i created model, controller, views using gii. After that i alter database table. I deleted 2 column and add 3 new columns. After that overwrite the model using the gii. But when i am trying to save into that table it show property(which was old column that I deleted) is not defined. Plz provide me a solution for this.
You need to define all columns in the validation rules() method in your model, have a look and make sure that you have defined a rule for every column in the table there, for example (if it's a string with max length 128):
public function rules()
{
return array(
...
array('myField', 'length', 'max'=>128),
...
);
}
See some info about validation rules.
Also, for forms if you're using CActiveForm widget and calling fields like so:
echo $form->labelEx($model,'myField');
echo $form->textField($model,'myField');
Then you'll need to make sure that a label is defined in the model too, in the attributeLabels() method, for example:
public function attributeLabels()
{
return array(
...
'myField'=>'My Field',
...
);
}
Lastly, if you want the field to be searchable, you'll need to add a statement to the search() method in the model, for example:
public function search()
{
...
$criteria->compare('myField',$this->myField);
...
}
Make sure you have all of those elements present and you shouldn't get the '* is not defined' error.
Also, if you're using schema caching in your main config file, you'll have to clear your cache before the app will see your new database structure.
Your changes should also be set at the Views since there are forms, widgets using the old properties !! (for this exact save issue, you will need to fix _form.php which is the partial responsible from your model Save & Update actions.
You can either do the same as you did with the model: (regenerate it using gii) or you can edit it manually (i recommend you get used to this since in the future you will have code you don't want to loose just because of altering a column name. simple Find & edit in most of the text editors will do the job).
May be you need to read a bit more about how MVC works in general & in Yii in special
This is because you are using schema-cache. Your table schema is cached in Yii. You need to flush AR cache. Either flush full schema cache or use
Yii::app()->db->schema->getTable('tablename', true); in start of your action. This will update model schema-cache.

Cakephp and database with uncomon structure

how can I access any table from database in my model?
For example, I have Indexcontroller and code inside it:
$results = $this->Index->query("SELECT COUNT(*) FROM my_own_table");
Error: Database table indices for model Index was not found.
So, as I understand, I can access only table with naming related to model/controller name. But what to do if I can't modify the table naming and I want to access it's data?
You're not limited to using a model that's directly associated with your controller (this is just default behaviour); you can use any model.
To achieve what you want, create a new model for this table, eg. MyOwnTable, and in your controller, you can add this property to the class:
public $uses = array('Index', 'MyOwnTable');
Now you can access MyOwnTable using CakePHP's built in ActiveRecord functionality:
$results = $this->MyOwnTable->find('count');
If you have other tables you want to access, simply create models for those and add them to the $uses property. (You can also use $this->loadModel('Model') inside the action if you prefer).
If you have a table name that isn't very readable (eg. my_tb_own_1_x or some such), you can call the model class something human readable (eg. MyTable), and add the $useTable property to the model:
public $useTable = 'my_tb_own_1_x';
/* and change the default primary key if you have an unusual one */
public $primaryKey = 'my_tb_own_1_x_idx_pk';
See the CakePHP manual for more info on how to change default model and controller behaviour:
1.3 - Model Attributes
2.0 - Model Attributes
1.3 - Controller Attributes
2.0 - Controller Attributes
Nope. You can access different tables. However, CakePHP stumbles over the fact that the table that is associated by default to the Index model doesn't exist.
In other words, the model Index expects a table 'indices' to exist (and an error is thrown when it doesn't). You can do one of two things:
Create a table indices
Add the following to your Index model: var $useTable = false;
If you have any use for an indices table I'd go with option 1. If you're not going to use the indices table, go with option 2.
If you go with either step 1 or 2, your example should start working.

Creating a PHPUnit mocked model uses default database instead of test in CakePHP

I am testing a model in CakePHP 2 and have mocked a model like this:
$this->User = $this->getMock('User', array(
'_saveUploadedFile',
'_removeUploadedFile',
));
$this->User->expects($this->any())
->method('_saveUploadedFile')
->with($data, Configure::read('App.myDirectory'), true);
->will($this->returnValue(true));
$this->User->expects($this->any())
->method('_removeUploadedFile')
->with($data, Configure::read('App.myDirectory'))
->will($this->returnValue(true));
Since any operation with the database raises the following error:
"Database table mock__user_b6241a4cs for model User was not found."
I redefined the model information:
$this->User->alias = 'User';
$this->User->useTable = 'users';
Now the test works well, but it's using the $default database in database.php instead of $test. What can be happening?
Why the database configuration for testing changes when using mocked objects? Could it be related to database permissions that causes the mocked object not being able to create its custom tables?
Thanks!
I finally solved the problem by passing the correct parameters to the model constructor in getMock() third agument:
$this->User = $this->getMock('User',
array('_saveUploadedFile', '_removeUploadedFile'),
array(false, 'users', 'test')
);
Applying what is said in Stubs section of PHPUnit documentation, this third argument indicates that I want to use the users table and the test datasource.
I have to keep the redefinition of the alias property though:
$this->User->alias = 'User';
because a simple $this->User->read(null, 1) raises an error saying that 'User.a_column' couldn't be found.
Thanks to José Lorenzo.
I haven't encountered this specific problem before, but I'm curious if you've tried setting the specific connection you want. So the same way you set alias and useTable:
$this->User->useDbConfig = 'test';

Categories