public function __construct(Xref $xref, $message = "", $code = 0, \Exception $previous = null) { if ($xref->hasLocation()) { $message = sprintf("Error resolving Xref of type \"%s\" from location \"%s\"%s", $xref->getType(), $xref->getLocation(), $message == '' ? '' : ': ' . $message); } parent::__construct($message, $code, $previous); }
public function __construct(Xref $xref, $message = "", $code = 0, \Exception $previous = null) { if ($xref->hasLocation()) { $message = sprintf('Unable to fetch external reference of type "%s" from location "%s"%s.', $xref->getType(), $xref->getLocation(), $message == '' ? '' : ': ' . $message); } else { $message = sprintf('Unable to fetch external reference of type "%s": no location specified.', $xref->getType()); } parent::__construct($message, $code, $previous); }
public function testOnDemandResolver() { $xrefDep1 = new Xref('file', '/dep1.json'); $xrefDep1->setData(array('on-demand1' => '{{token1}}', 'on-demand2' => '{{token2}}'))->setResolved(true); $xrefMain = new Xref('file', '/main.json'); $xrefMain->setData(array('include' => array('xref' => array('dep1' => array('type' => 'file', 'src' => '/dep1.json', 'resolve' => array(array('type' => 'on-demand', 'options' => array('token-prefix' => '{{', 'token-suffix' => '}}'), 'values' => array())))), 'main' => array('dep1'))))->setResolved(true); $treeCompiler = new TreeCompiler(); $treeCompiler->getXrefs()->add($xrefDep1); $compiled = $treeCompiler->compileXref($xrefMain); $expected = array('on-demand1' => '{{token1}}', 'on-demand2' => '{{token2}}'); $this->assertEquals($expected, $compiled); $this->onDemandTokenValues = array('token1' => 'ok1', 'token2' => 'ok2'); $testListener = new TestEventListener(array($this, 'eventListenerCallback')); $eventManager = EventManager::getInstance(); $eventManager->register($testListener); $this->assertTrue($eventManager->hasListeners()); $compiled = $treeCompiler->compileXref($xrefMain); $expected = array('on-demand1' => 'ok1', 'on-demand2' => 'ok2'); $this->assertEquals($expected, $compiled); $eventManager->remove($testListener); $this->assertFalse($eventManager->hasListeners()); }
/** * Fetch the data from the specified location of the Xref. * * @param Xref $xref * @param boolean $force If true and Xref already fetched, force the resolver to fetch the data again. * @throws \Exception */ public static function resolve(Xref $xref, $force = false) { $xref->setResolved(true); }
/** * Recursively resolve Xrefs and compile data. * * @param Xref $xref * @param XrefTokenResolverCollection $tokenResolvers * @param string|null $includeType * @param string|array|null $includeTypeValue * @param array $xrefPath * @return array * * @throws CircularReferenceException * @throws Exception\AlreadyRegisteredException * @throws TreeCompiler\XrefResolver\Exception\UnknownXrefTypeException * @throws UnknownXrefException * @throws XrefResolverFormatException * @throws \Exception */ protected function recursiveCompileXref(Xref $xref, XrefTokenResolverCollection $tokenResolvers = null, $includeType = null, $includeTypeValue = null, &$xrefPath) { static $XREF_KEY = 0; static $XREF_RESOLVERS_KEY = 1; if (!isset($includeType)) { $includeType = static::INCLUDE_TYPE_GROUP; } switch ($includeType) { case static::INCLUDE_TYPE_GROUP: if (!isset($includeTypeValue)) { $includeTypeValue = $this->includeMainKey; } else { if (gettype($includeTypeValue) != 'string') { throw new XrefResolverFormatException($xref, sprintf("Include type value must be a string representing the include group name. " . "\"%s\" given instead.", gettype($includeTypeValue))); } } break; case static::INCLUDE_TYPE_XREF: if (!is_array($includeTypeValue) || empty($includeTypeValue)) { throw new XrefResolverFormatException($xref, "Include type value must be a non-empty array of strings for named includes."); } break; default: throw new \Exception(sprintf('Unknown include type "%s".', $includeType)); } $mustIncludeSpecificGroup = $includeTypeValue != $this->includeMainKey; $xref->resolve(); $xrefData = $xref->getData(); if (empty($xrefData)) { if (!is_array($xrefData)) { throw new XrefResolverFormatException($xref, "De-serialized data must be an array."); } return array(); } if (!isset($xrefData[$this->includeKey]) || !is_array($xrefData[$this->includeKey])) { switch ($includeType) { case static::INCLUDE_TYPE_XREF: throw new XrefResolverFormatException($xref, sprintf("Required to explicitly include the list of Xref keys [\"%s\"] " . "but the \"%s\" key is missing from the first level.", implode('", "', $includeTypeValue), $this->includeKey)); case static::INCLUDE_TYPE_GROUP: if (!$mustIncludeSpecificGroup) { if (isset($xrefData[$this->addKey])) { $result = $xrefData[$this->addKey]; } else { if (isset($xrefData[$this->removeKey])) { unset($xrefData[$this->removeKey]); } $result = $xrefData; } if (isset($tokenResolvers)) { $tokenResolvers->applyToArray($result); } return $result; } throw new XrefResolverFormatException($xref, sprintf("Required to explicitly include the \"%s\" group of Xref keys " . "but the \"%s\" key is missing from the first level.", $includeTypeValue, $this->includeKey)); } } $xrefDataInclude =& $xrefData[$this->includeKey]; if (!isset($xrefDataInclude[$this->includeXrefKey]) || !is_array($xrefDataInclude[$this->includeXrefKey])) { switch ($includeType) { case static::INCLUDE_TYPE_XREF: throw new XrefResolverFormatException($xref, sprintf("Required to explicitly include the list of Xref keys [\"%s\"] " . "but the \"%s\" key is missing from the \"%s\" key on the first level.", implode('", "', $includeTypeValue), $this->includeXrefKey, $this->includeKey)); case static::INCLUDE_TYPE_GROUP: if (!$mustIncludeSpecificGroup) { if (isset($xrefData[$this->addKey])) { $result = $xrefData[$this->addKey]; } else { if (isset($xrefData[$this->removeKey])) { unset($xrefData[$this->removeKey]); } $result = $xrefData; } if (isset($tokenResolvers)) { $tokenResolvers->applyToArray($result); } return $result; } throw new XrefResolverFormatException($xref, sprintf("Required to explicitly include the \"%s\" group of Xref keys " . "but the \"%s\" key is missing from the \"%s\" key on the first level.", $includeTypeValue, $this->includeXrefKey, $this->includeKey)); } } $xrefDataIncludeXrefs =& $xrefDataInclude[$this->includeXrefKey]; $xrefKeysToBeResolved = $this->getXrefKeysToBeResolved($xref, $xrefDataInclude, $xrefDataIncludeXrefs, $includeType, $includeTypeValue); $xrefsToBeParsed = array(); foreach ($xrefKeysToBeResolved as $xrefKeyToBeResolved) { if (!isset($xrefDataIncludeXrefs[$xrefKeyToBeResolved])) { throw new UnknownXrefException(sprintf("Unable to find the required Xref definition named \"%s\".", $xrefKeyToBeResolved)); } $xrefsToBeParsed[$xrefKeyToBeResolved] = $xrefDataIncludeXrefs[$xrefKeyToBeResolved]; } unset($xrefDataIncludeXrefs); $xrefId = $xref->getId(); $xrefPath[$xrefId] = $xref; $xrefsToBeResolved = array(); foreach ($xrefsToBeParsed as $xrefKey => $xrefInfo) { $includedXref = $this->parseXrefInfo($xrefKey, $xrefInfo, $tokenResolvers, $xrefPath); if (is_array($xrefInfo) && isset($xrefInfo[$this->includeXrefResolversKey])) { $xrefTokenResolvers = $this->parseXrefTokenResolverDefinitions($xrefKey, $xrefInfo[$this->includeXrefResolversKey], $tokenResolvers, $xrefPath); } else { $xrefTokenResolvers = null; } $xrefsToBeResolved[] = array($XREF_KEY => $includedXref, $XREF_RESOLVERS_KEY => $xrefTokenResolvers); } /** @var array $includedXrefs */ $result = array(); foreach ($xrefsToBeResolved as $xrefToBeResolved) { /** @var Xref $includedXref */ $includedXref = $xrefToBeResolved[$XREF_KEY]; if (isset($xrefPath[$includedXref->getId()])) { throw new CircularReferenceException(sprintf('Tree compiler encountered circular reference at "%s" in path ["%s"].', sprintf('%s:%s', $includedXref->getType(), $includedXref->getLocation()), implode('", "', $xrefPath))); } $this->xrefs->add($includedXref); /** @var XrefTokenResolverCollection $includeTokenResolvers */ $includeTokenResolvers = $xrefToBeResolved[$XREF_RESOLVERS_KEY]; if (isset($includeTokenResolvers)) { $downTokenResolvers = $includeTokenResolvers; } else { $downTokenResolvers = new XrefTokenResolverCollection(); } if (isset($tokenResolvers)) { $downTokenResolvers->addCollection($tokenResolvers); } $includeData = $this->recursiveCompileXref($includedXref, $downTokenResolvers, static::INCLUDE_TYPE_GROUP, $this->includeMainKey, $xrefPath); $this->recursiveAddData($includeData, $result); } unset($xrefPath[$xrefId]); if (isset($xrefData[$this->removeKey])) { if (isset($tokenResolvers)) { $tokenResolvers->applyToArray($xrefData[$this->removeKey]); } $this->recursiveRemoveData($xrefData[$this->removeKey], $result); } if (isset($xrefData[$this->addKey])) { if (isset($tokenResolvers)) { $tokenResolvers->applyToArray($xrefData[$this->addKey]); } $this->recursiveAddData($xrefData[$this->addKey], $result); } return $result; }
public function testTokensInValuesXrefLocation() { $xrefDep1 = new Xref('file', '/dep1.json'); $xrefDep1->setData(array('content' => 'dep1.json', 'dep1version' => '{{version}}'))->setResolved(true); $xrefDep2 = new Xref('file', '/dep2.json'); $xrefDep2->setData(array('include' => array('xref' => array('dep1' => array('type' => 'file', 'src' => '/dep1.json', 'resolve' => array(array('type' => 'registered', 'options' => array('token-prefix' => '{{', 'token-suffix' => '}}'), 'values-xref' => array('type' => 'file', 'src' => '/dep{{version}}.json'))))), 'main' => array('dep1'))))->setResolved(true); $xrefMain = new Xref('file', '/main.json'); $xrefMain->setData(array('include' => array('xref' => array('dep2' => array('type' => 'file', 'src' => '/dep2.json', 'resolve' => array(array('type' => 'registered', 'options' => array('token-prefix' => '{{', 'token-suffix' => '}}'), 'values' => array('version' => '1'))))), 'main' => array('dep2'))))->setResolved(true); $treeCompiler = new TreeCompiler(); $treeCompiler->getXrefs()->add($xrefDep1); $treeCompiler->getXrefs()->add($xrefDep2); $compiled = $treeCompiler->compileXref($xrefMain); $expected = array('content' => 'dep1.json', 'dep1version' => 1); $this->assertEquals($expected, $compiled); }
/** * Fetch the data from the specified location of the Xref. * * @param Xref $xref * @param boolean $force If true and Xref already fetched, force the resolver to fetch the data again. * @throws UnknownXrefTypeException * @throws XrefResolverFetchException * @throws \ConfigToken\TreeCompiler\XrefResolver\Exception\InvalidXrefTypeException * @throws \ConfigToken\TreeSerializer\Exception\UnknownContentTypeException * @throws \ConfigToken\TreeSerializer\Exception\UnknownFileExtensionException */ public static function resolve(Xref $xref, $force = false) { if ($xref->isResolved() && !$force) { return; } static::matchType($xref); if (!$xref->hasLocation()) { throw new XrefResolverFetchException($xref); } $data = null; $httpCode = null; $contentType = null; $eventManager = EventManager::getInstance(); if ($eventManager->hasListeners()) { $event = new Event(self::EVENT_ID_RESOLVE_URL); $event->data[self::EVENT_URL] = $xref->getLocation(); $event->data[Event::RESULT] = false; $eventManager->dispatch($event); if (isset($event->data[Event::RESULT])) { if ($event->data[Event::RESULT] === true) { $data = $event->data[self::EVENT_DATA]; $contentType = $event->data[self::EVENT_CONTENT_TYPE]; $httpCode = 200; } else { if ($event->data[Event::RESULT] !== false) { throw new XrefResolverFetchException($xref, sprintf('Got error message from listener: %s', $event->data[Event::RESULT])); } } } } if (!isset($data)) { $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_URL, $xref->getLocation()); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15); curl_setopt($ch, CURLOPT_TIMEOUT, 15); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_HEADER, false); $data = curl_exec($ch); $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); } if ($httpCode != 200) { throw new XrefResolverFetchException($xref, sprintf('Got response code %d', $httpCode)); } if (TreeSerializerFactory::isRegisteredByContentType($contentType)) { $serializer = TreeSerializerFactory::getByContentType($contentType); $xref->setContentType($contentType); } else { $path = parse_url($xref->getLocation(), PHP_URL_PATH); $fileExtension = pathinfo($path, PATHINFO_EXTENSION); if (!TreeSerializerFactory::isRegisteredByFileExtension($fileExtension)) { throw new UnknownXrefTypeException(sprintf('Unable to find resolver for Xref content type "%s" or file extension "%s" for location "%s".', $contentType, $fileExtension, $xref->getLocation())); } $serializer = TreeSerializerFactory::getByFileExtension($fileExtension); $xref->setContentType($serializer::getContentType()); } // TODO: catch exception, show xref location in error message $data = $serializer::deserialize($data); $xref->setData($data); $xref->setResolved(true); }
/** * Used internally to verify if this Xref has the same type as the given Xref. * * @param Xref $xref The Xref to compare to. * @throws InvalidXrefTypeException */ protected static function matchType(Xref $xref) { if ($xref->getType() !== static::getType()) { throw new InvalidXrefTypeException(sprintf('%s is unable to resolve Xrefs of type %s.', get_called_class(), $xref->getType())); } }
public function parse($xrefs, $typeDelimiter, $overwrite = False, $ignore = True) { if (!is_array($xrefs)) { $xrefs = array($xrefs); } $parsed = array(); foreach ($xrefs as $key => $value) { $xref = Xref::makeFromDefinitionString($value, $typeDelimiter); if ($this->has($xref)) { if (!$ignore) { throw new AlreadyRegisteredException(sprintf('Not allowed to overwrite Xref of type "%s" with location "%s" already in collection.', $xref->getType(), $xref->getLocation())); } if ($overwrite && !$ignore) { $this->add($xref); } } else { $this->add($xref); } $parsed[$key] = $xref; } return $parsed; }
/** * Fetch the data from the specified location of the Xref. * * @param Xref $xref * @param boolean $force If true and Xref already fetched, force the resolver to fetch the data again. * @throws XrefResolverFetchException */ public static function resolve(Xref $xref, $force = false) { if ($xref->isResolved() && !$force) { return; } static::matchType($xref); if (!$xref->hasLocation()) { throw new XrefResolverFetchException($xref); } $xrefLocation = $xref->getLocation(); if (!file_exists($xrefLocation)) { throw new XrefResolverFetchException($xref, 'File does not exist.'); } try { $data = file_get_contents($xrefLocation); } catch (\Exception $e) { throw new XrefResolverFetchException($xref, $e->getMessage()); } $xref->setResolved(false); if ($xref->hasContentType()) { $serializer = TreeSerializerFactory::getByContentType($xref->getContentType()); } else { $fileExtension = pathinfo($xrefLocation, PATHINFO_EXTENSION); $serializer = TreeSerializerFactory::getByFileExtension($fileExtension); $xref->setContentType($serializer::getContentType()); } try { $data = $serializer::deserialize($data); } catch (TreeSerializerSyntaxException $e) { throw new XrefResolverFetchException($xref, $e->getMessage()); } $xref->setData($data); $xref->setResolved(true); }