/** * Compiles AngularJS ng-repeat attribute. * Each element's copy is treated and rendered as separate template with it's * own Scope data. Those elements are later appended to element's parent node. * * @todo Think of refactoring methods. * @todo Implement expression cache for better performance. * * @param \DOMElement $domElement DOM element to compile. * @param Scope $scope Scope object. * @return void */ public function compile(\DOMElement $domElement, Scope $scope) { $parsedArray = $this->parseRepeat($domElement); $repeatArray = $scope->getData($parsedArray['array']); /** * Reset interrupting to default value. */ $this->setInterrupt(false); /** * Let's check if variable we're trying to enumerate is array. */ if (is_array($repeatArray) === true) { /** * Helper variables for ng-repeat special scope variables e.g. $index. */ $repeatCount = count($repeatArray); $repeatIndex = 0; foreach ($repeatArray as $repeatKey => $repeatValue) { $subScope = new Scope($scope->getData()); $this->setScopeData($subScope, $parsedArray, $repeatKey, $repeatValue); $this->setScopeSpecial($subScope, $repeatCount, $repeatIndex); /** * Append subcompiled DOM element. */ Utils::appendHTML($domElement->parentNode, $this->subcompile($domElement->cloneNode(true), $subScope)); $repeatIndex++; } /** * We stop further compiling of source DOM element, we want it to * be intact and hidden so we can replace it back on the client side. */ $this->setInterrupt(true); Utils::addClass($domElement, 'ng-hide'); } }
/** * Compiles given AngularJS expression with given Scope data. * * @param string $expression Expression string to compile. * @param Scope $scope Scope object containing data for expression. * @return string Compiled expression. * @throws InvalidExpressionException Exception is thrown if expression contains brackets "()" * to prevent eval from calling functions for security reasons. */ public function compile($expression, Scope $scope) { $expression = trim($expression, '{} '); /** * We forbid any function calls inside expressions. */ if (preg_match('/[\\(\\)]/', $expression) === 1) { throw new InvalidExpressionException('Expression contains one or both of forbidden characters: "()"!'); } $expressionOperators = '/[^' . preg_quote('+-/*!=&|?:<>%,\'"', '/') . ']+/'; preg_match_all($expressionOperators, $expression, $expressionMatches); /** * I no special operators found just replace access string with value. */ if (isset($expressionMatches[0][0]) && $expressionMatches[0][0] === $expression) { $renderedExpression = $scope->getData($expression); } else { /** * Check each expression we can replace. */ foreach ($expressionMatches[0] as $expressionMatch) { $expressionMatch = trim($expressionMatch); /** * If we can replace it with data - do this and format variable if required for later eval. */ if (is_numeric($expressionMatch) === false) { $expression = str_replace($expressionMatch, var_export($scope->getData($expressionMatch), true), $expression); } } $renderedExpression = $this->evalaluate($expression); } return $renderedExpression; }
/** * Compiles AngularJS ng-class-odd attributes by evaluating expression inside it * and setting element's class attribute if element has odd index. * * @param \DOMElement $element DOM element to compile. * @param Scope $scope Scope object containing data for expression. * @return \DOMElement Compiled DOM element. */ public function compile(\DOMElement $element, Scope $scope) { if ($scope->getData('$odd') == true) { $ngClass = new NgClass($this->phCompile); $ngClass->compile($element, $scope); } }
/** * Returns value corresponding to given access string. * * @param string|null $accessString Access string to wanted config value, * null if you want entire config array. * @return mixed Value corresponding to given access string or null if value * does not exist. */ public function getConfig($accessString = null) { return $this->config->getData($accessString); }
/** * @covers PhCompile\Scope::getData * @depends testSetData * @dataProvider getDataProvider */ public function testGetAllData($data, $access, $expected) { $this->scope->setData($data); $this->assertSame($data, $this->scope->getData()); }