diff --git a/spec/Fixtures/invalid_template/plastic.svg b/spec/Fixtures/invalid_template/plastic.svg new file mode 100644 index 0000000..94b2a65 --- /dev/null +++ b/spec/Fixtures/invalid_template/plastic.svg @@ -0,0 +1,13 @@ + + + + + + + + + stable + stable + v2.0 + v2.0 + diff --git a/spec/Fixtures/xml_template/plastic.svg b/spec/Fixtures/xml_template/plastic.svg new file mode 100644 index 0000000..0ec2225 --- /dev/null +++ b/spec/Fixtures/xml_template/plastic.svg @@ -0,0 +1,26 @@ + + + + PHP: Behind the Parser + + + Ms. Coder + Onlivia Actora + + + Mr. Coder + El ActÓr + + + + So, this language. It's like, a programming language. Or is it a + scripting language? All is revealed in this thrilling horror spoof + of a documentary. + + + PHP solves all my web problems + + 7 + 5 + + diff --git a/spec/PUGX/Poser/Render/SvgRenderSpec.php b/spec/PUGX/Poser/Render/SvgRenderSpec.php index 34e54f9..50dc13c 100644 --- a/spec/PUGX/Poser/Render/SvgRenderSpec.php +++ b/spec/PUGX/Poser/Render/SvgRenderSpec.php @@ -21,6 +21,22 @@ function it_should_render_a_svg() $this->render($badge)->shouldBeAValidSVGImage(); } + function it_should_not_render_an_invalid_svg($calculator) + { + $templatesDir = __DIR__ . '/../../../Fixtures/invalid_template'; + $this->beConstructedWith($calculator, $templatesDir); + $badge = Badge::fromURI('version-stable-97CA00.svg'); + $this->shouldThrow(new \RuntimeException('Generated string is not a valid XML'))->duringRender($badge); + } + + function it_should_not_render_non_svg_xml($calculator) + { + $templatesDir = __DIR__ . '/../../../Fixtures/xml_template'; + $this->beConstructedWith($calculator, $templatesDir); + $badge = Badge::fromURI('version-stable-97CA00.svg'); + $this->shouldThrow(new \RuntimeException('Generated xml is not a SVG'))->duringRender($badge); + } + public function getMatchers() { return array( diff --git a/src/Render/LocalSvgRenderer.php b/src/Render/LocalSvgRenderer.php index bb0b039..5d37ec3 100644 --- a/src/Render/LocalSvgRenderer.php +++ b/src/Render/LocalSvgRenderer.php @@ -15,6 +15,7 @@ use PUGX\Poser\Calculator\GDTextSizeCalculator; use PUGX\Poser\Calculator\TextSizeCalculatorInterface; use PUGX\Poser\Image; +use SimpleXMLElement; /** * Local SVG renderer. @@ -31,16 +32,26 @@ abstract class LocalSvgRenderer implements RenderInterface */ private $textSizeCalculator; + /** + * @var string + */ + private $templatesDirectory; + /** * @param TextSizeCalculatorInterface $textSizeCalculator + * @param null|string $templatesDirectory */ - public function __construct(TextSizeCalculatorInterface $textSizeCalculator = null) + public function __construct(TextSizeCalculatorInterface $textSizeCalculator = null, $templatesDirectory = null) { $this->textSizeCalculator = $textSizeCalculator; - if (null === $this->textSizeCalculator) { $this->textSizeCalculator = new GDTextSizeCalculator(); } + + $this->templatesDirectory = $templatesDirectory; + if (null === $this->templatesDirectory) { + $this->templatesDirectory = __DIR__ . '/../Resources/templates';; + } } /** @@ -50,7 +61,7 @@ public function __construct(TextSizeCalculatorInterface $textSizeCalculator = nu */ public function render(Badge $badge) { - $template = $this->getTemplate($this->getTemplateName()); + $template = $this->getTemplate($this->getTemplateName()); $parameters = $this->buildParameters($badge); return $this->renderSvg($template, $parameters, $badge->getFormat()); @@ -68,8 +79,7 @@ abstract protected function getTemplateName(); */ private function getTemplate($format) { - $templatesDirectory = __DIR__ . '/../Resources/templates'; - $filepath = sprintf('%s/%s.svg', $templatesDirectory, $format); + $filepath = sprintf('%s/%s.svg', $this->templatesDirectory, $format); if (!file_exists($filepath)) { throw new \InvalidArgumentException(sprintf('No template for format %s', $format)); @@ -90,7 +100,7 @@ private function stringWidth($text) /** * @param string $render - * @param array $parameters + * @param array $parameters * @param string $format * * @return Image @@ -101,11 +111,13 @@ private function renderSvg($render, $parameters, $format) $render = str_replace(sprintf('{{ %s }}', $key), $variable, $render); } - // validate svg - libxml_use_internal_errors(true); - $xml = simplexml_load_string($render); - if (false === $xml) { - throw new \RuntimeException('Generated string is not a valid SVG'); + try { + $xml = new SimpleXMLElement($render); + } catch (\Exception $e) { + throw new \RuntimeException('Generated string is not a valid XML'); + } + if ('svg' !== $xml->getName()) { + throw new \RuntimeException('Generated xml is not a SVG'); } return Image::createFromString($render, $format); @@ -120,15 +132,15 @@ private function buildParameters(Badge $badge) { $parameters = array(); - $parameters['vendorWidth'] = $this->stringWidth($badge->getSubject()); - $parameters['valueWidth'] = $this->stringWidth($badge->getStatus()); - $parameters['totalWidth'] = $parameters['valueWidth'] + $parameters['vendorWidth']; - $parameters['vendorColor'] = static::VENDOR_COLOR; - $parameters['valueColor'] = $badge->getHexColor(); - $parameters['vendor'] = $badge->getSubject(); - $parameters['value'] = $badge->getStatus(); + $parameters['vendorWidth'] = $this->stringWidth($badge->getSubject()); + $parameters['valueWidth'] = $this->stringWidth($badge->getStatus()); + $parameters['totalWidth'] = $parameters['valueWidth'] + $parameters['vendorWidth']; + $parameters['vendorColor'] = static::VENDOR_COLOR; + $parameters['valueColor'] = $badge->getHexColor(); + $parameters['vendor'] = $badge->getSubject(); + $parameters['value'] = $badge->getStatus(); $parameters['vendorStartPosition'] = round($parameters['vendorWidth'] / 2, 1) + 1; - $parameters['valueStartPosition'] = $parameters['vendorWidth'] + round($parameters['valueWidth'] / 2, 1) - 1; + $parameters['valueStartPosition'] = $parameters['vendorWidth'] + round($parameters['valueWidth'] / 2, 1) - 1; return $parameters; }