In Doctrine 2 is there a way to get the array hydration mode to include the class name of the relevant entity in the output, so instead of:
array(
'id' => 1,
'name' => 'test',
// ...
);
You get:
array(
'__class' => 'MyProject\MyClass',
'id' => 1,
'name' => 'test',
// ...
);
I know the Doctrine\ORM\Internal\Hydration\ArrayHydrator class has access to the relevant information, but I'm trying to work out if this can be done without re-implementing the entire ArrayHydrator?
So creating a custom hydrator that extends ArrayHydrator and overriding the gatherRowData method with this is one potential solution:
protected function gatherRowData(array $data, array &$id, array &$nonemptyComponents)
{
$rowData = parent::gatherRowData($data, $id, $nonemptyComponents);
foreach ($rowData['data'] as $dqlAlias => $data) {
$class = $this->_rsm->aliasMap[$dqlAlias];
$meta = $this->getClassMetadata($class);
if ($meta->discriminatorMap) {
$class = $meta->discriminatorMap[$data[$meta->discriminatorColumn['name']]];
}
$rowData['data'][$dqlAlias]['__CLASS__'] = $class;
}
return $rowData;
}
Be interested to know if there's a better way?
Related
I have the following code:
public function transform($obj)
{
return [
'id' => (int) $obj->id,
'name' => $obj->name,
"prototype" => $obj->_prototypes()->get()
];
}
Where $obj->_prototypes()->get() is collection with fields (id, name).
How to format new array like as:
'name' => 'name' => $obj->name,
"prototype" => [
["id": 1, "name" : "ok"],
["id": 2, "name" : "ok 2"],
]
So, I need to iterate $obj->_prototypes()->get() inside transformer object.
So, I have nested objects(relations). And now I need to use loop, that to take nested object and combine them to one output object again.
you could use a for each loop, and in the for each loop use array_push or array_merge to merge the current iteration of the loop into a new array.
array_push docs = http://php.net/manual/en/function.array-push.php
array_merge docs = http://php.net/manual/en/function.array-merge.php
Definitely take a look at fractal's transformers. There are really nice features, including yours: http://fractal.thephpleague.com/transformers/
class MyTransformer extends TransformerAbstract
{
public $defaultIncludes = ['prototype'];
public function transform($obj)
{
return [
'id' => (int) $obj->id,
'name' => $obj->name
]
}
public function includePrototype($obj)
{
return $this->collection($obj->_prototypes()->get(), new PrototypeTransformer);
}
}
How can insert element into final position of array this array is on a private function??
private function getData()
{
return array(
1 => array(
'open_cookie_id' => 1,
'text' => 'I may throw up on ya',
'who' => 'Leonard McCoy',
),
2 => array(
'open_cookie_id' => 2,
'text' => 'I think these things are pretty safe.',
'who' => 'James T. Kirk'
),
3 => array(
'open_cookie_id' => 3,
'text' => 'Well, I hate to break this to you, but Starfleet operates in space.',
'who' => 'James T. Kirk'
),
4 => array(
'open_cookie_id' => 4,
'text' => 'Yeah. Well, I got nowhere else to go. The ex-wife took the whole damn planet in the divorce. All I got left is my bones.',
'who' => 'Leonard McCoy'
),
5 => array(
'open_cookie_id' => 5,
'text' => 'If you eliminate the impossible, whatever remains, however improbable, must be the truth.',
'who' => 'Spock'
)
);
}
How to insert the element 6 , 7, 8 etc to final array on these function private from other function
from this function:
/**
* Create a resource
*
* #param mixed $data
* #return ApiProblem|mixed
*/
public function create($data)
{
//return new ApiProblem(405, 'The POST method has not been defined');
//return $this->create($data) ;
$adapter = new ArrayAdapter($this->getData());
$adapter2 = Array
(
$data->open_cookie_id => array(
'open_cookie_id'=>$data->open_cookie_id ,
'text' =>$data->text,
'who' => $data->who
)
);
$adapter2_converted = new ArrayAdapter($adapter2);
//operation for merge two ArayAdapter ($adapter+$adapter2_convert)
// $collection = new OpenCookieCollection($final_adapter);
//return $collection;
}
I'm using php zend framework and apigility.
The function is private not the array so you can safely work with your returned array. Do notice that $adapter is a ArrayAdapter data type, not a simple array so you can't simple push.
My suggestion is to add a method to your ArrayAdapter that uses PHP array_push() to add your array to your ArrayAdapter data structure and use like this:
$adapter->pushArray($adapter2);
I think this is the line where you're actually calling the private method getData():
$adapter = new ArrayAdapter($this->getData());
If all you need as a result is an array with some extra elements added to it, you can do something like this:
$data = $this->getData();
$data[] = 'more data';
$data[] = 'even more data';
$adapter = new ArrayAdapter($data);
I'm trying to build a dynamic associative array value lookup function (within a class):
class Family
{
public static $members = array(
'one' => array(
'child' => 0,
'children' => 5
),
'two' => array(
'child' => 2,
'children' => null
)
);
public static function resolveMemberValue()
{
$chain = func_get_args();
$lookup = 'members' . '[\'' . implode('\'][\'', $chain) . '\']';
var_dump( $lookup );
return static::$$lookup;
}
}
Family::resolveMemberValue('one', 'child');
But this results in:
string(23) "members['one']['child']"
Fatal error: Access to undeclared static property: Family::$members['one']['child'] in /family.php on line 23
PHP Fatal error: Access to undeclared static property: Family::$members['one']['child'] in /family.php on line 23
Though, copying the dumped value, and pasting inside the script + appending dollar sign, it returns what's expected:
var_dump( Family::$members['one']['child'] );
int(0)
Reason why I need this is, because it will be used with multiple variables, and called from generator functions.
What is wrong with the snippet?
Variable variables only substitutes in a string for the name of the variable. It can't evaluate the content of that string (in this case the string members['one']['child'])
Your code is looking for a static property literally with the named $members['one']['child'] not an element of the static array $members.
Try this instead:
$member = static::$members[$chain[0]];
return $member[$chain[1]];
Also, I'd recommend not using func_get_args(), but explicitly naming your parameters in the method declaration. Some features of PHP a best left behind....
Oh, had to just tinker a little - managed to make a helper function.
The function replaces the implode() and the explicit key definition.
function array_lookup()
{
$chain = func_get_args();
$array = array_shift($chain);
foreach ($chain as $key) $array = $array[$key];
return $array;
}
$test = array(
'one' => array(
'child' => 0,
'children' => 5
),
'two' => array(
'child' => 2,
'children' => null
)
);
var_dump($test, 'one', 'child'); // int(0)
I have left out any kind of error checking for this example, but it does what I was looking for.
And yes, for my example, it nails it.
i want use json + php for my data. I read more document to do this, and the basic function are json_decode() and json_encode(). My problem is that, read more document and read different example of structure have created in me a lot of doubts.
I want create a structure like this begine from the basic to the container:
there is a Base, that have 2 property: id and value
there is a Operations that can have multiple Base
there is a Command that can have multiple Operations (and if possible a property callad name)
the structure in my mind is like this...
[ //The start of Commands
//Can make a property name here like "name":"puls1"
[ //Operation1
{ //Base1
"id":"22398",
"value":"255"
},
{ //Base2
"id":"22657",
"value":"80",
},
{ //Base3
"id":"7928",
"valore":"15"
}
],
[ //Operation2
{ //Base1
"id":"22398",
"value":"0"
},
{ //Base2
"id":"22657",
"value":"0",
},
{ //Base3
"id":"7928",
"valore":"0"
}
],
] //The close of Commands
But i have put the [ and { in the not correct order i think...
How can i make a json structure like this? And after set a command to insert a new Operation or remove Operation?
Thank's at all..
//Ok by answer of i made this code
class Base
{
var $i;
var $value;
function __construct($i,$v)
{
$this->id = $i;
$this->value = $v;
}
}
$a = new Base('1','11');
$b = new Base('2','10');
$c = new Base ('3','20');
$d = new Base ('4','30');
class Operation
{
var $name;
var $values = Array();
function __construct($a)
{
$this->name = $a;
}
public function addArray($a)
{
array_push($this->values,$a);
}
}
$oper1 = new Operation("op1");
$oper1->addArray($a);
$oper1->addArray($b);
$oper2= new Operation("op2");
$oper2->addArray($c);
$oper2->addArray($d);
$commands = Array($oper1,$oper2);
echo json_encode($tot);
Now the problem is how can i make the revert operation? Such a use of json_decode and incapsulate in its appropriate structure?
The json list type [] is equal to a array without keys in php.
The json dictionary type {}is equal to a keyed array in php.
What you want is something like this:
$json = array(
array(
array('id' => $num, 'value' => $val), // Base 1
array('id' => $num_1, 'value' => $val_1), // Base 3
array('id' => $num_2, 'value' => $val_2), // Base 2
),
array(...),
array(...),
);
If you're working with PHP I would construct the objects from native PHP Classes (json_encode works with php objects as well):
class Base {
var $id;
var $value;
}
Then it's just a matter of putting these objects in various arrays, which you can also abstract with methods like addToOperation($baseObj) and addToCommands($operationObj).
You're dealing with native data structures (Arrays), so you can use native methods to remove (array_pop) and add (array_push) data.
Something like this should work
// Build up your data as a mulitdimensional array
$data = array(
'operations' => array(
0 => array(
'bases' => array (
0 => array(
'id' => '22398',
'value' => 'whatever'
),
1 => array(
'id' => 'id goes here',
'value' => 'value goes here'
),
1 => array(
//data for operation 2
)
);
// Then use json_encode
$json = json_encode($data);
My syntax may not be perfect but that should give you the idea. To access it then you would use code like
$operations = json_decode($data);
foreach ($operations as $op) {
foreach ($op->bases as $base) {
//Logic goes here
}
}
Hope this helps.
Say hypothetically I have a class...
class Main {
$prop1 = 2;
$prop2 = 23;
...
$prop42 = "what";
function __construct($arg_array) {
foreach ($arg_array as $key => $val) {
$this->$key = $val;
}
}
}
Say I create and object...
$attributes = array("prop1"=>1, "prop2"=>35235, "prop3"=>"test");
$o = new Main($attributes);
Providing for default property values if not supplied by the user is obvious. But what if I want to enforce arbitrary limits on user supplied values for object properties? What if I want to enforce $prop1 to be of int, be no less than 1, and be no greater than 5. And, $prop42 to be of type string, no less than 'A', and no greater than 'Z'? For this purpose, what would be the cleanest way, keeping the script as short and sweet as possible, using any possible language feature or trick?
I'm stuck in __construct() checking supplied values against a rule array built like so...
$allowable = array(
"prop1" => array(
'type' => 'int',
'allowable_values' => array(
'min' => 1,
'max' => 5
)
),
"prop2" => array(
'type' => 'int',
'allowable_values' => array(
1,
235,
37,
392,
13,
409,
3216
)
),
...
"prop42" => array(
'type' => 'string',
'allowable_values' => array(
'min' => 'A',
'max' => 'Z'
)
)
);
As you can see by prop2, my validation function is starting to get pretty messy with so many 'if-then-iterate-again' blocks as I have to account for not only ranges but a list of permitted values. With the validation code and this rule array, my script is getting rather bulky.
The question is, how can I structure my class or class properties or the validation code or any other aspect of my script to be as short and concise as possible to allow property range and value enforcement? Is there a language feature or trick to handle this more elegantly? Have I reached a brick wall, the limit of this language? Are there any examples from other languages that can easily implement this which can provide some clue?
getters and setters
class Main {
private $prop1;
private $prop2;
private $prop3;
public function __construct( $p1 , $p2 , $p3 )
{
$this->setProp1($p1);
$this->setProp2($p2);
$this->setProp3($p3);
}
public function setProp1($p1)
{
// conditional checking for prop1
if(!$ok) throw new Exception('problem with prop1');
$this->prop1 = $p1;
}
//.. and so on
}
I ran into a similar issue the other day. Here's what I would do:
private $props;
private $rules;
function __construct($params) {
// or you can get the rules from another file,
// or a singleton as I suggested
$this->rules = array (array('type' => 'range', 'min' => 10, 'max' => 20),
array('type' => 'in_set', 'allowed' => array(1,2,3)));
for ($i=0; $i<count($params); $i++) {
if ($this->check($params[$i], $this->rules($i))
$this->props[$i] = $params[$i];
else
throw new Exception('Error adding prop ' . $i);
}
}
function check($value, $rule) {
switch($rule['type']) {
case 'range':
return ($rule['min'] <= $value && $value <= $rule['max']);
case 'in_set':
return (in_array($value, $rule['allowed']));
// and so on
}
}
If you have many parameters, you can use an array and iterate through that.
If your validation rules are always going to be the same, you can put them in a separate file and load that in your constructor or whatever.
EDIT: By the way, there is really no point in testing type in PHP. It is both not very reliable and unnecessary.
EDIT 2: Instead of having a global variable with the rules, you can use a Singleton: