Doctrine ORM HYDRATE_SCALAR vs HYDRATE_ARRAY - doctrine-orm

I'm trying to get all values of a column from a table through Doctrine ORM using following query:
SELECT item.templateId FROM MyBundle:Item item WHERE item.id IN (:ids)
I know Doctrine has hydration mode Query::HYDRATE_SINGLE_SCALAR which returns single scalar value. When, however, having more than one record in result it throws NonUniqueResultException which is fine.
Naturally, I guessed that Query::HYDRATE_SCALAR would do the trick. However, it returns exactly the same result as when using Query::HYDRATE_ARRAY.
Code:
$ids = [1, 2, 3];
$query = $this->entityManager->createQuery('
SELECT item.templateId FROM MyBundle:Item item WHERE item.id IN (:ids)
')
->setParameter('ids', $ids)
;
// Regardles whether I use HYDRATE_SCALAR or HYDRATE_ARRAY
// $result is the same
$result = $query->getResult(Query::HYDRATE_SCALAR);
Here is how $result looks in both cases:
Array
(
[0] => Array
(
[templateId] => 52
)
[1] => Array
(
[templateId] => 90
)
[2] => Array
(
[templateId] => 89
)
)
How I wish it looked:
Array
(
[0] => 52
[1] => 90
[2] => 89
)
I know I can transform it into the form I want, but I wonder why HYDRATE_SCALAR isn't behaving as I expect it to.

I think it behaves like this because, as the documentation says :
[it] can contain duplicate data.
That's when array_column (php 5.5) comes into play.

Try this:
$result = $query->getResult(Query::HYDRATE_SCALAR);
return array_map('reset', $result);
There you go :)

10 years later, I'm adding another answer, that I will hope is better.
Once again, the documentation I mentioned 10 years ago is helpful:
Query#getArrayResult(): Retrieves an array graph (a nested array) that is largely interchangeable with the object graph generated by Query#getResult() for read-only purposes. .. note:: An array graph can differ from the corresponding object graph in certain scenarios due to the difference of the identity semantics between arrays and objects.
Query#getScalarResult(): Retrieves a flat/rectangular result set of scalar values that can contain duplicate data. The pure/mixed distinction does not apply.
ORM means Object-relational mapper: it maps an RDBMS with an object graph. One one hand you have tabular data, on the other hand you have objects that can be related to each other.
When using getArrayResult(), you will get an array graph, meaning something (deeply) nested, like a JSON document.
When using getScalarResult(), there will be little to no intervention besides converting column names to field names, and that's why it can contain duplicate data. So for instance, If you write a query that retrieves a user with 2 phonenumbers, the former will give you something like
[0 => [
'lastname' => 'Anderson',
'firstname' => 'Thomas',
'phoneNumbers' => [[
'alias' => 'home',
'number' => '0123456789',
], [
'alias' => 'work',
'number' => '987654321',
]],
]]
The latter will give you something flat and duplicated, like this:
[0 => [
'lastname' => 'Anderson',
'firstname' => 'Thomas',
'alias' => 'work',
'number' => '987654321',
],
],
1 => [
'lastname' => 'Anderson',
'firstname' => 'Thomas',
'alias' => 'work',
'number' => '987654321',
]]
Of course, if your query is simple enough, there is no difference.

Related

Regex patter for SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'abc' at row 1

I am writing validation rule for double data type numeric value column in Laravel but following regex is not validating and error goes to database, can you please suggest which rule is right
$data=Request::all();
$validator = Validator::make($data, [
'abc' => array(
'required',
'regex:/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?([eE][-+]?[0-9]+)?/u'
),
]);
This patter also not working. /\d+\.\d*|\.?\d+/

Sublime text: Replace every nth occurrence of comma using regex

I have a file with hundreds of line like quoted below. I want to change the indexed array to an associative array by adding keys.
(['Maricao', 'PR', '00606', '18.182778', '-66.980278']),
so after the process, what I need is
(['name' =>'Maricao', 'code' => 'PR', 'zip' => '00606', 'lat' => '18.182778', ' lng' =>'-66.980278']),
Assuming the keys and order are the same. Find:
('[^']+', )('[^']+', )('[^']+', )('[^']+', )('[^']+')
Replace with:
'name' => \1'code' => \2'zip' => \3'lat' => \4'lng' => \5

Doctrine retrieve indexes of selected columns only

I am currently refactoring an application written in Symfony 3 and relies heavily on Doctrine ORM and I'm stuck trying to get an object/array with indexes of my selected columns.
Now I am fairly familiar with PHP PDO and as I recall a basic fetch of query results as shown below
$sth->fetchAll();
(Depending on my query) it would give me an array similar to the one below
[0] => Array
(
[name] => pear
[0] => pear
[colour] => green
[1] => green
)
[1] => Array
(
[name] => watermelon
[0] => watermelon
[colour] => pink
[1] => pink
)
With Doctrine i have tried to use several inbuilt functions with Hydration parameters
$query->getResult();
And with no luck I end up getting something like this
Array
(
[0] => Array
(
[name] => pear
[colour] => green
)
[1] => Array
(
[name] => Watermelon
[colour] => Pink
)
)
Can someone help me or point me in the right direction how to properly have this sorted out?
------Updated the question to include the full method I am currently using----
public function getDepartmentCount()
{
$qb = $this->createQueryBuilder('fruit')
->leftJoin('fruit.color','color')
$query=$qb->getQuery();
return $query->getArrayResult(); //Method that possibly needs to be changed
}
I have been able to solve this on my own after creating a custom Hydrator.
I will keep the solution here for anyone who might face a similar problem.
Below is a class for the custom Hydrator
namespace AppBundle\Doctrine;
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
use PDO;
class CustomHydrator extends AbstractHydrator
{
/**
* Hydrates all rows from the current statement instance at once.
*
* #return array
*/
protected function hydrateAllData()
{
// TODO: Implement hydrateAllData() method.
return $this->_stmt->fetchAll(PDO::FETCH_NUM);
}
}
Added this in my config file under the orm section to tell Symfony where to find the Custom Hydrator and its name
hydrators:
GridDataHydrator: AppBundle\Doctrine\CustomHydrator
And Finally executed the query using this method
$query->getResult('GridDataHydrator');

filter a List according to multiple contains

I want to filter a List, and I only want to keep a string if the string contains .jpg,.jpeg or .png:
scala> var list = List[String]("a1.png","a2.amr","a3.png","a4.jpg","a5.jpeg","a6.mp4","a7.amr","a9.mov","a10.wmv")
list: List[String] = List(a1.png, a2.amr, a3.png, a4.jpg, a5.jpeg, a6.mp4, a7.amr, a9.mov, a10.wmv)
I am not finding that .contains will help me!
Required output:
List("a1.png","a3.png","a4.jpg","a5.jpeg")
Use filter method.
list.filter( name => name.contains(pattern1) || name.contains(pattern2) )
If you have undefined amount of extentions:
val extensions = List("jpg", "png")
list.filter( p => extensions.exists(e => p.matches(s".*\\.$e$$")))
To select anything that contains one of an arbitrary number of extensions:
list.filter(p => extensions.exists(e => p.contains(e)))
Which is what #SergeyLagutin said above, but I thought I'd point out it doesn't need matches.
Why not use filter() with an appropriate function performing your selection/predicate?
e.g.
list.filter(x => x.endsWith(".jpg") || x.endsWith(".jpeg")
etc.

Ignore returned expression in DQL

I have a DQL query containing a SELECT expression that's only used for ordering:
SELECT u, (u.orderTotal / u.orderCount) AS orderAverage
FROM User u
ORDER BY orderAverage
I have to use this trick because so far, Doctrine does not support ordering by an expression.
That works fine, expect that for a reason outside the scope of this question, I'd like to have only u returned by getResult():
[0] => object(User)
[1] => object(User)
and not a nested array containing u and orderAverage:
[0] =>
[0] => object(User)
['orderAverage'] => float
[1] =>
[0] => object(User)
['orderAverage'] => float
I thought I'd read somewhere that there was a DQL keyword for not returning an expression in the result, but I've failed to find it in the documentation. It'd be something like:
SELECT u, IGNORE (u.orderTotal / u.orderCount) AS orderAverage
FROM ...
Does that exist, or did I dream?
Ok, I finally managed to find it in the EBNF documentation.
The correct keyword is HIDDEN, and goes after AS:
SELECT u, (u.orderTotal / u.orderCount) AS HIDDEN orderAverage