Ignore returned expression in DQL - doctrine-orm

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

Related

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');

gst regular expression mismatch of group generates exception

I have a simple example in GNU Smalltalk 3.2.5 of attempting to group match on a key value setting:
st> m := 'a=b' =~ '(.*?)=(.*)'
MatchingRegexResults:'a=b'('a','b')
The above example works just as expected. However, if there is no match to the second group (.*), an exception is generated:
st> m := 'a=' =~ '(.*?)=(.*)'
Object: Interval new "<-0x4ce2bdf0>" error: Invalid index 1: index out of range
SystemExceptions.IndexOutOfRange(Exception)>>signal (ExcHandling.st:254)
SystemExceptions.IndexOutOfRange class>>signalOn:withIndex: (SysExcept.st:660)
Interval>>first (Interval.st:245)
Kernel.MatchingRegexResults>>at: (Regex.st:382)
Kernel.MatchingRegexResults>>printOn: (Regex.st:305)
Kernel.MatchingRegexResults(Object)>>printString (Object.st:534)
Kernel.MatchingRegexResults(Object)>>printNl (Object.st:571)
I don't understand this behavior. I would have expected the result to be ('a', nil) and that m at: 2 to be nil. I tried a different approach as follows:
st> 'a=' =~ '(.*?)=(.*)' ifMatched: [ :m | 'foo' printNl ]
'foo'
'foo'
Which determines properly that there's a match to the regex. But I still can't check if a specific group is nil:
st> 'a=' =~ '(.*?)=(.*)' ifMatched: [ :m | (m at: 2) ifNotNil: [ (m at: 2) printNl ] ]
Object: Interval new "<-0x4ce81b58>" error: Invalid index 1: index out of range
SystemExceptions.IndexOutOfRange(Exception)>>signal (ExcHandling.st:254)
SystemExceptions.IndexOutOfRange class>>signalOn:withIndex: (SysExcept.st:660)
Interval>>first (Interval.st:245)
Kernel.MatchingRegexResults>>at: (Regex.st:382)
optimized [] in UndefinedObject>>executeStatements (a String:1)
Kernel.MatchingRegexResults>>ifNotMatched:ifMatched: (Regex.st:322)
Kernel.MatchingRegexResults(RegexResults)>>ifMatched: (Regex.st:188)
UndefinedObject>>executeStatements (a String:1)
nil
st>
I don't understand this behavior. I would have expected the result to be ('a', nil) and that m at: 2 to be nil. At least that's the way it works in any other language I've used regex in. This makes me think maybe I'm not doing something correct with my syntax.
My question this is: do I have the correct syntax for attempting to match ASCII key value pairs like this (for example, in parsing environment settings)? And if I do, why is an exception being generated, or is there a way I can have it provide a result that I can check without generating an exception?
I found a related issue reported at gnu.org from Dec 2013 with no responses.
The issue had been fixed in master after the above report was received. The commit can be seen here. A stable release is currently blocked by the glib event loop integration.
ValidationExpression="[0-9]{2}[(a-z)(A-Z)]{5}\d{4}[(a-z)(A-Z)]{1}\d{1}Z\d{1}"
SetFocusOnError="true" ControlToValidate="txtGST" Display="Dynamic" runat="server" ErrorMessage="Invalid GST No." ValidationGroup="Add" ForeColor="Red"></asp:RegularExpressionValidator>

Doctrine ORM HYDRATE_SCALAR vs HYDRATE_ARRAY

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.

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.

doctrine2 dql, use setParameter with % wildcard when doing a like comparison

I want to use the parameter place holder - e.g. ?1 - with the % wild cards. that is, something like: "u.name LIKE %?1%" (though this throws an error). The docs have the following two examples:
1.
// Example - $qb->expr()->like('u.firstname', $qb->expr()->literal('Gui%'))
public function like($x, $y); // Returns Expr\Comparison instance
I do not like this as there is no protection against code injection.
2.
// $qb instanceof QueryBuilder
// example8: QueryBuilder port of: "SELECT u FROM User u WHERE u.id = ?1 OR u.nickname LIKE ?2 ORDER BY u.surname DESC" using QueryBuilder helper methods
$qb->select(array('u')) // string 'u' is converted to array internally
->from('User', 'u')
->where($qb->expr()->orx(
$qb->expr()->eq('u.id', '?1'),
$qb->expr()->like('u.nickname', '?2')
))
->orderBy('u.surname', 'ASC'));
I do not like this because I need to search for terms within the object's properties - that is, I need the wild cards on either side.
When binding parameters to queries, DQL pretty much works exactly like PDO (which is what Doctrine2 uses under the hood).
So when using the LIKE statement, PDO treats both the keyword and the % wildcards as a single token. You cannot add the wildcards next to the placeholder. You must append them to the string when you bind the params.
$qb->expr()->like('u.nickname', '?2')
$qb->getQuery()->setParameter(2, '%' . $value . '%');
See this comment in the PHP manual.
The selected answer is wrong. It works, but it is not secure.
You should escape the term that you insert between the percentage signs:
->setParameter(2, '%'.addcslashes($value, '%_').'%')
The percentage sign '%' and the symbol underscore '_' are interpreted as wildcards by LIKE. If they're not escaped properly, an attacker might construct arbirtarily complex queries that can cause a denial of service attack. Also, it might be possible for the attacker to get search results he is not supposed to get. A more detailed description of attack scenarios can be found here: https://stackoverflow.com/a/7893670/623685