Get key value list from Doctrine - php

I wrote this function inside my Repository class to receive a simple key value from Doctrine. Isn't there a build in Doctrine function to do this? (I couldn't find it). Or maybe the code can be improved.
Here's my function:
public function getListBy($criteria=null, $key, $value) {
$dql = "SELECT i.".$key." as k,
i.".$value." as v
FROM MbFooBundle:Input i";
if (isset($criteria) && is_array($criteria)) {
foreach($criteria as $cKey => $cValue) {
if (!isset($where))
$where = " WHERE ";
else
$where .= " AND ";
$where .= "i.".$cKey." = ".(is_numeric($cValue) ? $cValue : "'".$cValue."'");
}
$dql .= $where;
}
$query = $this->getEntityManager()
->createQuery($dql);
$result = $query->getArrayResult();
$list = array();
if (count($result)) {
foreach($result as $data) {
$list[$data['k']] = $data['v'];
}
}
return $list;
}

I wouldn't do this. Yet this code is vulnerable to SQL Injection but it also breaks some standards.
Here's my way of thinking.
I would create a method which will manipulate the results of the standard doctrine's findBy
/**
* Data Manipulator
*/
class DataManipulator
{
/**
* Associates any traversable input into its key and value
*
* #param mixed $input A Traversable input
* #param string $key Key to associate
* #param string $value Value to associate
* #return array Associated array
*
* #throws InvalidArgumentException When Input is not traversable
*/
public function associate($input, $key, $value)
{
if (!is_array($input) && !($input instanceof Traversable)) {
throw new InvalidArgumentException("Expected traversable");
}
$out = array();
foreach ($input as $row) {
$out[$this->getInput($row, $key)] = $this->getInput($row, $value);
}
return $out;
}
/**
* Fetches the input of a given property
*
* #param mixed $row An array or an object
* #param string $find Property to find
* #return mixed Property's value
*
* #throws UnexpectedValueException When no matching with $find where found
*/
protected function getInput($row, $find)
{
if (is_array($row) && array_key_exists($find, $row)) {
return $row[$find];
}
if (is_object($row)) {
if (isset($row->$find)) {
return $row->$find;
}
$method = sprintf("get%s", $find);
if (method_exists($row, $method)) {
return $row->$method();
}
}
throw new UnexpectedValueException("Could not find any method to resolve");
}
}
Then you can use it
$em = $this->getDoctrine()->getManager();
$results = $em->getRepository('AcmeFooBundle:Input')
->findBy(array('category' => 'foo'));
$manipulator = new DataManipulator;
$filtered = $manipulator->associate($results, 'key', 'value');
You can see it working
If you need to select only partial objects, you should create a method in your repository which will fetch your partial input.
This function must only fetch the object, not associate its content.
public function findPartialBy(array $values, array $criterias = array())
{
$qb = $this->createQueryBuilder('i');
$qb->select($values);
foreach ($criterias as $key => $value) {
$qb->andWhere(sprintf("i.%s", $key), sprintf(":%s", $key))
$qb->setParameter(sprintf(":%s", $key), $value);
}
return $qb->getQuery()->getResult();
}
Then you can use it
$fetch = array('key', 'value');
$em = $this->getDoctrine()->getManager();
$results = $em->getRepository('AcmeFooBundle:Input')
->findPartialBy($fetch, array('category' => 'foo'));
$manipulator = new DataManipulator;
$filtered = $manipulator->associate($results, 'key', 'value');
Read more about partial objects
Read more about the query builder
Read more on how to select partial objects with a query builder

Related

How to convert an Object to an array in PHP7? [duplicate]

I'm integrating an API to my website which works with data stored in objects while my code is written using arrays.
I'd like a quick-and-dirty function to convert an object to an array.
Just typecast it
$array = (array) $yourObject;
From Arrays:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side.
Example: Simple Object
$object = new StdClass;
$object->foo = 1;
$object->bar = 2;
var_dump( (array) $object );
Output:
array(2) {
'foo' => int(1)
'bar' => int(2)
}
Example: Complex Object
class Foo
{
private $foo;
protected $bar;
public $baz;
public function __construct()
{
$this->foo = 1;
$this->bar = 2;
$this->baz = new StdClass;
}
}
var_dump( (array) new Foo );
Output (with \0s edited in for clarity):
array(3) {
'\0Foo\0foo' => int(1)
'\0*\0bar' => int(2)
'baz' => class stdClass#2 (0) {}
}
Output with var_export instead of var_dump:
array (
'' . "\0" . 'Foo' . "\0" . 'foo' => 1,
'' . "\0" . '*' . "\0" . 'bar' => 2,
'baz' =>
stdClass::__set_state(array(
)),
)
Typecasting this way will not do deep casting of the object graph and you need to apply the null bytes (as explained in the manual quote) to access any non-public attributes. So this works best when casting StdClass objects or objects with only public properties. For quick and dirty (what you asked for) it's fine.
Also see this in-depth blog post:
Fast PHP Object to Array conversion
You can quickly convert deeply nested objects to associative arrays by relying on the behavior of the JSON encode/decode functions:
$array = json_decode(json_encode($nested_object), true);
From the first Google hit for "PHP object to assoc array" we have this:
function object_to_array($data)
{
if (is_array($data) || is_object($data))
{
$result = [];
foreach ($data as $key => $value)
{
$result[$key] = (is_array($value) || is_object($value)) ? object_to_array($value) : $value;
}
return $result;
}
return $data;
}
The source is at codesnippets.joyent.com.
To compare it to the solution of json_decode & json_encode, this one seems faster. Here is a random benchmark (using the simple time measuring):
$obj = (object) [
'name' =>'Mike',
'surname' =>'Jovanson',
'age' =>'45',
'time' =>1234567890,
'country' =>'Germany',
];
##### 100 000 cycles ######
* json_decode(json_encode($var)) : 4.15 sec
* object_to_array($var) : 0.93 sec
If your object properties are public you can do:
$array = (array) $object;
If they are private or protected, they will have weird key names on the array. So, in this case you will need the following function:
function dismount($object) {
$reflectionClass = new ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
}
return $array;
}
What about get_object_vars($obj)? It seems useful if you only want to access the public properties of an object.
See get_object_vars.
class Test{
const A = 1;
public $b = 'two';
private $c = test::A;
public function __toArray(){
return call_user_func('get_object_vars', $this);
}
}
$my_test = new Test();
var_dump((array)$my_test);
var_dump($my_test->__toArray());
Output
array(2) {
["b"]=>
string(3) "two"
["Testc"]=>
int(1)
}
array(1) {
["b"]=>
string(3) "two"
}
Type cast your object to an array.
$arr = (array) $Obj;
It will solve your problem.
Here is some code:
function object_to_array($data) {
if ((! is_array($data)) and (! is_object($data)))
return 'xxx'; // $data;
$result = array();
$data = (array) $data;
foreach ($data as $key => $value) {
if (is_object($value))
$value = (array) $value;
if (is_array($value))
$result[$key] = object_to_array($value);
else
$result[$key] = $value;
}
return $result;
}
All other answers posted here are only working with public attributes. Here is one solution that works with JavaBeans-like objects using reflection and getters:
function entity2array($entity, $recursionDepth = 2) {
$result = array();
$class = new ReflectionClass(get_class($entity));
foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
$methodName = $method->name;
if (strpos($methodName, "get") === 0 && strlen($methodName) > 3) {
$propertyName = lcfirst(substr($methodName, 3));
$value = $method->invoke($entity);
if (is_object($value)) {
if ($recursionDepth > 0) {
$result[$propertyName] = $this->entity2array($value, $recursionDepth - 1);
}
else {
$result[$propertyName] = "***"; // Stop recursion
}
}
else {
$result[$propertyName] = $value;
}
}
}
return $result;
}
To convert an object into array just cast it explicitly:
$name_of_array = (array) $name_of_object;
You can also create a function in PHP to convert an object array:
function object_to_array($object) {
return (array) $object;
}
Use:
function readObject($object) {
$name = get_class ($object);
$name = str_replace('\\', "\\\\", $name); // Outcomment this line, if you don't use
// class namespaces approach in your project
$raw = (array)$object;
$attributes = array();
foreach ($raw as $attr => $val) {
$attributes[preg_replace('('.$name.'|\*|)', '', $attr)] = $val;
}
return $attributes;
}
It returns an array without special characters and class names.
You can easily use this function to get the result:
function objetToArray($adminBar){
$reflector = new ReflectionObject($adminBar);
$nodes = $reflector->getProperties();
$out = [];
foreach ($nodes as $node) {
$nod = $reflector->getProperty($node->getName());
$nod->setAccessible(true);
$out[$node->getName()] = $nod->getValue($adminBar);
}
return $out;
}
Use PHP 5 or later.
Short solution of #SpYk3HH
function objectToArray($o)
{
$a = array();
foreach ($o as $k => $v)
$a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v;
return $a;
}
Here is my recursive PHP function to convert PHP objects to an associative array:
// ---------------------------------------------------------
// ----- object_to_array_recursive --- function (PHP) ------
// ---------------------------------------------------------
// --- arg1: -- $object = PHP Object - required --
// --- arg2: -- $assoc = TRUE or FALSE - optional --
// --- arg3: -- $empty = '' (Empty String) - optional --
// ---------------------------------------------------------
// ----- Return: Array from Object --- (associative) -------
// ---------------------------------------------------------
function object_to_array_recursive($object, $assoc=TRUE, $empty='')
{
$res_arr = array();
if (!empty($object)) {
$arrObj = is_object($object) ? get_object_vars($object) : $object;
$i=0;
foreach ($arrObj as $key => $val) {
$akey = ($assoc !== FALSE) ? $key : $i;
if (is_array($val) || is_object($val)) {
$res_arr[$akey] = (empty($val)) ? $empty : object_to_array_recursive($val);
}
else {
$res_arr[$akey] = (empty($val)) ? $empty : (string)$val;
}
$i++;
}
}
return $res_arr;
}
// ---------------------------------------------------------
// ---------------------------------------------------------
Usage example:
// ---- Return associative array from object, ... use:
$new_arr1 = object_to_array_recursive($my_object);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, TRUE);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, 1);
// ---- Return numeric array from object, ... use:
$new_arr2 = object_to_array_recursive($my_object, FALSE);
Custom function to convert stdClass to an array:
function objectToArray($d) {
if (is_object($d)) {
// Gets the properties of the given object
// with get_object_vars function
$d = get_object_vars($d);
}
if (is_array($d)) {
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
return array_map(__FUNCTION__, $d);
} else {
// Return array
return $d;
}
}
Another custom function to convert Array to stdClass:
function arrayToObject($d) {
if (is_array($d)) {
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
return (object) array_map(__FUNCTION__, $d);
} else {
// Return object
return $d;
}
}
Usage Example:
// Create new stdClass Object
$init = new stdClass;
// Add some test data
$init->foo = "Test data";
$init->bar = new stdClass;
$init->bar->baaz = "Testing";
$init->bar->fooz = new stdClass;
$init->bar->fooz->baz = "Testing again";
$init->foox = "Just test";
// Convert array to object and then object back to array
$array = objectToArray($init);
$object = arrayToObject($array);
// Print objects and array
print_r($init);
echo "\n";
print_r($array);
echo "\n";
print_r($object);
First of all, if you need an array from an object you probably should constitute the data as an array first. Think about it.
Don't use a foreach statement or JSON transformations. If you're planning this, again you're working with a data structure, not with an object.
If you really need it use an object-oriented approach to have a clean and maintainable code. For example:
Object as array
class PersonArray implements \ArrayAccess, \IteratorAggregate
{
public function __construct(Person $person) {
$this->person = $person;
}
// ...
}
If you need all properties, use a transfer object:
class PersonTransferObject
{
private $person;
public function __construct(Person $person) {
$this->person = $person;
}
public function toArray() {
return [
// 'name' => $this->person->getName();
];
}
}
Also you can use The Symfony Serializer Component
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$array = json_decode($serializer->serialize($object, 'json'), true);
You might want to do this when you obtain data as objects from databases:
// Suppose 'result' is the end product from some query $query
$result = $mysqli->query($query);
$result = db_result_to_array($result);
function db_result_to_array($result)
{
$res_array = array();
for ($count=0; $row = $result->fetch_assoc(); $count++)
$res_array[$count] = $row;
return $res_array;
}
This answer is only the union of the different answers of this post, but it's the solution to convert a PHP object with public or private properties with simple values or arrays to an associative array...
function object_to_array($obj)
{
if (is_object($obj))
$obj = (array)$this->dismount($obj);
if (is_array($obj)) {
$new = array();
foreach ($obj as $key => $val) {
$new[$key] = $this->object_to_array($val);
}
}
else
$new = $obj;
return $new;
}
function dismount($object)
{
$reflectionClass = new \ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
}
return $array;
}
Some impovements to the "well-knwon" code
/*** mixed Obj2Array(mixed Obj)***************************************/
static public function Obj2Array($_Obj) {
if (is_object($_Obj))
$_Obj = get_object_vars($_Obj);
return(is_array($_Obj) ? array_map(__METHOD__, $_Obj) : $_Obj);
} // BW_Conv::Obj2Array
Notice that if the function is member of a class (like above) you must change __FUNCTION__ to __METHOD__
For your case it was right/beautiful if you would use the "decorator" or "date model transformation" patterns. For example:
Your model
class Car {
/** #var int */
private $color;
/** #var string */
private $model;
/** #var string */
private $type;
/**
* #return int
*/
public function getColor(): int
{
return $this->color;
}
/**
* #param int $color
* #return Car
*/
public function setColor(int $color): Car
{
$this->color = $color;
return $this;
}
/**
* #return string
*/
public function getModel(): string
{
return $this->model;
}
/**
* #param string $model
* #return Car
*/
public function setModel(string $model): Car
{
$this->model = $model;
return $this;
}
/**
* #return string
*/
public function getType(): string
{
return $this->type;
}
/**
* #param string $type
* #return Car
*/
public function setType(string $type): Car
{
$this->type = $type;
return $this;
}
}
Decorator
class CarArrayDecorator
{
/** #var Car */
private $car;
/**
* CarArrayDecorator constructor.
* #param Car $car
*/
public function __construct(Car $car)
{
$this->car = $car;
}
/**
* #return array
*/
public function getArray(): array
{
return [
'color' => $this->car->getColor(),
'type' => $this->car->getType(),
'model' => $this->car->getModel(),
];
}
}
Usage
$car = new Car();
$car->setType('type#');
$car->setModel('model#1');
$car->setColor(255);
$carDecorator = new CarArrayDecorator($car);
$carResponseData = $carDecorator->getArray();
So it will be more beautiful and more correct code.
Converting and removing annoying stars:
$array = (array) $object;
foreach($array as $key => $val)
{
$new_array[str_replace('*_', '', $key)] = $val;
}
Probably, it will be cheaper than using reflections.
I use this (needed recursive solution with proper keys):
/**
* This method returns the array corresponding to an object, including non public members.
*
* If the deep flag is true, is will operate recursively, otherwise (if false) just at the first level.
*
* #param object $obj
* #param bool $deep = true
* #return array
* #throws \Exception
*/
public static function objectToArray(object $obj, bool $deep = true)
{
$reflectionClass = new \ReflectionClass(get_class($obj));
$array = [];
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$val = $property->getValue($obj);
if (true === $deep && is_object($val)) {
$val = self::objectToArray($val);
}
$array[$property->getName()] = $val;
$property->setAccessible(false);
}
return $array;
}
Example of usage, the following code:
class AA{
public $bb = null;
protected $one = 11;
}
class BB{
protected $two = 22;
}
$a = new AA();
$b = new BB();
$a->bb = $b;
var_dump($a)
Will print this:
array(2) {
["bb"] => array(1) {
["two"] => int(22)
}
["one"] => int(11)
}
There's my proposal, if you have objects in objects with even private members:
public function dismount($object) {
$reflectionClass = new \ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
if (is_object($property->getValue($object))) {
$array[$property->getName()] = $this->dismount($property->getValue($object));
} else {
$array[$property->getName()] = $property->getValue($object);
}
$property->setAccessible(false);
}
return $array;
}
Since a lot of people find this question because of having trouble with dynamically access attributes of an object, I will just point out that you can do this in PHP: $valueRow->{"valueName"}
In context (removed HTML output for readability):
$valueRows = json_decode("{...}"); // Rows of unordered values decoded from a JSON object
foreach ($valueRows as $valueRow) {
foreach ($references as $reference) {
if (isset($valueRow->{$reference->valueName})) {
$tableHtml .= $valueRow->{$reference->valueName};
}
else {
$tableHtml .= " ";
}
}
}
I think it is a nice idea to use traits to store object-to-array converting logic. A simple example:
trait ArrayAwareTrait
{
/**
* Return list of Entity's parameters
* #return array
*/
public function toArray()
{
$props = array_flip($this->getPropertiesList());
return array_map(
function ($item) {
if ($item instanceof \DateTime) {
return $item->format(DATE_ATOM);
}
return $item;
},
array_filter(get_object_vars($this), function ($key) use ($props) {
return array_key_exists($key, $props);
}, ARRAY_FILTER_USE_KEY)
);
}
/**
* #return array
*/
protected function getPropertiesList()
{
if (method_exists($this, '__sleep')) {
return $this->__sleep();
}
if (defined('static::PROPERTIES')) {
return static::PROPERTIES;
}
return [];
}
}
class OrderResponse
{
use ArrayAwareTrait;
const PROP_ORDER_ID = 'orderId';
const PROP_TITLE = 'title';
const PROP_QUANTITY = 'quantity';
const PROP_BUYER_USERNAME = 'buyerUsername';
const PROP_COST_VALUE = 'costValue';
const PROP_ADDRESS = 'address';
private $orderId;
private $title;
private $quantity;
private $buyerUsername;
private $costValue;
private $address;
/**
* #param $orderId
* #param $title
* #param $quantity
* #param $buyerUsername
* #param $costValue
* #param $address
*/
public function __construct(
$orderId,
$title,
$quantity,
$buyerUsername,
$costValue,
$address
) {
$this->orderId = $orderId;
$this->title = $title;
$this->quantity = $quantity;
$this->buyerUsername = $buyerUsername;
$this->costValue = $costValue;
$this->address = $address;
}
/**
* #inheritDoc
*/
public function __sleep()
{
return [
static::PROP_ORDER_ID,
static::PROP_TITLE,
static::PROP_QUANTITY,
static::PROP_BUYER_USERNAME,
static::PROP_COST_VALUE,
static::PROP_ADDRESS,
];
}
/**
* #return mixed
*/
public function getOrderId()
{
return $this->orderId;
}
/**
* #return mixed
*/
public function getTitle()
{
return $this->title;
}
/**
* #return mixed
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* #return mixed
*/
public function getBuyerUsername()
{
return $this->buyerUsername;
}
/**
* #return mixed
*/
public function getCostValue()
{
return $this->costValue;
}
/**
* #return string
*/
public function getAddress()
{
return $this->address;
}
}
$orderResponse = new OrderResponse(...);
var_dump($orderResponse->toArray());
$Menu = new Admin_Model_DbTable_Menu();
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu();
$Addmenu->populate($row->toArray());
Here I've made an objectToArray() method, which also works with recursive objects, like when $objectA contains $objectB which points again to $objectA.
Additionally I've restricted the output to public properties using ReflectionClass. Get rid of it, if you don't need it.
/**
* Converts given object to array, recursively.
* Just outputs public properties.
*
* #param object|array $object
* #return array|string
*/
protected function objectToArray($object) {
if (in_array($object, $this->usedObjects, TRUE)) {
return '**recursive**';
}
if (is_array($object) || is_object($object)) {
if (is_object($object)) {
$this->usedObjects[] = $object;
}
$result = array();
$reflectorClass = new \ReflectionClass(get_class($this));
foreach ($object as $key => $value) {
if ($reflectorClass->hasProperty($key) && $reflectorClass->getProperty($key)->isPublic()) {
$result[$key] = $this->objectToArray($value);
}
}
return $result;
}
return $object;
}
To identify already used objects, I am using a protected property in this (abstract) class, named $this->usedObjects. If a recursive nested object is found, it will be replaced by the string **recursive**. Otherwise it would fail in because of infinite loop.
By using typecasting you can resolve your problem.
Just add the following lines to your return object:
$arrObj = array(yourReturnedObject);
You can also add a new key and value pair to it by using:
$arrObj['key'] = value;

Call to a member function publish()

i have created a joomla component and when i click on publish and unpublish button in admin then i am getting such error.
Fatal error: Call to a member function publish() on boolean in ...\libraries\legacy\controller\admin.php on line 209
Please help
UPDATE
my View.html.php
require_once JPATH_COMPONENT . '/helpers/lab.php';
class labViewStructurelist extends JViewLegacy
{
protected $structurelist;
protected $pagination;
public $filterForm;
public $activeFilters;public $state;
public function display($tpl = null)
{
$this->structurelist = $this->get('Items');
$this->pagination = $this->get('Pagination');
$this->state = $this->get('State');
//print_r($this->pagination->pagesTotal);die();
$this->filterForm = $this->get('FilterForm');
$this->activeFilters = $this->get('ActiveFilters');
$this->addToolBar();
$this->sidebar = JHtmlSidebar::render();
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode('<br />', $errors));
return false;
}
return parent::display($tpl);
}
protected function addToolBar() {
JToolBarHelper::title( JText::_('COM_LAB_LAB_DDDD'), 'generic.png' );
JToolBarHelper::publish('Structurelist.publish');
JToolBarHelper::unpublish('Structurelist.unpublish');
JToolBarHelper::deleteList('', 'patients.delete', 'JTOOLBAR_DELETE');
JToolBarHelper::preferences('com_lab');
}
}
Controller/stricturelist.php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import Joomla controller library
jimport('joomla.application.component.controlleradmin');
class LabControllerStructurelist extends JControllerAdmin
{
public function getModel($name='Structurelist',$prefix='ssModel',$config=array('ignore_request'=>true))
{
$model=parent::getModel($name,$prefix,$config);
return $model;
}
}
models\structurelist.php
defined('_JEXEC') or die;
jimport('joomla.application.component.modellist');
JFormHelper::loadFieldClass('list');
class LabModelStructurelist extends JModelList{
public function __construct($config = array())
{
if (empty($config['filter_fields']))
{
$config['filter_fields'] = array(
'id', 'a.id',
'fullname', 'a.fullname',
);
$assoc = JLanguageAssociations::isEnabled();
if ($assoc)
{
$config['filter_fields'][] = 'association';
}
}
parent::__construct($config);
}
public function getListQuery()
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('*');
$query->from('#__ss_structure_tmp');
$search = $this->getState('filter.search');
$limit = $this->getState('filter.limit');
if (!empty($search)) {
$query->where('fullname LIKE "%' . $search .'%" ' );
}
if (!empty($limit)) {
$query->setLimit($limit);
}
return $query;
}
protected function populateState($ordering = 'a.fullname', $direction = 'asc')
{
$app = JFactory::getApplication();
if ($layout = $app->input->get('layout'))
{
$this->context .= '.' . $layout;
}
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$this->setState('filter.search', $search);
parent::populateState();
}
}
You need to provide the model to your controller using the getModel() method. Look in the articles controller of the com_content for example.
You need to add a table file with the publish function within:
defined('_JEXEC') or die;
use Joomla\Utilities\ArrayHelper;
class labTableStructurelist extends JTable
{
/**
* Constructor
*
* #param JDatabase &$db A database connector object
*/
public function __construct(&$db)
{
parent::__construct('#__ss_structure_tmp', 'id', $db);
}
/**
* Overloaded bind function to pre-process the params.
*
* #param array $array Named array
* #param mixed $ignore Optional array or list of parameters to ignore
*
* #return null|string null is operation was satisfactory, otherwise returns an error
*
* #see JTable:bind
* #since 1.5
*/
public function bind($array, $ignore = '')
{
$input = JFactory::getApplication()->input;
$task = $input->getString('task', '');
if (($task == 'save' || $task == 'apply') && (!JFactory::getUser()->authorise('core.edit.state', 'com_lab.structurelist.'.$array['id']) && $array['state'] == 1))
{
$array['state'] = 0;
}
if ($array['id'] == 0)
{
$array['created_by'] = JFactory::getUser()->id;
}
if (isset($array['params']) && is_array($array['params']))
{
$registry = new JRegistry;
$registry->loadArray($array['params']);
$array['params'] = (string) $registry;
}
if (isset($array['metadata']) && is_array($array['metadata']))
{
$registry = new JRegistry;
$registry->loadArray($array['metadata']);
$array['metadata'] = (string) $registry;
}
if (!JFactory::getUser()->authorise('core.admin', 'com_lab.structurelist.' . $array['id']))
{
$actions = JAccess::getActionsFromFile(
JPATH_ADMINISTRATOR . '/components/com_lab/access.xml',
"/access/section[#name='user']/"
);
$default_actions = JAccess::getAssetRules('com_lab.structurelist.' . $array['id'])->getData();
$array_jaccess = array();
foreach ($actions as $action)
{
$array_jaccess[$action->name] = $default_actions[$action->name];
}
$array['rules'] = $this->JAccessRulestoArray($array_jaccess);
}
// Bind the rules for ACL where supported.
if (isset($array['rules']) && is_array($array['rules']))
{
$this->setRules($array['rules']);
}
return parent::bind($array, $ignore);
}
/**
* This function convert an array of JAccessRule objects into an rules array.
*
* #param array $jaccessrules An array of JAccessRule objects.
*
* #return array
*/
private function JAccessRulestoArray($jaccessrules)
{
$rules = array();
foreach ($jaccessrules as $action => $jaccess)
{
$actions = array();
foreach ($jaccess->getData() as $group => $allow)
{
$actions[$group] = ((bool) $allow);
}
$rules[$action] = $actions;
}
return $rules;
}
/**
* Overloaded check function
*
* #return bool
*/
public function check()
{
// If there is an ordering column and this is a new row then get the next ordering value
if (property_exists($this, 'ordering') && $this->id == 0)
{
$this->ordering = self::getNextOrder();
}
return parent::check();
}
/**
* Method to set the publishing state for a row or list of rows in the database
* table. The method respects checked out rows by other users and will attempt
* to checkin rows that it can after adjustments are made.
*
* #param mixed $pks An optional array of primary key values to update. If not
* set the instance property value is used.
* #param integer $state The publishing state. eg. [0 = unpublished, 1 = published]
* #param integer $userId The user id of the user performing the operation.
*
* #return boolean True on success.
*
* #since 1.0.4
*
* #throws Exception
*/
public function publish($pks = null, $state = 1, $userId = 0)
{
// Initialise variables.
$k = $this->_tbl_key;
// Sanitize input.
ArrayHelper::toInteger($pks);
$userId = (int) $userId;
$state = (int) $state;
// If there are no primary keys set check to see if the instance key is set.
if (empty($pks))
{
if ($this->$k)
{
$pks = array($this->$k);
}
// Nothing to set publishing state on, return false.
else
{
throw new Exception(500, JText::_('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED'));
}
}
// Build the WHERE clause for the primary keys.
$where = $k . '=' . implode(' OR ' . $k . '=', $pks);
// Determine if there is checkin support for the table.
if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time'))
{
$checkin = '';
}
else
{
$checkin = ' AND (checked_out = 0 OR checked_out = ' . (int) $userId . ')';
}
// Update the publishing state for rows with the given primary keys.
$this->_db->setQuery(
'UPDATE `' . $this->_tbl . '`' .
' SET `state` = ' . (int) $state .
' WHERE (' . $where . ')' .
$checkin
);
$this->_db->execute();
// If checkin is supported and all rows were adjusted, check them in.
if ($checkin && (count($pks) == $this->_db->getAffectedRows()))
{
// Checkin each row.
foreach ($pks as $pk)
{
$this->checkin($pk);
}
}
// If the JTable instance value is in the list of primary keys that were set, set the instance.
if (in_array($this->$k, $pks))
{
$this->state = $state;
}
return true;
}
/**
* Define a namespaced asset name for inclusion in the #__assets table
*
* #return string The asset name
*
* #see JTable::_getAssetName
*/
protected function _getAssetName()
{
$k = $this->_tbl_key;
return 'com_lab.structurelist.' . (int) $this->$k;
}
/**
* Returns the parent asset's id. If you have a tree structure, retrieve the parent's id using the external key field
*
* #param JTable $table Table name
* #param integer $id Id
*
* #see JTable::_getAssetParentId
*
* #return mixed The id on success, false on failure.
*/
protected function _getAssetParentId(JTable $table = null, $id = null)
{
// We will retrieve the parent-asset from the Asset-table
$assetParent = JTable::getInstance('Asset');
// Default: if no asset-parent can be found we take the global asset
$assetParentId = $assetParent->getRootId();
// The item has the component as asset-parent
$assetParent->loadByName('com_lab');
// Return the found asset-parent-id
if ($assetParent->id)
{
$assetParentId = $assetParent->id;
}
return $assetParentId;
}
/**
* Delete a record by id
*
* #param mixed $pk Primary key value to delete. Optional
*
* #return bool
*/
public function delete($pk = null)
{
$this->load($pk);
$result = parent::delete($pk);
return $result;
}
}
Please note, that this is just an example of a table file, I can't guarantee that this would work just by copy&paste. Please check com_content/table for another example.
Also add a getTable() to your List single item model:
public function getTable($type = 'view_name', $prefix = 'labTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
Please check if file structure is correct:
List View
structurelist**s** -> list view with multiple items
|-> controller/structurelists.php
|-> models/structurelists.php
|-> view/structurelists/
Single View / List View (publish() for example)
structurelist -> single item view (edit view)
|-> models/structurelist.php (this is important for the publish() in the list view)
|-> models/forms/structurelist.xml
|-> tables/structurelist.php (this is important for the publish() in the list view)
|-> view/structurelist/
Feel free to comment if you need more help.

Foreach array php [duplicate]

I'm integrating an API to my website which works with data stored in objects while my code is written using arrays.
I'd like a quick-and-dirty function to convert an object to an array.
Just typecast it
$array = (array) $yourObject;
From Arrays:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side.
Example: Simple Object
$object = new StdClass;
$object->foo = 1;
$object->bar = 2;
var_dump( (array) $object );
Output:
array(2) {
'foo' => int(1)
'bar' => int(2)
}
Example: Complex Object
class Foo
{
private $foo;
protected $bar;
public $baz;
public function __construct()
{
$this->foo = 1;
$this->bar = 2;
$this->baz = new StdClass;
}
}
var_dump( (array) new Foo );
Output (with \0s edited in for clarity):
array(3) {
'\0Foo\0foo' => int(1)
'\0*\0bar' => int(2)
'baz' => class stdClass#2 (0) {}
}
Output with var_export instead of var_dump:
array (
'' . "\0" . 'Foo' . "\0" . 'foo' => 1,
'' . "\0" . '*' . "\0" . 'bar' => 2,
'baz' =>
stdClass::__set_state(array(
)),
)
Typecasting this way will not do deep casting of the object graph and you need to apply the null bytes (as explained in the manual quote) to access any non-public attributes. So this works best when casting StdClass objects or objects with only public properties. For quick and dirty (what you asked for) it's fine.
Also see this in-depth blog post:
Fast PHP Object to Array conversion
You can quickly convert deeply nested objects to associative arrays by relying on the behavior of the JSON encode/decode functions:
$array = json_decode(json_encode($nested_object), true);
From the first Google hit for "PHP object to assoc array" we have this:
function object_to_array($data)
{
if (is_array($data) || is_object($data))
{
$result = [];
foreach ($data as $key => $value)
{
$result[$key] = (is_array($value) || is_object($value)) ? object_to_array($value) : $value;
}
return $result;
}
return $data;
}
The source is at codesnippets.joyent.com.
To compare it to the solution of json_decode & json_encode, this one seems faster. Here is a random benchmark (using the simple time measuring):
$obj = (object) [
'name' =>'Mike',
'surname' =>'Jovanson',
'age' =>'45',
'time' =>1234567890,
'country' =>'Germany',
];
##### 100 000 cycles ######
* json_decode(json_encode($var)) : 4.15 sec
* object_to_array($var) : 0.93 sec
If your object properties are public you can do:
$array = (array) $object;
If they are private or protected, they will have weird key names on the array. So, in this case you will need the following function:
function dismount($object) {
$reflectionClass = new ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
}
return $array;
}
What about get_object_vars($obj)? It seems useful if you only want to access the public properties of an object.
See get_object_vars.
class Test{
const A = 1;
public $b = 'two';
private $c = test::A;
public function __toArray(){
return call_user_func('get_object_vars', $this);
}
}
$my_test = new Test();
var_dump((array)$my_test);
var_dump($my_test->__toArray());
Output
array(2) {
["b"]=>
string(3) "two"
["Testc"]=>
int(1)
}
array(1) {
["b"]=>
string(3) "two"
}
Type cast your object to an array.
$arr = (array) $Obj;
It will solve your problem.
Here is some code:
function object_to_array($data) {
if ((! is_array($data)) and (! is_object($data)))
return 'xxx'; // $data;
$result = array();
$data = (array) $data;
foreach ($data as $key => $value) {
if (is_object($value))
$value = (array) $value;
if (is_array($value))
$result[$key] = object_to_array($value);
else
$result[$key] = $value;
}
return $result;
}
All other answers posted here are only working with public attributes. Here is one solution that works with JavaBeans-like objects using reflection and getters:
function entity2array($entity, $recursionDepth = 2) {
$result = array();
$class = new ReflectionClass(get_class($entity));
foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
$methodName = $method->name;
if (strpos($methodName, "get") === 0 && strlen($methodName) > 3) {
$propertyName = lcfirst(substr($methodName, 3));
$value = $method->invoke($entity);
if (is_object($value)) {
if ($recursionDepth > 0) {
$result[$propertyName] = $this->entity2array($value, $recursionDepth - 1);
}
else {
$result[$propertyName] = "***"; // Stop recursion
}
}
else {
$result[$propertyName] = $value;
}
}
}
return $result;
}
To convert an object into array just cast it explicitly:
$name_of_array = (array) $name_of_object;
You can also create a function in PHP to convert an object array:
function object_to_array($object) {
return (array) $object;
}
Use:
function readObject($object) {
$name = get_class ($object);
$name = str_replace('\\', "\\\\", $name); // Outcomment this line, if you don't use
// class namespaces approach in your project
$raw = (array)$object;
$attributes = array();
foreach ($raw as $attr => $val) {
$attributes[preg_replace('('.$name.'|\*|)', '', $attr)] = $val;
}
return $attributes;
}
It returns an array without special characters and class names.
You can easily use this function to get the result:
function objetToArray($adminBar){
$reflector = new ReflectionObject($adminBar);
$nodes = $reflector->getProperties();
$out = [];
foreach ($nodes as $node) {
$nod = $reflector->getProperty($node->getName());
$nod->setAccessible(true);
$out[$node->getName()] = $nod->getValue($adminBar);
}
return $out;
}
Use PHP 5 or later.
Short solution of #SpYk3HH
function objectToArray($o)
{
$a = array();
foreach ($o as $k => $v)
$a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v;
return $a;
}
Here is my recursive PHP function to convert PHP objects to an associative array:
// ---------------------------------------------------------
// ----- object_to_array_recursive --- function (PHP) ------
// ---------------------------------------------------------
// --- arg1: -- $object = PHP Object - required --
// --- arg2: -- $assoc = TRUE or FALSE - optional --
// --- arg3: -- $empty = '' (Empty String) - optional --
// ---------------------------------------------------------
// ----- Return: Array from Object --- (associative) -------
// ---------------------------------------------------------
function object_to_array_recursive($object, $assoc=TRUE, $empty='')
{
$res_arr = array();
if (!empty($object)) {
$arrObj = is_object($object) ? get_object_vars($object) : $object;
$i=0;
foreach ($arrObj as $key => $val) {
$akey = ($assoc !== FALSE) ? $key : $i;
if (is_array($val) || is_object($val)) {
$res_arr[$akey] = (empty($val)) ? $empty : object_to_array_recursive($val);
}
else {
$res_arr[$akey] = (empty($val)) ? $empty : (string)$val;
}
$i++;
}
}
return $res_arr;
}
// ---------------------------------------------------------
// ---------------------------------------------------------
Usage example:
// ---- Return associative array from object, ... use:
$new_arr1 = object_to_array_recursive($my_object);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, TRUE);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, 1);
// ---- Return numeric array from object, ... use:
$new_arr2 = object_to_array_recursive($my_object, FALSE);
Custom function to convert stdClass to an array:
function objectToArray($d) {
if (is_object($d)) {
// Gets the properties of the given object
// with get_object_vars function
$d = get_object_vars($d);
}
if (is_array($d)) {
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
return array_map(__FUNCTION__, $d);
} else {
// Return array
return $d;
}
}
Another custom function to convert Array to stdClass:
function arrayToObject($d) {
if (is_array($d)) {
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
return (object) array_map(__FUNCTION__, $d);
} else {
// Return object
return $d;
}
}
Usage Example:
// Create new stdClass Object
$init = new stdClass;
// Add some test data
$init->foo = "Test data";
$init->bar = new stdClass;
$init->bar->baaz = "Testing";
$init->bar->fooz = new stdClass;
$init->bar->fooz->baz = "Testing again";
$init->foox = "Just test";
// Convert array to object and then object back to array
$array = objectToArray($init);
$object = arrayToObject($array);
// Print objects and array
print_r($init);
echo "\n";
print_r($array);
echo "\n";
print_r($object);
First of all, if you need an array from an object you probably should constitute the data as an array first. Think about it.
Don't use a foreach statement or JSON transformations. If you're planning this, again you're working with a data structure, not with an object.
If you really need it use an object-oriented approach to have a clean and maintainable code. For example:
Object as array
class PersonArray implements \ArrayAccess, \IteratorAggregate
{
public function __construct(Person $person) {
$this->person = $person;
}
// ...
}
If you need all properties, use a transfer object:
class PersonTransferObject
{
private $person;
public function __construct(Person $person) {
$this->person = $person;
}
public function toArray() {
return [
// 'name' => $this->person->getName();
];
}
}
Also you can use The Symfony Serializer Component
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$array = json_decode($serializer->serialize($object, 'json'), true);
You might want to do this when you obtain data as objects from databases:
// Suppose 'result' is the end product from some query $query
$result = $mysqli->query($query);
$result = db_result_to_array($result);
function db_result_to_array($result)
{
$res_array = array();
for ($count=0; $row = $result->fetch_assoc(); $count++)
$res_array[$count] = $row;
return $res_array;
}
This answer is only the union of the different answers of this post, but it's the solution to convert a PHP object with public or private properties with simple values or arrays to an associative array...
function object_to_array($obj)
{
if (is_object($obj))
$obj = (array)$this->dismount($obj);
if (is_array($obj)) {
$new = array();
foreach ($obj as $key => $val) {
$new[$key] = $this->object_to_array($val);
}
}
else
$new = $obj;
return $new;
}
function dismount($object)
{
$reflectionClass = new \ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
}
return $array;
}
Some impovements to the "well-knwon" code
/*** mixed Obj2Array(mixed Obj)***************************************/
static public function Obj2Array($_Obj) {
if (is_object($_Obj))
$_Obj = get_object_vars($_Obj);
return(is_array($_Obj) ? array_map(__METHOD__, $_Obj) : $_Obj);
} // BW_Conv::Obj2Array
Notice that if the function is member of a class (like above) you must change __FUNCTION__ to __METHOD__
For your case it was right/beautiful if you would use the "decorator" or "date model transformation" patterns. For example:
Your model
class Car {
/** #var int */
private $color;
/** #var string */
private $model;
/** #var string */
private $type;
/**
* #return int
*/
public function getColor(): int
{
return $this->color;
}
/**
* #param int $color
* #return Car
*/
public function setColor(int $color): Car
{
$this->color = $color;
return $this;
}
/**
* #return string
*/
public function getModel(): string
{
return $this->model;
}
/**
* #param string $model
* #return Car
*/
public function setModel(string $model): Car
{
$this->model = $model;
return $this;
}
/**
* #return string
*/
public function getType(): string
{
return $this->type;
}
/**
* #param string $type
* #return Car
*/
public function setType(string $type): Car
{
$this->type = $type;
return $this;
}
}
Decorator
class CarArrayDecorator
{
/** #var Car */
private $car;
/**
* CarArrayDecorator constructor.
* #param Car $car
*/
public function __construct(Car $car)
{
$this->car = $car;
}
/**
* #return array
*/
public function getArray(): array
{
return [
'color' => $this->car->getColor(),
'type' => $this->car->getType(),
'model' => $this->car->getModel(),
];
}
}
Usage
$car = new Car();
$car->setType('type#');
$car->setModel('model#1');
$car->setColor(255);
$carDecorator = new CarArrayDecorator($car);
$carResponseData = $carDecorator->getArray();
So it will be more beautiful and more correct code.
Converting and removing annoying stars:
$array = (array) $object;
foreach($array as $key => $val)
{
$new_array[str_replace('*_', '', $key)] = $val;
}
Probably, it will be cheaper than using reflections.
I use this (needed recursive solution with proper keys):
/**
* This method returns the array corresponding to an object, including non public members.
*
* If the deep flag is true, is will operate recursively, otherwise (if false) just at the first level.
*
* #param object $obj
* #param bool $deep = true
* #return array
* #throws \Exception
*/
public static function objectToArray(object $obj, bool $deep = true)
{
$reflectionClass = new \ReflectionClass(get_class($obj));
$array = [];
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$val = $property->getValue($obj);
if (true === $deep && is_object($val)) {
$val = self::objectToArray($val);
}
$array[$property->getName()] = $val;
$property->setAccessible(false);
}
return $array;
}
Example of usage, the following code:
class AA{
public $bb = null;
protected $one = 11;
}
class BB{
protected $two = 22;
}
$a = new AA();
$b = new BB();
$a->bb = $b;
var_dump($a)
Will print this:
array(2) {
["bb"] => array(1) {
["two"] => int(22)
}
["one"] => int(11)
}
There's my proposal, if you have objects in objects with even private members:
public function dismount($object) {
$reflectionClass = new \ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
if (is_object($property->getValue($object))) {
$array[$property->getName()] = $this->dismount($property->getValue($object));
} else {
$array[$property->getName()] = $property->getValue($object);
}
$property->setAccessible(false);
}
return $array;
}
Since a lot of people find this question because of having trouble with dynamically access attributes of an object, I will just point out that you can do this in PHP: $valueRow->{"valueName"}
In context (removed HTML output for readability):
$valueRows = json_decode("{...}"); // Rows of unordered values decoded from a JSON object
foreach ($valueRows as $valueRow) {
foreach ($references as $reference) {
if (isset($valueRow->{$reference->valueName})) {
$tableHtml .= $valueRow->{$reference->valueName};
}
else {
$tableHtml .= " ";
}
}
}
I think it is a nice idea to use traits to store object-to-array converting logic. A simple example:
trait ArrayAwareTrait
{
/**
* Return list of Entity's parameters
* #return array
*/
public function toArray()
{
$props = array_flip($this->getPropertiesList());
return array_map(
function ($item) {
if ($item instanceof \DateTime) {
return $item->format(DATE_ATOM);
}
return $item;
},
array_filter(get_object_vars($this), function ($key) use ($props) {
return array_key_exists($key, $props);
}, ARRAY_FILTER_USE_KEY)
);
}
/**
* #return array
*/
protected function getPropertiesList()
{
if (method_exists($this, '__sleep')) {
return $this->__sleep();
}
if (defined('static::PROPERTIES')) {
return static::PROPERTIES;
}
return [];
}
}
class OrderResponse
{
use ArrayAwareTrait;
const PROP_ORDER_ID = 'orderId';
const PROP_TITLE = 'title';
const PROP_QUANTITY = 'quantity';
const PROP_BUYER_USERNAME = 'buyerUsername';
const PROP_COST_VALUE = 'costValue';
const PROP_ADDRESS = 'address';
private $orderId;
private $title;
private $quantity;
private $buyerUsername;
private $costValue;
private $address;
/**
* #param $orderId
* #param $title
* #param $quantity
* #param $buyerUsername
* #param $costValue
* #param $address
*/
public function __construct(
$orderId,
$title,
$quantity,
$buyerUsername,
$costValue,
$address
) {
$this->orderId = $orderId;
$this->title = $title;
$this->quantity = $quantity;
$this->buyerUsername = $buyerUsername;
$this->costValue = $costValue;
$this->address = $address;
}
/**
* #inheritDoc
*/
public function __sleep()
{
return [
static::PROP_ORDER_ID,
static::PROP_TITLE,
static::PROP_QUANTITY,
static::PROP_BUYER_USERNAME,
static::PROP_COST_VALUE,
static::PROP_ADDRESS,
];
}
/**
* #return mixed
*/
public function getOrderId()
{
return $this->orderId;
}
/**
* #return mixed
*/
public function getTitle()
{
return $this->title;
}
/**
* #return mixed
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* #return mixed
*/
public function getBuyerUsername()
{
return $this->buyerUsername;
}
/**
* #return mixed
*/
public function getCostValue()
{
return $this->costValue;
}
/**
* #return string
*/
public function getAddress()
{
return $this->address;
}
}
$orderResponse = new OrderResponse(...);
var_dump($orderResponse->toArray());
$Menu = new Admin_Model_DbTable_Menu();
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu();
$Addmenu->populate($row->toArray());
Here I've made an objectToArray() method, which also works with recursive objects, like when $objectA contains $objectB which points again to $objectA.
Additionally I've restricted the output to public properties using ReflectionClass. Get rid of it, if you don't need it.
/**
* Converts given object to array, recursively.
* Just outputs public properties.
*
* #param object|array $object
* #return array|string
*/
protected function objectToArray($object) {
if (in_array($object, $this->usedObjects, TRUE)) {
return '**recursive**';
}
if (is_array($object) || is_object($object)) {
if (is_object($object)) {
$this->usedObjects[] = $object;
}
$result = array();
$reflectorClass = new \ReflectionClass(get_class($this));
foreach ($object as $key => $value) {
if ($reflectorClass->hasProperty($key) && $reflectorClass->getProperty($key)->isPublic()) {
$result[$key] = $this->objectToArray($value);
}
}
return $result;
}
return $object;
}
To identify already used objects, I am using a protected property in this (abstract) class, named $this->usedObjects. If a recursive nested object is found, it will be replaced by the string **recursive**. Otherwise it would fail in because of infinite loop.
By using typecasting you can resolve your problem.
Just add the following lines to your return object:
$arrObj = array(yourReturnedObject);
You can also add a new key and value pair to it by using:
$arrObj['key'] = value;

View and debug prepared PDO query without looking at MySQL logs

I want to see what PDO is preparing without looking into the MySQL logs. Basically the final query it has built right before it executes the query.
Is there a way to do this?
There is no built-in way to do it. bigwebguy created a function to do it in one of his answers:
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* #param string $query The sql query with parameter placeholders
* #param array $params The array of substitution parameters
* #return string The interpolated query
*/
public static function interpolateQuery($query, $params) {
$keys = array();
# build a regular expression for each parameter
foreach ($params as $key => $value) {
if (is_string($key)) {
$keys[] = '/:'.$key.'/';
} else {
$keys[] = '/[?]/';
}
}
$query = preg_replace($keys, $params, $query, 1, $count);
#trigger_error('replaced '.$count.' keys');
return $query;
}
This is just a derivation of #Maerlyn code above which accept non-asociative arrays for params like and where if the key starts already with ':' don't add it.
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* #param string $query The sql query with parameter placeholders
* #param array $params The array of substitution parameters
* #return string The interpolated query
*
* #author maerlyn https://stackoverflow.com/users/308825/maerlyn
*/
function interpolateQuery($query, $params) {
$keys = array();
# build a regular expression for each parameter
if (!isAssoc($params)){
$_params = []; // associative array
foreach($params as $param){
$key = $param[0];
$value = $param[1];
// $type = $param[2];
$_params[$key] = $value;
}
$params = $_params;
}
foreach ($params as $key => $value) {
if (is_string($key)) {
$keys[] = '/'.((substr($key,0,1)==':') ? '' : ':').$key.'/';
} else {
$keys[] = '/[?]/';
}
}
$query = preg_replace($keys, $params, $query, 1, $count);
#trigger_error('replaced '.$count.' keys');
return $query;
}

Convert a PHP object to an associative array

I'm integrating an API to my website which works with data stored in objects while my code is written using arrays.
I'd like a quick-and-dirty function to convert an object to an array.
Just typecast it
$array = (array) $yourObject;
From Arrays:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side.
Example: Simple Object
$object = new StdClass;
$object->foo = 1;
$object->bar = 2;
var_dump( (array) $object );
Output:
array(2) {
'foo' => int(1)
'bar' => int(2)
}
Example: Complex Object
class Foo
{
private $foo;
protected $bar;
public $baz;
public function __construct()
{
$this->foo = 1;
$this->bar = 2;
$this->baz = new StdClass;
}
}
var_dump( (array) new Foo );
Output (with \0s edited in for clarity):
array(3) {
'\0Foo\0foo' => int(1)
'\0*\0bar' => int(2)
'baz' => class stdClass#2 (0) {}
}
Output with var_export instead of var_dump:
array (
'' . "\0" . 'Foo' . "\0" . 'foo' => 1,
'' . "\0" . '*' . "\0" . 'bar' => 2,
'baz' =>
stdClass::__set_state(array(
)),
)
Typecasting this way will not do deep casting of the object graph and you need to apply the null bytes (as explained in the manual quote) to access any non-public attributes. So this works best when casting StdClass objects or objects with only public properties. For quick and dirty (what you asked for) it's fine.
Also see this in-depth blog post:
Fast PHP Object to Array conversion
You can quickly convert deeply nested objects to associative arrays by relying on the behavior of the JSON encode/decode functions:
$array = json_decode(json_encode($nested_object), true);
From the first Google hit for "PHP object to assoc array" we have this:
function object_to_array($data)
{
if (is_array($data) || is_object($data))
{
$result = [];
foreach ($data as $key => $value)
{
$result[$key] = (is_array($value) || is_object($value)) ? object_to_array($value) : $value;
}
return $result;
}
return $data;
}
The source is at codesnippets.joyent.com.
To compare it to the solution of json_decode & json_encode, this one seems faster. Here is a random benchmark (using the simple time measuring):
$obj = (object) [
'name' =>'Mike',
'surname' =>'Jovanson',
'age' =>'45',
'time' =>1234567890,
'country' =>'Germany',
];
##### 100 000 cycles ######
* json_decode(json_encode($var)) : 4.15 sec
* object_to_array($var) : 0.93 sec
If your object properties are public you can do:
$array = (array) $object;
If they are private or protected, they will have weird key names on the array. So, in this case you will need the following function:
function dismount($object) {
$reflectionClass = new ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
}
return $array;
}
What about get_object_vars($obj)? It seems useful if you only want to access the public properties of an object.
See get_object_vars.
class Test{
const A = 1;
public $b = 'two';
private $c = test::A;
public function __toArray(){
return call_user_func('get_object_vars', $this);
}
}
$my_test = new Test();
var_dump((array)$my_test);
var_dump($my_test->__toArray());
Output
array(2) {
["b"]=>
string(3) "two"
["Testc"]=>
int(1)
}
array(1) {
["b"]=>
string(3) "two"
}
Type cast your object to an array.
$arr = (array) $Obj;
It will solve your problem.
Here is some code:
function object_to_array($data) {
if ((! is_array($data)) and (! is_object($data)))
return 'xxx'; // $data;
$result = array();
$data = (array) $data;
foreach ($data as $key => $value) {
if (is_object($value))
$value = (array) $value;
if (is_array($value))
$result[$key] = object_to_array($value);
else
$result[$key] = $value;
}
return $result;
}
All other answers posted here are only working with public attributes. Here is one solution that works with JavaBeans-like objects using reflection and getters:
function entity2array($entity, $recursionDepth = 2) {
$result = array();
$class = new ReflectionClass(get_class($entity));
foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
$methodName = $method->name;
if (strpos($methodName, "get") === 0 && strlen($methodName) > 3) {
$propertyName = lcfirst(substr($methodName, 3));
$value = $method->invoke($entity);
if (is_object($value)) {
if ($recursionDepth > 0) {
$result[$propertyName] = $this->entity2array($value, $recursionDepth - 1);
}
else {
$result[$propertyName] = "***"; // Stop recursion
}
}
else {
$result[$propertyName] = $value;
}
}
}
return $result;
}
To convert an object into array just cast it explicitly:
$name_of_array = (array) $name_of_object;
You can also create a function in PHP to convert an object array:
function object_to_array($object) {
return (array) $object;
}
Use:
function readObject($object) {
$name = get_class ($object);
$name = str_replace('\\', "\\\\", $name); // Outcomment this line, if you don't use
// class namespaces approach in your project
$raw = (array)$object;
$attributes = array();
foreach ($raw as $attr => $val) {
$attributes[preg_replace('('.$name.'|\*|)', '', $attr)] = $val;
}
return $attributes;
}
It returns an array without special characters and class names.
You can easily use this function to get the result:
function objetToArray($adminBar){
$reflector = new ReflectionObject($adminBar);
$nodes = $reflector->getProperties();
$out = [];
foreach ($nodes as $node) {
$nod = $reflector->getProperty($node->getName());
$nod->setAccessible(true);
$out[$node->getName()] = $nod->getValue($adminBar);
}
return $out;
}
Use PHP 5 or later.
Short solution of #SpYk3HH
function objectToArray($o)
{
$a = array();
foreach ($o as $k => $v)
$a[$k] = (is_array($v) || is_object($v)) ? objectToArray($v): $v;
return $a;
}
Here is my recursive PHP function to convert PHP objects to an associative array:
// ---------------------------------------------------------
// ----- object_to_array_recursive --- function (PHP) ------
// ---------------------------------------------------------
// --- arg1: -- $object = PHP Object - required --
// --- arg2: -- $assoc = TRUE or FALSE - optional --
// --- arg3: -- $empty = '' (Empty String) - optional --
// ---------------------------------------------------------
// ----- Return: Array from Object --- (associative) -------
// ---------------------------------------------------------
function object_to_array_recursive($object, $assoc=TRUE, $empty='')
{
$res_arr = array();
if (!empty($object)) {
$arrObj = is_object($object) ? get_object_vars($object) : $object;
$i=0;
foreach ($arrObj as $key => $val) {
$akey = ($assoc !== FALSE) ? $key : $i;
if (is_array($val) || is_object($val)) {
$res_arr[$akey] = (empty($val)) ? $empty : object_to_array_recursive($val);
}
else {
$res_arr[$akey] = (empty($val)) ? $empty : (string)$val;
}
$i++;
}
}
return $res_arr;
}
// ---------------------------------------------------------
// ---------------------------------------------------------
Usage example:
// ---- Return associative array from object, ... use:
$new_arr1 = object_to_array_recursive($my_object);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, TRUE);
// -- or --
// $new_arr1 = object_to_array_recursive($my_object, 1);
// ---- Return numeric array from object, ... use:
$new_arr2 = object_to_array_recursive($my_object, FALSE);
Custom function to convert stdClass to an array:
function objectToArray($d) {
if (is_object($d)) {
// Gets the properties of the given object
// with get_object_vars function
$d = get_object_vars($d);
}
if (is_array($d)) {
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
return array_map(__FUNCTION__, $d);
} else {
// Return array
return $d;
}
}
Another custom function to convert Array to stdClass:
function arrayToObject($d) {
if (is_array($d)) {
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
return (object) array_map(__FUNCTION__, $d);
} else {
// Return object
return $d;
}
}
Usage Example:
// Create new stdClass Object
$init = new stdClass;
// Add some test data
$init->foo = "Test data";
$init->bar = new stdClass;
$init->bar->baaz = "Testing";
$init->bar->fooz = new stdClass;
$init->bar->fooz->baz = "Testing again";
$init->foox = "Just test";
// Convert array to object and then object back to array
$array = objectToArray($init);
$object = arrayToObject($array);
// Print objects and array
print_r($init);
echo "\n";
print_r($array);
echo "\n";
print_r($object);
First of all, if you need an array from an object you probably should constitute the data as an array first. Think about it.
Don't use a foreach statement or JSON transformations. If you're planning this, again you're working with a data structure, not with an object.
If you really need it use an object-oriented approach to have a clean and maintainable code. For example:
Object as array
class PersonArray implements \ArrayAccess, \IteratorAggregate
{
public function __construct(Person $person) {
$this->person = $person;
}
// ...
}
If you need all properties, use a transfer object:
class PersonTransferObject
{
private $person;
public function __construct(Person $person) {
$this->person = $person;
}
public function toArray() {
return [
// 'name' => $this->person->getName();
];
}
}
Also you can use The Symfony Serializer Component
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$array = json_decode($serializer->serialize($object, 'json'), true);
You might want to do this when you obtain data as objects from databases:
// Suppose 'result' is the end product from some query $query
$result = $mysqli->query($query);
$result = db_result_to_array($result);
function db_result_to_array($result)
{
$res_array = array();
for ($count=0; $row = $result->fetch_assoc(); $count++)
$res_array[$count] = $row;
return $res_array;
}
This answer is only the union of the different answers of this post, but it's the solution to convert a PHP object with public or private properties with simple values or arrays to an associative array...
function object_to_array($obj)
{
if (is_object($obj))
$obj = (array)$this->dismount($obj);
if (is_array($obj)) {
$new = array();
foreach ($obj as $key => $val) {
$new[$key] = $this->object_to_array($val);
}
}
else
$new = $obj;
return $new;
}
function dismount($object)
{
$reflectionClass = new \ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$array[$property->getName()] = $property->getValue($object);
$property->setAccessible(false);
}
return $array;
}
Some impovements to the "well-knwon" code
/*** mixed Obj2Array(mixed Obj)***************************************/
static public function Obj2Array($_Obj) {
if (is_object($_Obj))
$_Obj = get_object_vars($_Obj);
return(is_array($_Obj) ? array_map(__METHOD__, $_Obj) : $_Obj);
} // BW_Conv::Obj2Array
Notice that if the function is member of a class (like above) you must change __FUNCTION__ to __METHOD__
For your case it was right/beautiful if you would use the "decorator" or "date model transformation" patterns. For example:
Your model
class Car {
/** #var int */
private $color;
/** #var string */
private $model;
/** #var string */
private $type;
/**
* #return int
*/
public function getColor(): int
{
return $this->color;
}
/**
* #param int $color
* #return Car
*/
public function setColor(int $color): Car
{
$this->color = $color;
return $this;
}
/**
* #return string
*/
public function getModel(): string
{
return $this->model;
}
/**
* #param string $model
* #return Car
*/
public function setModel(string $model): Car
{
$this->model = $model;
return $this;
}
/**
* #return string
*/
public function getType(): string
{
return $this->type;
}
/**
* #param string $type
* #return Car
*/
public function setType(string $type): Car
{
$this->type = $type;
return $this;
}
}
Decorator
class CarArrayDecorator
{
/** #var Car */
private $car;
/**
* CarArrayDecorator constructor.
* #param Car $car
*/
public function __construct(Car $car)
{
$this->car = $car;
}
/**
* #return array
*/
public function getArray(): array
{
return [
'color' => $this->car->getColor(),
'type' => $this->car->getType(),
'model' => $this->car->getModel(),
];
}
}
Usage
$car = new Car();
$car->setType('type#');
$car->setModel('model#1');
$car->setColor(255);
$carDecorator = new CarArrayDecorator($car);
$carResponseData = $carDecorator->getArray();
So it will be more beautiful and more correct code.
Converting and removing annoying stars:
$array = (array) $object;
foreach($array as $key => $val)
{
$new_array[str_replace('*_', '', $key)] = $val;
}
Probably, it will be cheaper than using reflections.
I use this (needed recursive solution with proper keys):
/**
* This method returns the array corresponding to an object, including non public members.
*
* If the deep flag is true, is will operate recursively, otherwise (if false) just at the first level.
*
* #param object $obj
* #param bool $deep = true
* #return array
* #throws \Exception
*/
public static function objectToArray(object $obj, bool $deep = true)
{
$reflectionClass = new \ReflectionClass(get_class($obj));
$array = [];
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
$val = $property->getValue($obj);
if (true === $deep && is_object($val)) {
$val = self::objectToArray($val);
}
$array[$property->getName()] = $val;
$property->setAccessible(false);
}
return $array;
}
Example of usage, the following code:
class AA{
public $bb = null;
protected $one = 11;
}
class BB{
protected $two = 22;
}
$a = new AA();
$b = new BB();
$a->bb = $b;
var_dump($a)
Will print this:
array(2) {
["bb"] => array(1) {
["two"] => int(22)
}
["one"] => int(11)
}
There's my proposal, if you have objects in objects with even private members:
public function dismount($object) {
$reflectionClass = new \ReflectionClass(get_class($object));
$array = array();
foreach ($reflectionClass->getProperties() as $property) {
$property->setAccessible(true);
if (is_object($property->getValue($object))) {
$array[$property->getName()] = $this->dismount($property->getValue($object));
} else {
$array[$property->getName()] = $property->getValue($object);
}
$property->setAccessible(false);
}
return $array;
}
Since a lot of people find this question because of having trouble with dynamically access attributes of an object, I will just point out that you can do this in PHP: $valueRow->{"valueName"}
In context (removed HTML output for readability):
$valueRows = json_decode("{...}"); // Rows of unordered values decoded from a JSON object
foreach ($valueRows as $valueRow) {
foreach ($references as $reference) {
if (isset($valueRow->{$reference->valueName})) {
$tableHtml .= $valueRow->{$reference->valueName};
}
else {
$tableHtml .= " ";
}
}
}
I think it is a nice idea to use traits to store object-to-array converting logic. A simple example:
trait ArrayAwareTrait
{
/**
* Return list of Entity's parameters
* #return array
*/
public function toArray()
{
$props = array_flip($this->getPropertiesList());
return array_map(
function ($item) {
if ($item instanceof \DateTime) {
return $item->format(DATE_ATOM);
}
return $item;
},
array_filter(get_object_vars($this), function ($key) use ($props) {
return array_key_exists($key, $props);
}, ARRAY_FILTER_USE_KEY)
);
}
/**
* #return array
*/
protected function getPropertiesList()
{
if (method_exists($this, '__sleep')) {
return $this->__sleep();
}
if (defined('static::PROPERTIES')) {
return static::PROPERTIES;
}
return [];
}
}
class OrderResponse
{
use ArrayAwareTrait;
const PROP_ORDER_ID = 'orderId';
const PROP_TITLE = 'title';
const PROP_QUANTITY = 'quantity';
const PROP_BUYER_USERNAME = 'buyerUsername';
const PROP_COST_VALUE = 'costValue';
const PROP_ADDRESS = 'address';
private $orderId;
private $title;
private $quantity;
private $buyerUsername;
private $costValue;
private $address;
/**
* #param $orderId
* #param $title
* #param $quantity
* #param $buyerUsername
* #param $costValue
* #param $address
*/
public function __construct(
$orderId,
$title,
$quantity,
$buyerUsername,
$costValue,
$address
) {
$this->orderId = $orderId;
$this->title = $title;
$this->quantity = $quantity;
$this->buyerUsername = $buyerUsername;
$this->costValue = $costValue;
$this->address = $address;
}
/**
* #inheritDoc
*/
public function __sleep()
{
return [
static::PROP_ORDER_ID,
static::PROP_TITLE,
static::PROP_QUANTITY,
static::PROP_BUYER_USERNAME,
static::PROP_COST_VALUE,
static::PROP_ADDRESS,
];
}
/**
* #return mixed
*/
public function getOrderId()
{
return $this->orderId;
}
/**
* #return mixed
*/
public function getTitle()
{
return $this->title;
}
/**
* #return mixed
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* #return mixed
*/
public function getBuyerUsername()
{
return $this->buyerUsername;
}
/**
* #return mixed
*/
public function getCostValue()
{
return $this->costValue;
}
/**
* #return string
*/
public function getAddress()
{
return $this->address;
}
}
$orderResponse = new OrderResponse(...);
var_dump($orderResponse->toArray());
$Menu = new Admin_Model_DbTable_Menu();
$row = $Menu->fetchRow($Menu->select()->where('id = ?', $id));
$Addmenu = new Admin_Form_Addmenu();
$Addmenu->populate($row->toArray());
Here I've made an objectToArray() method, which also works with recursive objects, like when $objectA contains $objectB which points again to $objectA.
Additionally I've restricted the output to public properties using ReflectionClass. Get rid of it, if you don't need it.
/**
* Converts given object to array, recursively.
* Just outputs public properties.
*
* #param object|array $object
* #return array|string
*/
protected function objectToArray($object) {
if (in_array($object, $this->usedObjects, TRUE)) {
return '**recursive**';
}
if (is_array($object) || is_object($object)) {
if (is_object($object)) {
$this->usedObjects[] = $object;
}
$result = array();
$reflectorClass = new \ReflectionClass(get_class($this));
foreach ($object as $key => $value) {
if ($reflectorClass->hasProperty($key) && $reflectorClass->getProperty($key)->isPublic()) {
$result[$key] = $this->objectToArray($value);
}
}
return $result;
}
return $object;
}
To identify already used objects, I am using a protected property in this (abstract) class, named $this->usedObjects. If a recursive nested object is found, it will be replaced by the string **recursive**. Otherwise it would fail in because of infinite loop.
By using typecasting you can resolve your problem.
Just add the following lines to your return object:
$arrObj = array(yourReturnedObject);
You can also add a new key and value pair to it by using:
$arrObj['key'] = value;

Categories