$this->getDoctrine()
->getRepository('AppBundle:CAP270ColisProduits')
->findBy(array('idcolis' => array($listedesidcolis)));
with $listedesidcolis = '49','55'
it return only one result
if i do:
$this->getDoctrine()
->getRepository('AppBundle:CAP270ColisProduits')
->findBy(array('idcolis' => array('49','55')));
I ve got my two results
Related
I have a simple test where I am searching on '.shop' elements, returning two of them, and then I want to get the first element and look at an embedded element : '.shop__title'.
See code :
describe('Shop Page', () => {
let wrapper
let store = createStore(reducers, mockStoreData);
beforeEach(() => {
wrapper = mount(
<Provider store={store}>
<Dashboard />
</Provider>,
);
});
afterEach(() => {
wrapper.unmount();
});
it('test ', () => {
let elems = wrapper.find('.shop');
expect(elems.length).toBe(2); //yes, i have two shops!
let e = elems.get(0);
e.find('.shop__title') //find function does not exist!!!
})
});
I am not quite sure what this 'e' element is (the first element in the array that I am looking at), but my IDE shows me this :
What sort of object is this? How do I get the 'find' and 'simulate' functions working on this element?
You need to use at instead of get
let e = elems.at(0);
e.find('.shop__title') //find function does not exist!!!
The problem is get returns you the ReactElement but at returns a ShallowWrapper which has the find method.
I have created a service where I get all the elements of my database:
Service
getElements() {
return (this.eleList= this.firebase.list("elements"));
}
Component
eleList: Element[];
getBets() {
return this.databaseService
.getElements()
.snapshotChanges()
.subscribe(item => {
this.eleList= [];
item.forEach(element => {
let x = element.payload.toJSON();
x["$key"] = element.key;
this.eleList.push(x as Element);
});
});
}
With these two methods what I do is to store all my elements in this.eleList.
I would like to create a new method, named filterByName(name), where I would update this.eleList to an array which contains only the ones that contain namein the object, for example, this.eleList[1].name
I do not know if Firebase provides a way to short it, or I need to use Javascript/Typescript for it.
Firebase takes full advantage of the observables and async pipes.
You should take advantage of that :
eleList$ = new Subject();
getElements() {
this.this.firebase.list("elements")
.pipe(take(1))
.subscribe(list => this.eleList$.next(list));
}
getBets() {
this.databaseService
.getElements()
.snapshotChanges()
.pipe(
map(item => items.map(element => ({
...element.payload.toJSON(),
'$key': element.key
})))
)
.subscribe(elements => this.eleList$.next(list));
}
Now for a sorted list :
sortedList$ = this.eleList$.pipe(
map(elements => elements.filter(element => !!element.name))
);
I have an entity, call it Stones and Stones has a ManyToMany relationship with Attributes.
So I query the entity to get the Stones and then I hydrate this to convert it into an array.
$result = $this->stoneRepository->find($stone_id);
if ( ! $result )
{
return false;
}
$resultArray = $this->doctrineHydrator->extract($result);
This works fine for the Stone entity however I noticed that the join (Attributes) remain as objects.
array (size=12)
'id' => int 1
'name' => string 'Agate' (length=5)
'title' => string 'Title' (length=5)
'attribute' =>
array (size=5)
0 =>
object(Stone\Entity\StAttribute)[1935]
private 'id' => int 2
private 'name' => string 'Hay fevor' (length=9)
private 'state' => boolean true
private 'created' => null
private 'modified' => null
1 =>
object(Stone\Entity\StAttribute)[1936]
private 'id' => int 15
private 'name' => string 'Libra' (length=5)
private 'state' => boolean true
private 'created' => null
private 'modified' => null
2 =>
etc.
What is the process to hydrate the Attribute objects?
Hydration is populating an object (entity) using an array which is opposite of the extraction.
Since you want the resultset in array format, you should prevent unnecessary hydration and extraction process which already occurs in the ORM level under the hood.
Try to use Query Builder Api instead of built-in find() method of the entity repository. This is not a single-line but really straightforward and faster solution, it should work:
$qb = $this->stoneRepository->createQueryBuilder('S');
$query = $qb->addSelect('A')
->leftJoin('S.attribute', 'A')
->where('S.id = :sid')
->setParameter('sid', (int) $stone_id)
->getQuery();
$resultArray = $query->getOneOrNullResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
This way, you will also prevent running additional SQL queries against database to fetch associated entities. (StAttribute in your case)
I thought I would follow up on this to show how this can be resolved using a CustomStrategy.
By far the easiest and fastest method was suggested by foozy. What I like about the solution is that when I use hydration in ApiGility for instance I can build custom queries which will produce the desired result in a very few lines of code.
The other solution I was working on was to add a custom strategy:
<?php
namespace Api\V1\Rest\Stone;
use DoctrineModule\Stdlib\Hydrator\Strategy\AbstractCollectionStrategy;
use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;
class CustomStrategy extends AbstractCollectionStrategy
{
public function __construct($hydrator)
{
$this->hydrator = $hydrator;
}
/**
* #param mixed $values
* #return array|mixed
*/
public function extract($values)
{
$returnArray = [];
foreach ($values AS $value)
{
$returnArray[] = $this->hydrator->extract($value);
}
return $returnArray;
}
/**
* #param mixed $values
* #return mixed
*/
public function hydrate($values)
{
$returnArray = [];
foreach ($values AS $value )
{
$returnArray[] = $this->hydrator->hydrate($value);
}
return $returnArray;
}
}
Then from the service side I add various strategies to the hydrator like so:
$result = $this->stoneRepository->find($stone_id);
$this->doctrineHydrator->addStrategy("product", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("attribute", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("image", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("related", new CustomStrategy( $this->doctrineHydrator ) );
$resultArray = $this->doctrineHydrator->extract($result);
After which I created a custom entity:
<?php
namespace Api\V1\Rest\Stone;
class StoneEntity
{
public $id;
public $name;
public $description;
public $code;
public $attribute;
public $product;
public $image;
public function getArrayCopy()
{
return array(
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'code' => $this->code,
'attribute' => $this->attribute,
'product' => $this->product,
'image' => $this->image
);
}
public function exchangeArray(array $array)
{
$this->id = $array['id'];
$this->name = $array['name'];
$this->description = $array['description'];
$this->code = $array['code'];
$this->attribute = $array['attribute'];
$this->product = $array['product'];
$this->image = $array['image'];
}
}
And the final part is to exchange the returned data with the custom entity:
$entity = new StoneEntity();
$entity->exchangeArray($resultArray);
And finally to return the result:
return $entity;
To be honest, the above is just too long winded and my final solution as per the suggestion by foozy was this:
public function fetchOne($stone_id)
{
$qb = $this->stoneRepository->createQueryBuilder('S');
$query = $qb->addSelect('A','P','I','C')
->leftJoin('S.attribute', 'A')
->innerJoin('A.category', 'C')
->innerJoin('S.product' , 'P')
->innerJoin('S.image' , 'I')
->where('S.id = :sid')
->setParameter('sid', (int) $stone_id)
->getQuery();
$resultArray = $query->getOneOrNullResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
if ( ! $resultArray )
{
return false;
}
return $resultArray;
}
I'm new to CakePHP, and I just started writing my first tests. Usually doing Ruby on Rails, my approach to testing a Controller::create action would be to call the create action, and then comparing the number of models before and after that call, making sure it increased by one.
Would anyone test this any other way?
Is there an easy (builtin) way to access models from a ControllerTest in CakePHP? I couldn't find anything in the source, and accessing it through the Controller seems wrong.
I ended up doing something like this:
class AbstractControllerTestCase extends ControllerTestCase {
/**
* Load models, to be used like $this->DummyModel->[...]
* #param array
*/
public function loadModels() {
$models = func_get_args();
foreach ($models as $modelClass) {
$name = $modelClass . 'Model';
if(!isset($this->{$name})) {
$this->{$name} = ClassRegistry::init(array(
'class' => $modelClass, 'alias' => $modelClass
));
}
}
}
}
Then my tests inherit from AbstractControllerTestCase, call $this->loadModels('User'); in setUp and can do something like this in the test:
$countBefore = $this->UserModel->find('count');
// call the action with POST params
$countAfter = $this->UserModel->find('count');
$this->assertEquals($countAfter, $countBefore + 1);
Note that I'm new to CakePHP but came here with this question. Here's what I ended up doing.
I got my idea from #amiuhle, but I just do it manually in setUp, like how they mention in the model tests at http://book.cakephp.org/2.0/en/development/testing.html.
public function setUp() {
$this->Signup = ClassRegistry::init('Signup');
}
public function testMyTestXYZ() {
$data = array('first_name' => 'name');
$countBefore = $this->Signup->find('count');
$result = $this->testAction('/signups/add',
array(
'data' => array(
'Signup' => $data)
)
);
$countAfter = $this->Signup->find('count');
$this->assertEquals($countAfter, $countBefore + 1);
}
I am not sure why it is necessary to test how many times a model is called or instantiated from the controller action.
So, if I was testing Controller::create... my ControllerTest would contain something like:
testCreate(){
$result = $this->testAction('/controller/create');
if(!strpos($result,'form')){
$this->assertFalse(true);
}
$data = array(
'Article' => array(
'user_id' => 1,
'published' => 1,
'slug' => 'new-article',
'title' => 'New Article',
'body' => 'New Body'
)
);
$result = $this->testAction(
'/controller/create',
array('data' => $data, 'method' => 'post')
);
if(!strpos($result,'Record has been successfully created')){
$this->assertFalse(true);
}
}
The main things you want to test for is whether you are getting the right output for the input. And you can use xDebug profiler to easily find out what classes get instnantiated in a particular action and even how many times. There is no need to test for that manually!
how to test such a method:
public function add() {
if (!empty($this->request->data)) {
$this->Contest->create();
if ($this->Contest->saveAll($this->request->data)) {
$contestStage['name'] = 'First - ' . $this->request->data['Contest']['name'];
$contestStage['contest_id'] = $this->Contest->id;
if ($this->Contest->ContestStage->save($contestStage)) {
$this->setMessage(__ADD_OK, 'Konkurs');
$this->redirect(array(
'action' => 'view',
$this->Contest->id
));
} else {
$this->setMessage(__ADD_ERROR, 'Konkurs');
}
} else {
$this->setMessage(__ADD_ERROR, 'Konkurs');
}
}
}
my test method:
public function testAdd() {
$this->generateWithAuth(self::ADMIN); // genereting controller here
$url = $this->getUrl('add');
$options2 = array(
'method' => 'post',
'data' => array(
'Contest' => array(
'id' => 3,
'owner_id' => 1,
'name' => 'Testing',
'created' => '2012-11-16 12:02:33.946',
),
),
);
$this->testAction($url, $options2);
$this->assertArrayHasKey('Location', $this->headers, 'No redirection');
$this->assertEquals($this->Contest->hasAny(array('Contest.name' => 'Testing')), true);
$messages = Set::extract('{flash}.message', CakeSession::read('Message'));
}
what i receive is
PDOEXCEPTION
SQLSTATE[23505]: Unique violation: 7 BŁĄD: double key value violates a constraint
uniqueness "contest_stages_pkey" DETAIL: Key (id)=(1) alredy exists.
Because it's true i have a contestStage with id=1
why its not using next one ;<
Its kinda strange that Cakephp does not document how to test that well.
The problem is that your inserting the Contest id twice. You should make sure that the db that your using has a test prefix (or whatever you like) and clear the test tables.
As an alternative, you could use fixtures instead. The data produces a much better test case as it pre populates the data for you so that you know whats in the db at any time. Still make sure to use a prefix, I made the mistake once of not doing that and it blew away my entire db every time
Good luck