change parameter value of dependent method in phpunit - php

i wrote a sample test case for collection like class but weird thing about this is in my testAdd method that i add a item in CustomCollectionService and it changed my parameter too. how can this happend?
class CustomCollectionService
{
/**
* #var Collection $collection
*/
public $collection;
public function makeCollection($arr)
{
$this->collection = collect($arr);
}
/**
* #param Collection $collection
*/
public function setCollection(Collection $collection): void
{
$this->collection = $collection;
}
/**
* #return mixed
*/
public function getCollection()
{
return $this->collection;
}
public function add($item)
{
return $this->collection->add($item);
}
}
and this is my test:
class CustomCollectionTest extends TestCase
{
public $collectionService;
public $collection;
protected function setUp(): void
{
$this->collectionService = new CustomCollectionService();
}
public function testCollectionCreator()
{
$arr = ['sina','1',5];
$this->assertIsArray($arr);
return $arr;
}
/**
* #param $arr
* #depends testCollectionCreator
*/
public function testAction($arr)
{
$this->collectionService->makeCollection($arr);
$this->assertIsArray($this->collectionService->getCollection()->toArray());
return $this->collectionService->getCollection();
}
/**
* #depends testAction
*/
public function testAdd($col)
{
$actualCount = $col->count();
$this->collectionService->setCollection($col);
$manipulatedCollection = $this->collectionService->add(['xx']);
dump($actualCount); // 3
dump($col->count()); //4
$this->assertEquals($actualCount+1, $manipulatedCollection->count());
}
}

Because it is an object. So when you pass the $col object to the CollectionService and call the add method within the CollectionService, it is still the $col object from your test method that is being used.

Related

ArgumentCountError: Too few arguments to function

I am testing my model in isolation and keep getting this error. I thought perhaps it is my assert function but I want to check if what list I created a new instance with is the same as the list found.
Here is my model:
class ArchiveShoppingListModel
{
/**
* #var string
*/
private string $list;
/**
* ArchiveShoppingListModel constructor.
*
* #param string $list
*/
public function __construct(string $list)
{
$this->list = $list;
}
/**
* #return string
*/
public function getList(): string
{
return $this->list;
}
}
And here is my test:
class ArchiveShoppingListModelTest extends TestCase
{
/**
* #param string $list
* #return void
*/
public function test(string $list): void
{
$model = new ArchiveShoppingListModel('groceries');
$this->assertSame($list, $model->getList());
}
}
Why you make $list as a parameter in unit test? If you want to check by unit test you'd better use
public function test(): void
{
$list = ....; // the list you expect
$model = new ArchiveShoppingListModel('groceries');
$this->assertSame($list, $model->getList());
}

PhpStorm dynamic type hinting class property

I'm using a builder pattern to create an object, call methods, and return back to the calling object.
class Caller{
public function invoke() {
new Builder($this)->setColor('red')->setSize(5)-> // need typehint for Caller to return here
}
public function next() {
}
}
class Builder{
/**
* #var ????
*/
private $caller;
/**
* #param ???? $caller
*/
public function __construct($caller) {
$this->caller = $caller;
}
public function setColor($color) {
$this->color = $color;
return $this;
}
/**
* #param int $size
* #return ????
*/
public function setSize($size) {
$this->size = $size;
return $this->caller;
}
}
There is a way to invoke a parent method and return the child typehints by specifying $this as the return type in the parent class, but how can I reference a separate class type stored in $this->caller as the return type and get the typehints?

Zend Expressive API does not return contents of objects

I'm creating a small API, mostly for learning purposes, but, I might implement it into a project I'm working on. So far, I have installed the zend expressive skeleton application and set up my models and entities. I'm able to query the database and get results, but, when I return the results as a JSON Response, I can only see a list of empty arrays for each result. I would like to be able to return the actual objects that are being returned from the database instead of converting them to arrays.
HomePageHandler.php
<?php
declare(strict_types=1);
namespace App\Handler;
use App\Entity\Product;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response\JsonResponse;
use Zend\Expressive\Router;
use Zend\Expressive\Template\TemplateRendererInterface;
use App\Model\ProductModel;
class HomePageHandler implements RequestHandlerInterface
{
/** #var string */
private $containerName;
/** #var Router\RouterInterface */
private $router;
/** #var null|TemplateRendererInterface */
private $template;
private $productModel;
public function __construct(
string $containerName,
Router\RouterInterface $router,
?TemplateRendererInterface $template = null,
ProductModel $productModel
) {
$this->containerName = $containerName;
$this->router = $router;
$this->template = $template;
$this->productModel = $productModel;
}
public function handle(ServerRequestInterface $request) : ResponseInterface
{
$data = $this->productModel->fetchAllProducts();
return new JsonResponse([$data]);
//return new HtmlResponse($this->template->render('app::home-page', $data));
}
}
I'm expecting a JSON Response returned with a list of 18 "Product" entities. My results look like.
[[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]]
Let me know if there is any other code you would like to see.
Thanks in advance!
Edited with Product.php code
<?php
/**
* Created by PhpStorm.
* User: Brock H. Caldwell
* Date: 3/14/2019
* Time: 4:04 PM
*/
namespace App\Entity;
class Product
{
protected $id;
protected $picture;
protected $shortDescription;
protected $longDescription;
protected $dimensions;
protected $price;
protected $sold;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return mixed
*/
public function getPicture()
{
return $this->picture;
}
/**
* #param mixed $picture
*/
public function setPicture($picture)
{
$this->picture = $picture;
}
/**
* #return mixed
*/
public function getShortDescription()
{
return $this->shortDescription;
}
/**
* #param mixed $shortDescription
*/
public function setShortDescription($shortDescription)
{
$this->shortDescription = $shortDescription;
}
/**
* #return mixed
*/
public function getLongDescription()
{
return $this->longDescription;
}
/**
* #param mixed $longDescription
*/
public function setLongDescription($longDescription)
{
$this->longDescription = $longDescription;
}
/**
* #return mixed
*/
public function getDimensions()
{
return $this->dimensions;
}
/**
* #param mixed $dimensions
*/
public function setDimensions($dimensions)
{
$this->dimensions = $dimensions;
}
/**
* #return mixed
*/
public function getPrice()
{
return $this->price;
}
/**
* #param mixed $price
*/
public function setPrice($price)
{
$this->price = $price;
}
/**
* #return mixed
*/
public function getSold()
{
return $this->sold;
}
/**
* #param mixed $sold
*/
public function setSold($sold)
{
$this->sold = $sold;
}
public function exchangeArray($data)
{
$this->id = (!empty($data['id'])) ? $data['id'] : null;
$this->picture = (!empty($data['picture'])) ? $data['picture'] : null;
$this->shortDescription = (!empty($data['shortDescription'])) ? $data['shortDescription'] : null;
$this->longDescription = (!empty($data['longDescription'])) ? $data['longDescription'] : null;
$this->dimensions = (!empty($data['dimensions'])) ? $data['dimensions'] : null;
$this->price = (!empty($data['price'])) ? $data['price'] : null;
$this->sold = (!empty($data['sold'])) ? $data['sold'] : null;
}
}
You need to either make the properties public, or implement the JsonSerializable interface in your Product entity. All of its properties are protected, which is fine, but that means they aren't exposed when the object is JSON encoded.
Here are some brief examples:
class Example1 { protected $a = 1; }
class Example2 { public $b = 2; }
class Example3 implements JsonSerializable {
protected $c = 3;
public function jsonSerialize() {
return ['c' => $this->c];
}
}
echo json_encode([new Example1, new Example2, new Example3]);
The result:
[{},{"b":2},{"c":3}]
If you choose to implement JsonSerializable, exactly how you do it is up to you, but you just need a jsonSerialize() method that returns the properties you want in the JSON result in a format accessible to json_encode (an object with public properties or an array).

zf2 doctrine odm collection hydration

Hi everybody Im using doctrine ODM and have trouble with hydrator. I can't make extract on document with embed collection nor reference Class. the extract result for these class give me object and i really need to have them in array for rest module which is consumed by backbone implementation.
Here a example class :
Analyse.php Document
<?php
namespace Application\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\Common\Collections\Collection;
/**
* Application\Document\Analyse
*
* #ODM\Document(collection="analyse")
*/
class Analyse extends BaseDocument
{
/**
* #ODM\Id
*/
protected $id;
/**
* #ODM\Field(type="string")
*/
protected $nom;
/**
* #ODM\Field(type="string")
* #ODM\Index
*/
protected $alias;
/**
* #ODM\EmbedMany(targetDocument="ElementsAnalyse")
*/
protected $elements = array();
public function __construct()
{
parent::__construct();
$this->elements = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function setNom($nom)
{
$this->nom = $nom;
return $this;
}
public function getNom()
{
return $this->nom;
}
public function setAlias($alias)
{
$this->alias = $alias;
return $this;
}
public function getAlias()
{
return $this->alias;
}
public function addElements(Collection $elements)
{
foreach ($elements as $element) {
$this->elements->add($element);
}
}
public function removeElements(Collection $elements)
{
foreach ($elements as $item) {
$this->elements->removeElement($item);
}
}
public function getElements()
{
return $this->elements;
}
}
ElementAnalyse.php Collection
<?php
namespace Application\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\Common\Collections\Collection;
/**
* Application\Document\Valeurnormales
*
* #ODM\EmbeddedDocument
*
*/
class ElementsAnalyse
{
/**
* #ODM\Field(type="string")
*/
protected $nom;
/**
* #ODM\Field(type="string")
*/
protected $unite;
/**
* #ODM\EmbedMany(targetDocument="ValeurNormales")
*/
protected $valeurnormales = array();
/**
* #ODM\Field(type="string")
*/
protected $type;
public function __construct()
{
$this->valeurnormales = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set nom
*/
public function setNom($nom)
{
$this->nom = $nom;
return $this;
}
/**
* Get nom
*/
public function getNom()
{
return $this->nom;
}
/**
* Set unite
*/
public function setUnite($unite)
{
$this->unite = $unite;
return $this;
}
/**
* Get unite
*
* #return string
*/
public function getUnite()
{
return $this->unite;
}
/**
* add valeurnormales
*/
public function addValeurnormales(Collection $vn)
{
foreach ($vn as $item) {
$this->valeurnormales->add($item);
}
}
public function removeValeurnormales(Collection $vn)
{
foreach ($vn as $item) {
$this->valeurnormales->removeElement($item);
}
}
/**
* Get valeurnormales
*/
public function getValeurnormales()
{
return $this->valeurnormales;
}
/**
* Set type
*
* #param $type
* #return Analyse
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* #return Type
*/
public function getType()
{
return $this->type;
}
/**
* toArray function
*/
public function toArray()
{
return get_object_vars($this);
}
/**
* fromArray function
*
*/
public function fromArray(array $array)
{
$objects = $this->toArray();
foreach($array as $item => $value)
{
if(array_key_exists($item, $objects))
{
$this->$item = $value;
}
}
}
}
Here my getList Method
public function getList()
{
$hydrator = new DoctrineHydrator($entityManager, 'Application\Document\Analyse');
$service = $this->getAnalyseService();
$results = $service->findAll();
$data = $hydrator->extract($results);
return new JsonModel($data);
}
And obviously var_dump($data['elements']) return object Collection or proxy class
Can You help me. Anything will be appreciated it been 2 weeks i can't make it work.
Read about Hydrator Strategy out there but i don't knnow how to implement it.
Currently, the Doctrine ODM implementation does not provide recursion for embedded objects and references.
If you use var_dump() on your $hydrator->extract($results), you'll see that all your embeds/references are there in their original object format.
What you can do here is to use Zend\Stdlib\Hydrator\Strategy, and define your own logic for extraction/hydration. Doctrine extends Zend Framework 2's hydrators and strategies.

Netbeans Intellisense PHP Iterator Interface

I'm using Netbeans 6.9 and writing a PHP class that implements the Iterator interface. I would like to have the IDE offer Intellisense as I iterate over the items in my object. It seems to work for the Zend Framework as I've noticed that when iterating over a Zend_Db_Rowset I get intellisense for a Zend_DB_Row. For example, when I write:
foreach($rowset as $row) {
$row->delete();
}
When I type "$row->" Netbeans pops up its code hints for the member functions of Zend_Db_Row_Abstract. Unfortunately, I can't get this to work for my own code. Below is a sample I tried to get to work:
class Foo {
private $value;
/**
*
* #param string $value
*/
public function setValue($value) {
$this->value = $value;
}
/**
*
* #return string
*/
public function getValue() {
return $this->value;
}
}
class It implements Iterator {
private $data;
public function __construct($data) {
$this->data = $data;
}
/**
*
* #return Foo
*/
public function current() {
return current($this->data);
}
/**
*
* #return Foo
*/
public function key() {
return key($this->data);
}
/**
*
* #return Foo
*/
public function next() {
return next($this->data);
}
/**
*
* #return Foo
*/
public function rewind() {
return reset($this->data);
}
/**
*
* #return bool
*/
public function valid() {
return key($this->data) !== null;
}
}
$a = new Foo();
$b = new Foo();
$a->setValue('Hello');
$b->setValue('Bye');
$testData = array($a, $b);
$myIt = new It($testData);
foreach ($myIt as $obj) {
echo $obj->getValue();
}
Strangely the intellisense seems to think $obj is an object of type It when I want it to think (and it actually is) an object of type Foo.
Within the body of the loop you can provide the type hint in a comment.
/* #var $obj Foo */
+1 for Brian Fisher's suggestion.

Categories