Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EZP-26780 Implement DateMetadata criterion parser in REST #1861

Closed
wants to merge 1 commit into from

Conversation

kamilmusial
Copy link

JIRA: https://jira.ez.no/browse/EZP-26780

Currently there's no OperatorCriterion, so there's no easy way to set $operator for DateMetadataCriterion like it's done in other parsers.

That could be done by simply passing a string value to criterion constructor, but that'd omit a specification whitelist. So there's quick check in an array of abstract class reflection constants to validate an operator input before return a criterion object.

Another approach could be to implement an OperatorCriterion parser, but that should be another issue(?)

@kamilmusial
Copy link
Author

ping @andrerom @bdunogier

}
$target = $data['DateMetadataCriterion']['Target'];

$reflector = new ReflectionClass('eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be good to not have to use reflection

@kamilmusial
Copy link
Author

ping @andrerom
I created simple mapping helping to check for available operators. It's hard to fetch the constants from an abstract class without reflection. Maybe you have some suggestion about that solution?

/**
* @return array
*/
public static function getAvaliableOperators()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaik this does not have any meaning in the PHP API, as operators are never referred to by string names like "EQ" and so on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation referes to those names:
https://doc.ez.no/display/EZP/Criteria+reference

It does not say to use "=", ">=", etc.

Copy link
Contributor

@andrerom andrerom Dec 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I read that doc it refers to the constants, but it is indeed hard to tell on this page as it does not have any examples.

Copy link
Contributor

@andrerom andrerom Dec 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this is what I referred to above, you don't use the API by passing in string values EQ and so on, or = for that matter, you use constants.


if (!isset($data['DateMetadataCriterion']['Operator'])) {
$data['DateMetadataCriterion']['Operator'] = 'EQ';
} elseif (!in_array($data['DateMetadataCriterion']['Operator'], array_keys(Operator::getAvaliableOperators()))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move the method to this class as private function getAvaliableDateMetadateRESTOperators(), and it can return plain array with the available operators.

@kamilmusial
Copy link
Author

@andrerom Changed.


/**
* Parser for ViewInput Criterion.
*/
class DateMetadata extends BaseParser
{
/** @var array */
public $availableOperators = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

privat?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about changing this value or inheritance, but after rethink it can be changed I guess

@andrerom
Copy link
Contributor

andrerom commented Dec 13, 2016

@bdunogier looks ok to me now besides comment, but unsure about the whole OperatorCriterion as I'm not aware how this is done in other criteria.

@kamilmusial
Copy link
Author

@andrerom AFAIK there're no operators in other criteria or they are not implemented.

@andrerom
Copy link
Contributor

andrerom commented Dec 16, 2016

@andrerom AFAIK there're no operators in other criteria or they are not implemented.

ok, somewhat clear.

note to self/other-reviewers then: check spec and try to get how operators were intended to work, now that PR changed values from string versions of constants (EQ, LIKE, ..), to the actual values which afaik are supposed to be internal, hence the use of constants.

@pspanja
Copy link
Contributor

pspanja commented Dec 19, 2016

@andrerom @kamilmusial
The names of the constants in the Operator class should be used. They could be mapped to the actual value through a simple case switch, for example:

switch ($data['DateMetadataCriterion']['Operator']) {
    case 'IN':
        $operator = Operator::IN;
        break:
    case 'GTE':
        $operator = Operator::GTE;
        break:
    case 'BETWEEN':
        $operator = Operator::BETWEEN;
        break:
    ...
}

Copy link
Member

@bdunogier bdunogier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks okay.

After thinking about it for quite a bit, I'm wondering if we should move this up one level... we could conceal the whole operator debate by abstracting the criterion like this:

  • "ModifiedSince": <timestamp>
  • "PublishedAfter": <timestamp>
  • "ModifiedBetween": [<timestamp1>, <timestamp2>]

It would be much easier to use for REST consumers, and much more semantic/readable.

It is a bit more work for us to parse, but if we make this logic part of the parser dispatcher, it shouldn't be that complicated. Instead of a 1:1 match of the criterion's name, we could first detect this "operator suffix", and pass it to the parser when it gets invoked ? That way, we can keep the structs simple, and it also works for any criterion that needs an operator.

The main drawback that I can see is the non handling of the "than or equal" (e.g. GT vs GTE). But I'm kind of thinking that this case isn't that frequent, and it can always be formulated in other ways.

Please let me know what you think.

$target = $data['DateMetadataCriterion']['Target'];

if (!isset($data['DateMetadataCriterion']['Operator'])) {
$data['DateMetadataCriterion']['Operator'] = '=';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could skip this completely, and set a $operator to null. The Criterion's constructor will set it either to EQ or IN depending on the value.

}
$value = $data['DateMetadataCriterion']['Value'];

return new DateMetadataCriterion($target, $data['DateMetadataCriterion']['Operator'], $value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small consistency remark: why set a local variable for Value and not for Operator ? I'd probably be consistent here, and also set a $operator after the checks above.

['DateMetadataCriterion' => ['Target' => 'created', 'Operator' => '=', 'Value' => 1033920830]],
new DateMetadataCriterion('created', '=', 1033920830),
],
];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test case where the operator isn't set ?

* @expectedException \eZ\Publish\Core\REST\Common\Exceptions\Parser
* @expectedExceptionMessage Invalid <DateMetadataCriterion> format
*/
public function testParseExceptionOnInvalidCriterionFormat()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that you have multiple error tests, you could use a dataProvider for them as well, since you use one for valid cases.

@alongosz
Copy link
Member

REST implementation has been moved to eZ Platform REST Bundle. We'll have to implement it there. Closing this one.

@alongosz alongosz closed this Jun 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

6 participants