Skip to content
This repository has been archived by the owner on Dec 23, 2023. It is now read-only.

We need to invent some kind of chainable expression interface #174

Open
phenaproxima opened this issue Oct 28, 2014 · 3 comments
Open

We need to invent some kind of chainable expression interface #174

phenaproxima opened this issue Oct 28, 2014 · 3 comments

Comments

@phenaproxima
Copy link
Collaborator

In DMU, I'm starting to need to build constructs like this:

$node->field_foo[0]->value
$node->getTranslation('fr')->field_foo[0]->value

These expressions are getting really complex. I could just use parseExpression and feed it raw PHP, of course, but that's not ideal, especially considering that the chaining stuff we added to CallNode is so elegant and works so well.

What would be amazing -- and I can't honestly call this high priority, but it'd be extremely nice to have -- is the ability to chain different kinds of expressions beyond just CallNodes. Obviously not every type of expression can be chained, so I'm thinking we could devise a ChainableExpression interface (extending Expression), which exposes an appendExpression() method. This method accepts an Expression, and then returns $existingChain->$appendedExpr. And if the resulting chain is itself a chainable expression, it can be chained again.

So I envision something like the following:

// VariableNode will implement ChainableExpression
$var = Token::variable('$node')
// $body is an ArrayLookupNode: body[0]
$var = $var->appendExpression($body)
// $var is now $node->body[0]
$value = Token::string('value')
$var = $var->appendExpression($value)
// $var is now $node->body[0]->value
$get = FunctionCallNode::create('get')
$var = $var->appendExpression($get)
// $var is now $node->body[0]->value->get()
@grom358
Copy link
Owner

grom358 commented Oct 29, 2014

Ah this is almost there now we just missing some create method for ObjectPropertyNode. Then be something like:

$var = Token::variable('$node');
$var = ObjectPropertyNode::create($var, 'body');
$var = ArrayLookupNode::create($var, Token::integer(0));
$var = ObjectPropertyNode::create($var, 'value');
$var = ObjectMethodCallNode::create($var, 'get');
// results in $node->body[0]->value->get()

To make it chainable will require adding methods that call these create methods. For example:

class ArrayLookupNode {
  public function methodCall($methodName) {
    return ObjectMethodCallNode::create($this, $methodName);
  }
  public function objectProperty($propertyName) {
    return ObjectPropertyNode::create($this, $propertyName);
  }
}

Since -> is for both object property and method calls, will need both these methods.

@phenaproxima
Copy link
Collaborator Author

Gotcha.

I still think these should be defined on an interface, if for no other reason than it keeps it clear as to what types of nodes support chaining (if I'm not forgetting any, that'll be CallNode, VariableNode, ObjectPropertyNode, and ArrayLookupNode).

I propose something like this:

interface ChainableExpression extends Expression {
  /** @return ObjectMethodCallNode **/
  public function appendMethodCall($method_name);

  /** @return ObjectMethodCallNode **/
  public function appendProperty($property_name);

  /** @return ArrayLookupNode **/
  public function appendIndex($index);
}

I can probably create a PoC of this.

@grom358
Copy link
Owner

grom358 commented Oct 30, 2014

Yes could be interface if there a need to identify which nodes support it. Note that a lot of the traits don't have an associated interface though to identify which nodes support those operations. Whether they should or not... not sure. Just making observation there.

And probably have a Trait for implementation here since I believe the same implementation should be the same across the board.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants