X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fmodules%2Fcontrib%2Fdrupalmoduleupgrader%2Fsrc%2FPlugin%2FDMU%2FRewriter%2FGeneric.php;fp=web%2Fmodules%2Fcontrib%2Fdrupalmoduleupgrader%2Fsrc%2FPlugin%2FDMU%2FRewriter%2FGeneric.php;h=e3f07b40e557006d97f73566e37ec1fdba289584;hp=0000000000000000000000000000000000000000;hb=8acec36f19c470dfcda1ae2336826a782f41874c;hpb=e0411c4e83ba0d079034db83c3f7f55be24a0e35 diff --git a/web/modules/contrib/drupalmoduleupgrader/src/Plugin/DMU/Rewriter/Generic.php b/web/modules/contrib/drupalmoduleupgrader/src/Plugin/DMU/Rewriter/Generic.php new file mode 100644 index 000000000..e3f07b40e --- /dev/null +++ b/web/modules/contrib/drupalmoduleupgrader/src/Plugin/DMU/Rewriter/Generic.php @@ -0,0 +1,306 @@ +isAssigned = new NodeAssignmentFilter(); + } + + /** + * {@inheritdoc} + */ + public function rewrite(ParameterNode $parameter) { + // Don't even try to rewrite the function if the parameter is reassigned. + if ($this->isReassigned($parameter)) { + $error = $this->t('@function() cannot be parametrically rewritten because @parameter is reassigned.', [ + '@parameter' => $parameter->getName(), + '@function' => $parameter->getFunction()->getName()->getText(), + ]); + throw new \LogicException($error); + } + + foreach ($this->getExpressions($parameter)->not($this->isAssigned) as $expr) { + $property = $this->getProperty($expr); + if (empty($property)) { + continue; + } + + $getter = $this->rewriteAsGetter($expr, $property); + if ($getter) { + $empty = $expr->closest(Filter::isFunctionCall('empty', 'isset')); + + // If the original expression was wrapped by a call to isset() or + // empty(), we need to replace it entirely. + if ($getter instanceof CallNode && $empty instanceof CallNode) { + // If the isset() or empty() call was negated, reverse that logic. + $parent = $empty->parent(); + if ($parent instanceof BooleanNotNode) { + $parent->replaceWith($getter); + } + else { + $empty->replaceWith(BooleanNotNode::fromExpression($getter)); + } + } + else { + $expr->replaceWith($getter); + } + } + } + + foreach ($this->getExpressions($parameter)->filter($this->isAssigned) as $expr) { + // If the property cannot be determined, don't even try to rewrite the + // expression. + $property = $this->getProperty($expr); + if (empty($property)) { + continue; + } + + $assignment = $expr->closest(Filter::isInstanceOf('\Pharborist\Operators\AssignNode')); + + $setter = $this->rewriteAsSetter($expr, $property, $assignment); + if ($setter) { + $assignment->replaceWith($setter); + } + } + + // Set the type hint, if one is defined. + if (isset($this->pluginDefinition['type_hint'])) { + $parameter->setTypeHint($this->pluginDefinition['type_hint']); + + // If the type hint extends FieldableEntityInterface, rewrite any field + // lookups (e.g. $node->body[LANGUAGE_NONE][0]['value']). + if (in_array('Drupal\Core\Entity\FieldableEntityInterface', class_implements($this->pluginDefinition['type_hint']))) { + $filter = new FieldValueFilter($parameter->getName()); + + foreach ($parameter->getFunction()->find($filter) as $lookup) { + $lookup->replaceWith(self::rewriteFieldLookup($lookup)); + } + } + } + } + + /** + * Finds every rewritable expression in the function body. + * + * @param \Pharborist\Functions\ParameterNode $parameter + * The parameter on which the rewrite is based. + * + * @return \Pharborist\NodeCollection + */ + protected function getExpressions(ParameterNode $parameter) { + $filter = Filter::isInstanceOf('\Pharborist\ArrayLookupNode', '\Pharborist\Objects\ObjectPropertyNode'); + $expressions = new NodeCollection(); + + $parameter + ->getFunction() + ->find(Filter::isInstanceOf('\Pharborist\Variables\VariableNode')) + ->filter(function(VariableNode $variable) use ($parameter) { + return $variable->getName() == $parameter->getName(); + }) + ->each(function(VariableNode $variable) use ($filter, $expressions) { + $root = $variable->furthest($filter); + if ($root) { + $expressions->add($root); + } + }); + + return $expressions; + } + + /** + * Returns the property used by a rewritable expression, or NULL if the + * property cannot be determined. + * + * @param \Pharborist\ExpressionNode $expr + * The rewritable expression. + * + * @return string|NULL + */ + protected function getProperty(ExpressionNode $expr) { + if ($expr instanceof ObjectPropertyNode) { + return $expr->getPropertyName(); + } + elseif ($expr instanceof ArrayLookupNode) { + $key = $expr->getKey(0); + + if ($key instanceof StringNode) { + return $key->toValue(); + } + } + } + + /** + * Rewrites the given expression as a property getter. Returns NULL if the + * expression cannot be rewritten. + * + * @param \Pharborist\ExpressionNode $expr + * The expression to rewrite. + * @param string $property + * The property being used in the expression. + * + * @return \Pharborist\ExpressionNode|NULL + */ + public function rewriteAsGetter(ExpressionNode $expr, $property) { + if ($expr instanceof ObjectPropertyNode) { + // Should be getRootObject() or getLookupRoot(). + // @see Pharborist issue #191 + $object = clone $expr->getObject(); + } + elseif ($expr instanceof ArrayLookupNode) { + $object = clone $expr->getRootArray(); + } + + if (isset($object) && isset($this->pluginDefinition['properties'][$property]['get'])) { + return ObjectMethodCallNode::create($object, $this->pluginDefinition['properties'][$property]['get']); + } + } + + /** + * Rewrites an assignment expression as a property setter. Returns NULL if + * the expression cannot be rewritten. + * + * @param \Pharborist\ExpressionNode $expr + * The expression to rewrite. + * @param string $property + * The property being used in the expression. + * @param \Pharborist\Operators\AssignNode $assignment + * The entire assignment expression being rewritten. + * + * @return \Pharborist\ExpressionNode|NULL + */ + public function rewriteAsSetter(ExpressionNode $expr, $property, AssignNode $assignment) { + if ($expr instanceof ObjectPropertyNode) { + // Should be getRootObject() or getLookupRoot(). + // @see Pharborist issue #191 + $object = clone $expr->getObject(); + } + elseif ($expr instanceof ArrayLookupNode) { + $object = clone $expr->getRootArray(); + } + + if (isset($object) && isset($this->pluginDefinition['properties'][$property]['set'])) { + return ObjectMethodCallNode::create($object, $this->pluginDefinition['properties'][$property]['set']) + ->appendArgument(clone $assignment->getRightOperand()); + } + } + + /** + * Returns if the parameter is fully reassigned anywhere in the function. + * + * @param \Pharborist\Functions\ParameterNode $parameter + * The parameter to check. + * + * @return boolean + */ + protected function isReassigned(ParameterNode $parameter) { + return (boolean) $parameter + ->getFunction() + ->find(Filter::isInstanceOf('\Pharborist\Variables\VariableNode')) + ->filter(function(VariableNode $variable) use ($parameter) { + return $variable->getName() == $parameter->getName(); + }) + ->filter($this->isAssigned) + ->count(); + } + + /** + * Rewrites a Drupal 7 field lookup like so: + * + * $node->body[LANGUAGE_NONE][0]['value'] --> $node->body[0]->value + * $node->body['fr'][0]['value'] --> $node->getTranslation('fr')->body[0]->value + * + * @param \Pharborist\ArrayLookupNode $node + * The original field lookup. + * + * @return \Pharborist\ExpressionNode + */ + public static function rewriteFieldLookup(ArrayLookupNode $node) { + $keys = $node->getKeys(); + /** @var \Pharborist\Objects\ObjectPropertyNode $root */ + $root = $node->getRootArray(); + $expr = $root->getObject()->getText(); + + if (self::isTranslation($keys[0])) { + $expr .= '->getTranslation(' . $keys[0] . ')'; + } + $expr .= '->' . $root->getPropertyName() . '[' . $keys[1] . ']'; + + /** @var \Pharborist\Types\StringNode|\Pharborist\Node $column */ + foreach (array_slice($keys, 2) as $column) { + $expr .= '->'; + $expr .= $column instanceof StringNode ? $column->toValue() : $column->getText(); + } + + return Parser::parseExpression($expr); + } + + /** + * Checks if a field lookup key is translated. This will be TRUE unless one + * of the following conditions applies: + * + * - The key is the Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED + * constant. + * - The key is the LANGUAGE_NONE constant from Drupal 7. + * - The key is the string 'und'. + * + * @param Node $key + * The key to check. + * + * @return boolean + */ + public static function isTranslation(Node $key) { + if ($key instanceof ClassConstantLookupNode) { + $constant = $key->getClassName() . '::' . $key->getConstantName(); + return $constant != '\Drupal\Core\Language\Language::LANGCODE_NOT_SPECIFIED'; + } + elseif ($key instanceof ConstantNode) { + return $key->getConstantName() != 'LANGUAGE_NONE'; + } + elseif ($key instanceof StringNode) { + return $key->toValue() != 'und'; + } + else { + return TRUE; + } + } + +}