3

In cakephp 2.x in beforeFind I could check if some condition is set by !empty($queryData['conditions'][$this->alias.'.field']) or get the list of fields that would be retrived simply by $queryData['fields']. How to achieve this in cakephp 3.x ?

In beforeFind

public function beforeFind(Event $event, Query $query, $options, $primary)
{
}

the options is empty. The $query I can use to add conditions by $query->where(...), but how to check what fields are set to be retrieved or what conditions are already applied ?

Thanks

dav
  • 8,931
  • 15
  • 76
  • 140

2 Answers2

5

Taken from the CakePHP 3.0 API documentation:

traverse( callable $visitor , array $parts [] )

Will iterate over every specified part. Traversing functions can aggregate results using variables in the closure or instance variables. This function is commonly used as a way for traversing all query parts that are going to be used for constructing a query.

The callback will receive 2 parameters, the first one is the value of the query part that is being iterated and the second the name of such part.

Example:

$query->select(['title'])->from('articles')->traverse(function ($value, $clause) {
    if ($clause === 'select') {
        var_dump($value);
    }
}, ['select', 'from']);

So just call $query->traverse() and provide the callback closure and do your checks inside of it. See also traverseExpressions().

floriank
  • 25,546
  • 9
  • 42
  • 66
  • thanks for the answer, for getting the fields its fine, however for conditions (using where for `$parts`) I am getting object with protected properties https://justpaste.it/rzfo , is there any better/cake way of getting the conditions from it, or I should use reflection class http://stackoverflow.com/questions/20334355/how-to-get-protected-property-of-object-in-php/28352585#28352585 thanks – dav Mar 05 '16 at 19:52
  • 2
    @dav You should check the docs. What you are looking at is debug output that doesn't necessarily reflect the actual/complete object structure. Expression objects do also have public methods, and can be [**traversed**](http://api.cakephp.org/3.2/class-Cake.Database.Expression.QueryExpression.html#_traverse)/[**iterated**](http://api.cakephp.org/3.2/class-Cake.Database.Expression.QueryExpression.html#_iterateParts) too, and that is what you have to do if you want to inspect the `WHERE` clause. – ndm Mar 06 '16 at 12:08
  • 1
    @ndm, thanks for your comment, got it working by `$query->traverse(function ($value, $clause) { $value->iterateParts(function($val) { debug($val->getField()); debug($val->getOperator()); debug($val->getValue()); }); }, ['where']);` – dav Mar 06 '16 at 17:22
  • 2
    @dav Don't forget that the callable for `iterateParts()` should return the condition (`$val`), otherwise the iterated part will be removed, and thus the query being altered! – ndm Mar 06 '16 at 17:45
  • 1
    @ndm, appreciate your time for commenting, I missed that part from docs. thanks – dav Mar 06 '16 at 18:04
1

Thanks for the hint, but method "traverse" in the 4th version I already did not work like this. I looked at it in the Cake core:

public function beforeFind($event, $query, $options, $primary)
{
    $query
        ->clause('where')
        ->iterateParts(function ($callable) use (&$params): void {
            if ($callable->getField() === 'url') {
                // do something
            }
            $params[] = [
                $callable->getField() . ' ' . $callable->getOperator() => $callable->getValue()
            ];
        });

    $query->where($params);
}