PHP unit test Mock fetchAll object - php

can someone help me with mocking ZF1 fetchAll() method, it returns Zend_Db_Table_Rowset object
So tried to do mock in this way, here is my code.
$rowSet = $this->getMockBuilder(Zend_Db_Table_Rowset::class)
->disableOriginalConstructor()
->getMock();
and set private property tru reflaction class
$dataArray = [['id' => 1, 'name' => 'test_name'], ['id' => 2, 'name'=>'test2']];
$this->setProtectedFieldValue($rowSet, '_data', $dataArray);
protected function setProtectedFieldValue($entity, string $propertyName, $value) : void
{
$class = new ReflectionClass($entity);
$property = $class->getProperty($propertyName);
$property->setAccessible(true);
$property->setValue($entity, $value);
}
at the end in won't enter $rows set loop, i don't have idea how to loop or set data in this Zend_Db_Table_Rowset object.
$rows = $table->fetchAll($tableSelect);
foreach ($rows as $row) {
Small update i need something like this
https://hermanradtke.com/2010/02/08/mocking-zend-frameworks-row-and-rowset-objects.html, but in my version that My_ZendDbTable_Row_TestMockRow class doesn't exist
array(
'first_name' => 'Herman',
'last_name' => 'Radtke',
'email' => 'herman#example.com'
)
);
$row = new My_ZendDbTable_Row_TestMockRow($data);
$this->assertEquals('Herman', $row->first_name);
$this->assertEquals('Radtke', $row->last_name);
$this->assertEquals('herman#example.com', $row->email);
}
}

Related

Mongodb PHP cursor does not fill array

I have a find method in PHP which calls Mongodb, iterates over the cursor and should fill result array which will return. It looks like:
public function find($collection, $where, $select = [], $options = [])
{
$result = [];
if( $select ) foreach ( $select as $col) $options['projection'][$col] = 1; // Need projection in format: ['id' => 1, 'name' => 1, ...]
/** #var Cursor $cursor */
$cursor = $this->mongoDb->{$collection}->find($where, $options);
$cursor->setTypeMap(['root' => 'array', 'document' => 'array', 'array' => 'array']);
//$result = $cursor->toArray(); $result = $cursor;
$i = 0;
foreach ($cursor as $doc) {
if(++$i < 5) Debugger::log($doc);
$doc = $this->parseDocument($doc);
$result[] = $doc;
}
Debugger::log($result);
return $result;
}
The problem is that $result is empty although there are documents in result. It seems $result array is returned before cursor can fill it. It does not make any sense. I can not use $cursor->toArray() cause it has timeout error. How to fix it or how to fix timeout error with toArray()? Collection has above 170 mils. documents, so the timeout is quite a problem.

How to add elements to array in for loop, PHP - Laravel

I'm connecting to 3 databases which are stored in array $firmy
For now they are hard coded into array but they will be set via Axios request.
public function show(Request $request, $division, $id)
{
$firmy = array('connection1', 'connection2', 'connection3');
$data = [];
foreach ($firmy as $firma) {
DB::setDefaultConnection($firma);
$calendar = new CalendarEvent();
$data[] = CalendarEventResource::collection($calendar->with('calendarCategories')->where('start', '>', '2020-05-21')->get());
DB::purge($firma);
}
foreach ($data as $firma_event) {
foreach ($firma_event as $event) {
$eventT[] = $event;
}
}
return $eventT;
}
I set the connection, get collection and close the connection.
3 times in this case.
Then I loop through the data to get all records in one go.
Here's the API response returned by $eventT array:
[{"id":17549,"title":"Test","description":"test","contact":"test","email":"test","cat":1,"approved":0,"kto_dodal":450,"calendarCategories":{"id":1,"name":"Ogolna","color":"blue"},"start":"2020-09-30","end":"2020-09-30","private":0,"created_at":null,"updated_at":null},
{"id":17580,"title":"Test","description":"test","contact":"test","email":"test","cat":1,"approved":0,"kto_dodal":450,"calendarCategories":{"id":1,"name":"Ogolna","color":"blue"},"start":"2020-09-30","end":"2020-09-30","private":0,"created_at":null,"updated_at":null},
{"id":17545,"title":"Test","description":"test","contact":"test","email":"test","cat":1,"approved":0,"kto_dodal":450,"calendarCategories":{"id":1,"name":"Ogolna","color":"blue"},"start":"2020-09-30","end":"2020-09-30","private":0,"created_at":null,"updated_at":null}]
One per each connection/table which is fine.
I would like to add a name of the connection to each record. So the API response would look like this:
{"id":17545,"title":"Test","description":"test","contact":"test","email":"test","cat":1,"approved":0,"kto_dodal":450,"calendarCategories":{"id":1,"name":"Ogolna","color":"blue"},"start":"2020-09-30","end":"2020-09-30","private":0,"created_at":null,"updated_at":null, "firma":connection1}]
So "firma":nameOfConnection added to each record.
I tried looping through the data[] and using array_push but I can't place the value of connection inside each record.
Value ends up outside of object:
0: {id: 17549, title: "Test", description: "Test ",…} 1: {firma: "connection1"} firma: "connection1"
I managed to sort it.
First I added a value of firma to Resource class so it gets added to collection although it will be null because there is no column in DB with that name:
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'description' => $this->description,
'contact' => $this->contact,
'email' => $this->email,
'cat' => $this->cat,
'approved' => $this->approved,
'kto_dodal' => $this->kto_dodal,
'calendarCategories' => new CalendarCategoryResource($this->whenLoaded('calendarCategories')),
'start' => $this->start,
'end' => $this->end,
'private' => $this->private,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'firma' => $this->firma,
];
}
Then I access Event collection,loop through the results and set value of firma to whatever value the loop is currently at.
public function show(Request $request, $division, $id)
{
$firmy = array('connection1', 'connection2', 'connection3');
$data = [];
foreach ($firmy as $firma) {
DB::setDefaultConnection($firma);
$calendar = new CalendarEvent();
$data = CalendarEventResource::collection($calendar->with('calendarCategories')
->where('start', '>', '2020-09-21')
->where('private', '=', '0')
->get());
// Loop over data in collection and set value of firma
foreach ($data as $value) {
$value->firma = $firma;
$total[] = $value;
}
DB::purge($firma);
}
return $total;
}
Here's the returned value with the attribute firma inside the object:
{"id":17545,"title":"Test","description":"test","contact":"test","email":"test","cat":1,"approved":0,"kto_dodal":450,"calendarCategories":{"id":1,"name":"Ogolna","color":"blue"},"start":"2020-09-30","end":"2020-09-30","private":0,"created_at":null,"updated_at":null,"firma":"connection1"},

Retrieving Data from an object of an array of arrays

I know this question is more data structures but since I am doing it in Symfony there might be a simpler way. I have a recursive function treeBuilder() I want to call on some data to create a hierarchy. Say a database of people and I want to create a tree structure if they live with their parents. I know I am passing an array of object to the function but it needs to be an array. I am pretty sure I need to rewrite this function so that it handles the the array of object but am stumped. I am not sure how to access the elements of the array to check the parentid. I know the code below is not correct but that is where I am at now.
Controller:
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('CompanyMyBundle:Org')->findAll();
var_dump($entities);
$tree=$this->treeBuilder($entities);
return array(
'entities' => $tree,
);
}
private function treeBuilder($ar, $pid=null)
{
$op=array();
foreach( $ar as $item ) {
// I know I have an array of objects
if( $item['ParentId'] == $pid ) {
$op[$item['Id']] = array(
'Street' => $item['Street'],
'ParentId' => $item['ParentId']
);
$children = self::treeBuilder( $ar, $item['Id'] );
if( $children ) {
$op[$item['Id']]['children'] = $children;
}
}
}
return $op;
}
var_dump($entities) from indexAction():
/export/www/working/symfony/src/Company/MyBundle/Controller/DepController.php:34:
array (size=60)
0 =>
object(Company\MyBundle\Entity\Org)[1556]
private 'Name' => string 'Me' (length=46)
private 'Street' => string '123 Sesame' (length=255)
private 'City' => string 'Myhometown' (length=255)
private 'ParentId' => int 0
private 'Id' => int 1
1 =>
object(Company\MyBundle\Entity\Org)[1557]
private 'Name' => string 'Me2' (length=46)
private 'Street' => string '123 Sesame' (length=255)
private 'City' => string 'Myhometown' (length=255)
private 'ParentId' => int 1
private 'Id' => int 2
If you need to get entities as arrays instead of objects, you would need to use Doctrine's hydrator:
$em = $this->getDoctrine()->getManager();
$orgRepo = $em->getRepository('CompanyMyBundle:Org');
$entities = $orgRepo->createQueryBuilder('org')
->getQuery()
->getResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);
Note:
I would suggest to leave entities as objects and use getters:
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('CompanyMyBundle:Org')->findAll();
$tree = $this->treeBuilder($entities);
return array(
'entities' => $tree,
);
}
private function treeBuilder($entities, $pid = null)
{
$op = array();
/** Org $entity */ //Type hinting, if you use autocompletion
foreach ($entities as $entity) {
if ($entity->getParentId() == $pid) {
$op[$entity->getId()] = [
'Street' => $entity->getStreet(),
'ParentId' => $entity->getParentId()
];
$children = self::treeBuilder($entities, $entity->getId());
if (!empty($children)) {
$op[$entity->geId()]['children'] = $children;
}
}
}
return $op;
}

PHP class to JSON on several levels

I have a PHP class I would like to transform in a JSON on several levels like this type:
{"interface":{"Version":"0"},"Container":[{"id":"1","Element":[{"text":"Test","id":"0"},{"text":"Toto","id":"1"}]}]}
In my PHP class I have a function who returns the JSON of my private attributes who are arrays:
return (json_encode((get_object_vars($this)), JSON_UNESCAPED_UNICODE));
Private attributes of my class:
private $interface = '';
private $Container = array(array('id' => '1'));
private $Element = array('text' => 'Test', 'id' => '0');
Do you know how I could have a JSON like above ?
In pleasure to read you.
Not sure about your class members but as long as they are accessible you can generate the JSON string. Below if the example of this
$Contenant = array(array('id' => '1'));
$Element = array('text' => 'Test', 'id' => '0');
$json = json_encode(array('inerrface'=>array(
'content'=>$Contenant,
"Element"=>$Element
)
)
);
echo $json ;
You could implement the IteratorAggregate interface like in the following example
class YourClass implements IteratorAggregate {
protected $member1 = array();
protected $member2 = array();
...
public function getIterator() {
$tmpArr = array();
// create the structure you want in $tmpArr
return new ArrayIterator($tmpArr);
}
}
$myClass = new MyClass();
$iterator = $myClass->getIterator();
$encodedData = json_encode($iterator);
As of PHP5.4 you have the JsonSerializable interface ready to use. With this interface, you cann use direct modifications like in the example given in: http://de2.php.net/manual/en/jsonserializable.jsonserialize.php
have fun! ;)
This will get you started, take a look at the constructor what data input requires. You could make a private function doing the same thing, assigning your values to the structure and then printing it:
class Test{
private $data;
public function __construct($version = 0, $records = array()){
$data['interface'] = array('Version' => $version);
$data['Container'] = array();
for ($i = 0; $i < count($records); $i++) {
$data['Container'][$i] = $records[$i];
}
// your test input
print_r(json_decode('{"interface":{"Version":"0"},"Container":[{"id":"1","Element":[{"text":"Test","id":"0"},{"text":"Toto","id":"1"}]}]}',true));
// actual input
print_r($data);
// printing our actual data as json string
echo json_encode($data);
}
public function __destruct(){
}
}
$element1 = array('text' => 'Test', 'id' => 0);
$element2 = array('text' => 'Toto', 'id' => 1);
$elements = array($element1, $element2);
$record = array('id' => 1, 'element' => $elements);
$records = array($record);
new Test(0, $records);
You need to structure it, working example: example
class test {
private $interface = '';
private $Contenant = array(array('id' => '1'));
//private $Element = array(array('text' => 'Test', 'id' => '0'));
public function json(){
$this->Contenant = array(
array('id' => '1',
'Element' => array(array('text' => 'Test', 'id' => '0'))
),
);
return json_encode((get_object_vars($this)), JSON_UNESCAPED_UNICODE);
}
}
$t = new test();
$encode = $t->json();
echo $encode;
OUTPUT
{"interface":"","Contenant":[{"id":"1","Element":[{"text":"Test","id":"0"}]}]}

Recursive function inside class with foreach changes public value where it shouldn't

Ok, I'm really stucked with this. I hope you can help me.
I have my class, used to manage hierarchical data. The input is a plain array with the following structure (just an example):
$list = array(
(object) array('id' => 1, 'nombre' => 'Cámaras de fotos', 'parentId' => null),
(object) array('id' => 2, 'nombre' => 'Lentes', 'parentId' => null),
(object) array('id' => 3, 'nombre' => 'Zoom', 'parentId' => 2),
(object) array('id' => 4, 'nombre' => 'SLR', 'parentId' => 1),
(object) array('id' => 5, 'nombre' => 'Primarios', 'parentId' => 2),
(object) array('id' => 6, 'nombre' => 'Sensor APS-C', 'parentId' => 4),
(object) array('id' => 7, 'nombre' => 'Full-frame', 'parentId' => 4),
(object) array('id' => 8, 'nombre' => 'Flashes', 'parentId' => null),
(object) array('id' => 9, 'nombre' => 'Compactas', 'parentId' => 1)
);
I input the data to the class this way:
$Hierarchical = new Hierarchical;
$Hierarchical->plain = $list;
Then I have a public function (createTree) to create a multidimensional array representation of the list. It works perfectly. It can return the result or store it inside $this->tree.
As you can see, this is very simple. It calls private function iterateTree, which is the recursive function.
class Hierarchical {
public $plain = array();
public $tree = array();
public function createTree($parentId=0, $return=false) {
$tree = $this->iterateTree($parentId);
if(!$return) {
$this->tree = $tree;
} else {
return $tree;
}
}
private function iterateTree($parentId) {
$resArray = array();
foreach($this->plain as $item) {
if($item->parentId == $parentId) {
$children = $this->iterateTree($item->id);
if( count($children) > 0 ) {
$item->children = $children;
}
$resArray[] = $item;
}
}
return $resArray;
}
}
So far so good. It works fine.
BUT... The problem appears when I want to use $this->plain after calling createTree(). Instead of returning the original dataset, it returns some kind of mix between the original input, with all their children appended (similar to $this->tree).
I can't figure out why the content of $this->plain is being changed, neither in the both functions used I'm changing it's content.
I've tried unseting the variables inside the foreach, after the foreach, even passing the original array as an argument and not using $this->plain at all inside the recursive function. Nothing worked.
I'm also not using any other function inside the class that could change it's value.
It's a total mistery!
In your foreach loop $item will be a reference to the object in the array, so you are changing that same object in the line
$item->children = $children;
This will affect the object referred to in the original arrays $list and $this->plain.
One solution may be to clone $item within your foreach loop.
According to Doug's answer, the correct function is: (added $itemAux = clone $item)
private function iterateTree($parentId) {
$resArray = array();
foreach($this->plain as $item) {
$itemAux = clone $item;
if($itemAux->parentId == $parentId) {
$children = $this->iterateTree($itemAux->id);
if( count($children) > 0 ) {
$itemAux->children = $children;
}
$resArray[] = $itemAux;
}
}
return $resArray;
}
To add to Doug's answer, although the manual says that "objects are not passed by reference" (http://www.php.net/manual/en/language.oop5.references.php), it may instead help to think of objects as a completely separate entity from any variables that may "contain" them, and that they are actually passed everywhere by reference...
class testClass
{
public $var1 = 1;
}
function testFunc($obj)
{
$obj->var1 = 2;
}
$t = new testClass;
testFunc($t);
echo $t->var1; // 2
So when you do $item->children = $children;, you are in fact affecting each original object in that $plain array.

Categories