Fetch multi-row, single-column array using Doctrine - php

I have a Doctrine fetch statement like this
$query = "SELECT id FROM table LIMIT 2";
$result = $db->fetchAll($query);
which returns the array like this:
Array
(
[0] => Array
(
[id] => 1
)
[1] => Array
(
[id] => 2
)
)
Since the only column I fetch is ID, I don't need the array scope do be that deep. Is there a convenient way of making Doctrine return the results in a "flat" array, similar to what what PDO does:
$result = $db->query($query)->fetchAll(PDO::FETCH_COLUMN);
will return
Array
(
[0] => 1
[1] => 2
)
Currently I am flattening it using
$result = call_user_func_array('array_merge', array_map("array_values", $result));

You can simply use the PDO functionality (at least if you have MySQL).
$ids = $db
->executeQuery($query)
->fetchAll(\PDO::FETCH_COLUMN)
;

To resolve this problem you have to make your custom doctrine hydrator.
First: Make your own hydrator
<?php
namespace MyProject\Hydrators;
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
class CustomHydrator extends AbstractHydrator
{
protected function _hydrateAll()
{
return $this->_stmt->fetchAll(PDO::FETCH_COLUMN);
}
}
Add your hydrator to Doctrine configuration file :
<?php
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator','MyProject\Hydrators\CustomHydrator');
Finaly you can use your cutom hidrator :
<?php
$query = $em->createQuery('SELECT u FROM CmsUser u');
$results = $query->getResult('CustomHydrator');

I found a method called fetchFirstColumn which appears to do this. This was probably added in a later version of doctrine. I am currently on Doctrine ORM 2.7.4.
I am using it like this in Symfony:
$statement = $connection->prepare('SELECT foo FROM bar WHERE baz = :baz');
$statement->execute([':baz' => 1]);
$result = $statement->fetchFirstColumn();
The value of $result will be a numerically indexed array starting at 0 like this:
[
0 => 'foo1',
1 => 'foo2'
];

Fetch the data using fetchAssoc:
$result = $db->query($query)->fetchAssoc(PDO::FETCH_COLUMN);
You will get an Array like this:
Array (
[id] => 11
)

Related

PHP Multidimensional Array Merge Issue

I am running a query that outputs a multidimensional array like this: -
Array
(
[0] => Array
(
[0] => Array
(
[id] => 772
[display_name] => Test Company Ltd
[profile_page] => partners/test-company
)
)
[1] => Array
(
)
[2] => Array
(
[0] => Array
(
[id] => 772
[display_name] => Test Company Ltd
[profile_page] => partners/test-company
)
)
I am trying to make the Array look like this so that we can loop through it on our site: -
Array
(
[0] => Array
(
[id] => 772
[display_name] => Test Company Ltd
[profile_page] => partners/test-company
)
)
This is all being generated using PHP using Symfony2 and Doctrine2. I have tried a couple of methods to get this working but I have reverted back to my first method which is this: -
$companies = array();
foreach($postcodes as $key=>$value) {
$conn = $em->getConnection();
$query = $conn->prepare("SELECT a.id, a.display_name, a.profile_page, b.meta_data FROM companies a, `cms`.pages b WHERE b.slug = a.profile_page AND a.active = 1 AND a.postcode = ".$value." ORDER BY a.display_name ASC");
$execute = $query->execute();
$companies[] = array_replace_recursive($query->fetchAll());
}
echo '<pre>'; print_r($companies); echo '</pre>';
die();
If someone can show me how to get around this, that would be great.
$query->fetchAll() is itself is an multidimensional array you're in need.
Just replace following line
$companies[] = array_replace_recursive($query->fetchAll());
with
$innCompnies=$query->fetchAll();
foreach($innCompnies as $inComp) {
$companies[]=$inComp;
}
It wasn't working because you were pushing multidimensional array into another array. What we actually need to do is to push element one by one into the main array.
I suggest you to avoid SQL-queries in loop. Also you have potential SQL-injection vulnerability concatenating postcodes to your query. So the possible solution may be replacing your foreach loop with something like:
$companies = $conn->fetchAll(
"SELECT a.id, a.display_name, a.profile_page, b.meta_data FROM companies a, `cms`.pages b WHERE b.slug = a.profile_page AND a.active = 1 AND a.postcode IN :postcodes ORDER BY a.display_name ASC",
compact('postcodes')
);
you can transform the multidimentional array like this.
$new_companies = array();
array_walk($companies, function($companie) use($companies, &$new_companies){
if(is_array($companie)) {
foreach ($companie as $c) {
$new_companies[] = $c;
}
}
});
$new_companies is what you want.

Doctrine DBAL 2: fetchAll() unnecessary array dimensions

In doctrine DBAL2 when I execute a query like this:
<?php
$connection = $this->getDatabaseConnection();
$sql = "SELECT page_url
FROM cms_user_page
WHERE site_id = :siteid
AND active = '1'
";
$stmt = $connection->prepare($sql);
$stmt->bindValue("siteid", $id);
$stmt->execute();
return $stmt->fetchAll();
?>
I get a result like this:
Array
(
[0] => Array
(
[page_url] => index.php?action=login
)
[1] => Array
(
[page_url] => index.php?action=shoppingcart
)
[2] => Array
(
[page_url] => index.php?action=products
)
)
My question is, is there a fetch mode that produces an result like this:
Array
(
[0] => index.php?action=login
[1] => index.php?action=shoppingcart
[2] => index.php?action=products
)
I could not find any info about fetch modes in the documentation. and i could do an array map. But thats overhead in my opinion..
You can pass a fetch mode parameter to fetchAll().
$stmt->fetchAll(\PDO::FETCH_COLUMN)
This answer has been edited because this answer is correct.
You can use the FETCH_COLUMN fetch mode in fetchAll():
$stmt->fetchAll(\PDO::FETCH_COLUMN)
As another user points out in the comments, fetchAll() can return data formatted in a multitude of interesting formats.
Or you can iterate with fetchColumn():
while($page_url = $stmt->fetchColumn()) {
echo $page_url . PHP_EOL;
}
As of PHP5.5 you could use aray_column to achieve required result like so:
<?php
$connection = $this->getDatabaseConnection();
$sql = "SELECT page_url
FROM cms_user_page
WHERE site_id = :siteid
AND active = '1'
";
$stmt = $connection->prepare($sql);
$stmt->bindValue("siteid", $id);
$stmt->execute();
$data = array_column($stmt->fetchAll(), 'page_url');
return $data;
If you have more than one case where you need that form of result, although i dont really understand the sense too, you could implement AbstractHydrator interface to create your own ArrayHydrator that returns the structure as you need it.
Hydration Classes reside in NS:
Doctrine\ORM\Internal\Hydration
It looks like fetchAll was made deprecated in a recent version of DBAL. However I found another method called fetchFirstColumn which appears to do the same thing as fetchAll(\PDO::FETCH_COLUMN). I am currently on version 2.11.1 Doctrine DBAL.
I am using it like this in Symfony:
$statement = $connection->prepare('SELECT foo FROM bar WHERE baz = :baz');
$statement->execute([':baz' => 1]);
$result = $statement->fetchFirstColumn();
The value of $result will be a numerically indexed array starting at 0 like this:
[
0 => 'foo1',
1 => 'foo2'
];
As soon as you're requesting multiple rows in a database it does not make sense.
RDBMS stores rows and columns so the result is represented as rows and columns.
In the programming world it is called a matrix, in the PHP world it is an array.
________________
| id | name |
|______|_________|
| 1 | foo |
|______|_________|
| 2 | bar |
|______|_________|
will results in
array(
0 => array(
'id' => 1,
'name' => 'foo',
),
1 => array(
'id' => 2,
'name' => 'foo',
)
);
So no, you can't do that, you'd rather to process the result to fit your needs.

PHP - Removing one array layer

I have a simple PHP function that will grab information from a database based on a unique ID:
function oracleGetGata($query, $id="id") {
global $conn;
$results = array();
$sql = OCI_Parse($conn, $query);
OCI_Execute($sql);
while ( false!==($row=oci_fetch_assoc($sql)) ) {
$results[ $row[$id] ] = $row;
}
return $results;
}
So for example $array = oracleGetData('select * from table') would return:
[1] => Array
(
[Title] => Title 1
[Description] => Description 1
)
[2] => Array
(
[Title] => Title 2
[Description] => Description 2
)
This is fine, however, if I just want to return one record $array = oracleGetData('select * from table where id = 1') it returns the data like:
[] => Array
(
[Title] => Title 1
[Description] => Description 1
)
Not only am I unsure of how to reference this (there is nothing identifying the array) I'd also like to somehow change my function so if it just returns one record, it will just be a simple one dimensional array.
I've looked into the usual PHP array functions but can't find anything that'll help, nor an easy way of identifying how deep the array is.
Would really appreciate any help, thank you
Use array_pop():
$array = array_pop(oracleGetData('select * from table where id = 1'));
You will then get one single array:
Array
(
[Title] => Title 1
[Description] => Description 1
)
Instead of an array embedded in another one:
Array
(
[] => Array
(
[Title] => Title 1
[Description] => Description 1
)
}
I think there is an logic error in your script:
Change
$results[ $row[$id] ] = $row;
into
$results[] = $row;
The problem is, that you want to have the Database key value as array key value, but you don't know the Database key, since you don't know what the query will look like.
You could try:
$results[$row['id']] = $row;
But this only works when all of your results have a Database key named "id".
You pass a $id in the function signature, but in the loop you uses $row[$id], Why? Maybe the error is there.
If you want a sequencial id in your result set, you don't need use the $id, you can uses array_push() function
array_push($result, $row);
OR
$results[] = $row;

Object Oriented PHP return database row and access array elements

I am new to the concept of Object Oriented PHP (following the tutorial on www.killerphp.com) and I am planning to migrate all my php applications to OO PHP.
I started constructing my first class which reads authorization levels from database based on object properties in the "where" condition set by method "setSecurity()".
I managed to return the array "getSecurity()" but printing the output would give:
security Object
(
[secArray] => Array
(
[from_date1] => 1992-01-01
[to_date1] => 0000-00-00
[from_date2] => 1992-01-01
[to_date2] => 0000-00-00
[view] => 1
[insert] => 0
[update] => 1
[delete] => 1
[valid] => 1
)
)
/*"Array 1"*/
My problem is that I am not familiar with the printed output to that of a normal array (below).
Array
(
[from_date1] => 1992-01-01
[to_date1] => 0000-00-00
[from_date2] => 1992-01-01
[to_date2] => 0000-00-00
[view] => 1
[insert] => 0
[update] => 1
[delete] => 1
[valid] => 1
)
/*"Array 2"*/
My questions are:
1) How can I access the elements of my array from getSecurity() method (from Array 1)?
2) How can I get my method to return the array properly (same as Array 2)?
Code Snippets found below.
Thank you very much for any support...
'test.php'
<?php
include("connect.php");
include("security.php");
$secArray=new security();
$secArray->setSecurity('test_user',1,1,1,$link);
$secArray->getSecurity();
echo "<pre>"; print_r($secArray); echo "</pre>";
?>
'security.php'
<?php
class security
{
public $secArray = array();
function setSecurity($user,$appid,$funid,$objid,$conn='')
{
$query="SELECT lu.DATE1 as from_date1,
lu.DATE2 as to_date1,
ga.DATE1 as from_date2,
ga.DATE2 as to_date2,
ga.VIEW as view,
ga.INSERT as insert,
ga.UPDATE as update,
ga.DELETE as delete,
ob.VALID as valid
FROM
user as lu
inner join group as ug on lu.GRP_ID = ug.ID
inner join privileges as ga on lu.GRP_ID = ga.GRP_ID
and ug.ID = ga.GRP_ID
inner join level1 as ob on ob.APP_ID = ga.APP_ID
and ob.FUN_ID = ga.FUN_ID
and ob.ID = ga.OBJ_ID
where
USERID = '$user'
and ga.APP_ID = $appid
and ga.FUN_ID = $funid
and ga.OBJ_ID = $objid";
$result = mysql_query($query,$conn);
$row = mysql_fetch_assoc($result);
$this->secArray=$row;
}
function getSecurity()
{
return $this->secArray;
}
}
?>
The getter returns a value so calling $secArray->getSecurity(); doesn't really help you unless you do something with the value returned. $mySecurity=$secArray->getSecurity(); use $mySecurity...
Please read PHP documentation on accessing arrays and objects.

PHP class array question

For some reason my array I am returning is not what I expect. Could someone explain to me why I am getting the current results, and what I can do to fix it? Here is the code in question:
public static function getProduct($_row, $_value)
{
$stmt = _DB::init()->prepare("SELECT pid, name, quantity, price, cost
FROM products
WHERE $_row = ?"
);
if($stmt->execute(array($_value)))
{
while ($row = $stmt->fetch())
return $row;
}
}
$product = Class::getProduct('pid',1);
print_r($product);
When I print the following array I am getting two results per row like so:
Array ( [pid] => 1 [0] => 1 [name] => Boondoggle [1] => Boondoggle [quantity] => 12 [2] => 12 [price] => 9.9900 [3] => 9.9900 [cost] => 12.9900 [4] => 12.9900 ) Boondoggle
I was only wanting to show the associative results. What is wrong with my function?
From the looks of it you are using PDO to communicate with your DBMS. The PDOStatement::fetch() method's first argument is a parameter to tell it what to return. By default it returns each column in both name format and numbered index format to allow iterating through columns easier. To just get the column names as indexes, you can pass it PDO::FETCH_ASSOC to your call. So the fetch statement would look like this:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)
See here for more details:
http://www.php.net/manual/en/pdostatement.fetch.php
Pass PDO::FETCH_ASSOC to your fetch call:
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
edit: I'm just assuming you're using PDO, of course

Categories