diff --git a/spec/Fixtures/flat-square.svg b/spec/Fixtures/flat-square.svg new file mode 100644 index 0000000..6e7903c --- /dev/null +++ b/spec/Fixtures/flat-square.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + license + license + MIT + MIT + + diff --git a/spec/Fixtures/flat.svg b/spec/Fixtures/flat.svg new file mode 100644 index 0000000..a86cc24 --- /dev/null +++ b/spec/Fixtures/flat.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + license + license + MIT + MIT + + 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/license.svg b/spec/Fixtures/license.svg index df4ea43..4bfc082 100644 --- a/spec/Fixtures/license.svg +++ b/spec/Fixtures/license.svg @@ -1,13 +1,14 @@ - - - - - - -stable -stable -v2.0 -v2.0 - - \ No newline at end of file + + + + + + + + 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/SvgFlatRenderSpec.php b/spec/PUGX/Poser/Render/SvgFlatRenderSpec.php index 3f79d2e..734957d 100644 --- a/spec/PUGX/Poser/Render/SvgFlatRenderSpec.php +++ b/spec/PUGX/Poser/Render/SvgFlatRenderSpec.php @@ -5,7 +5,6 @@ use PhpSpec\ObjectBehavior; use Prophecy\Argument; use PUGX\Poser\Badge; -use PUGX\Poser\Calculator\TextSizeCalculatorInterface; class SvgFlatRenderSpec extends ObjectBehavior { @@ -37,32 +36,9 @@ public function getMatchers() function it_should_render_a_license_mit_exactly_like_this_svg() { - $template = << - - - - - - - - - - - - - - license - license - MIT - MIT - - -EOF; - + $fixture = __DIR__ . '/../../../Fixtures/flat.svg'; + $template = file_get_contents($fixture); $badge = Badge::fromURI('license-MIT-blue.svg'); $this->render($badge)->__toString()->shouldBeLike($template); } - - -} +} diff --git a/spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php b/spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php index 6abc733..c476785 100644 --- a/spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php +++ b/spec/PUGX/Poser/Render/SvgFlatSquareRenderSpec.php @@ -24,7 +24,7 @@ function it_should_render_a_svg() public function getMatchers() { return array( - 'beAValidSVGImage' => function($subject) { + 'beAValidSVGImage' => function ($subject) { $regex = '/^$/'; $matches = array(); @@ -36,29 +36,8 @@ public function getMatchers() function it_should_render_a_license_mit_exactly_like_this_svg() { - $template = << - - - - - - - - - - - - - - license - license - MIT - MIT - - -EOF; - + $fixture = __DIR__ . '/../../../Fixtures/flat-square.svg'; + $template = file_get_contents($fixture); $badge = Badge::fromURI('license-MIT-blue.svg'); $this->render($badge)->__toString()->shouldBeLike($template); } diff --git a/spec/PUGX/Poser/Render/SvgRenderSpec.php b/spec/PUGX/Poser/Render/SvgRenderSpec.php index 2793036..50dc13c 100644 --- a/spec/PUGX/Poser/Render/SvgRenderSpec.php +++ b/spec/PUGX/Poser/Render/SvgRenderSpec.php @@ -21,15 +21,31 @@ 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( - 'beAValidSVGImage' => function($subject) { + 'beAValidSVGImage' => function ($subject) { - $regex = '/^$/'; - $matches = array(); + $regex = '/^$/'; + $matches = array(); - return preg_match($regex, (string) $subject, $matches, PREG_OFFSET_CAPTURE, 0); + return preg_match($regex, (string) $subject, $matches, PREG_OFFSET_CAPTURE, 0); } ); } diff --git a/src/Render/LocalSvgRenderer.php b/src/Render/LocalSvgRenderer.php new file mode 100644 index 0000000..5d37ec3 --- /dev/null +++ b/src/Render/LocalSvgRenderer.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace PUGX\Poser\Render; + +use PUGX\Poser\Badge; +use PUGX\Poser\Calculator\GDTextSizeCalculator; +use PUGX\Poser\Calculator\TextSizeCalculatorInterface; +use PUGX\Poser\Image; +use SimpleXMLElement; + +/** + * Local SVG renderer. + * Generate SVG badges from local templates. + * + * @author JM Leroux + */ +abstract class LocalSvgRenderer implements RenderInterface +{ + const VENDOR_COLOR = '#555'; + + /** + * @var TextSizeCalculatorInterface + */ + private $textSizeCalculator; + + /** + * @var string + */ + private $templatesDirectory; + + /** + * @param TextSizeCalculatorInterface $textSizeCalculator + * @param null|string $templatesDirectory + */ + 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';; + } + } + + /** + * @param Badge $badge + * + * @return mixed + */ + public function render(Badge $badge) + { + $template = $this->getTemplate($this->getTemplateName()); + $parameters = $this->buildParameters($badge); + + return $this->renderSvg($template, $parameters, $badge->getFormat()); + } + + /** + * @return string + */ + abstract protected function getTemplateName(); + + /** + * @param $format + * + * @return string SVG content of the template + */ + private function getTemplate($format) + { + $filepath = sprintf('%s/%s.svg', $this->templatesDirectory, $format); + + if (!file_exists($filepath)) { + throw new \InvalidArgumentException(sprintf('No template for format %s', $format)); + } + + return file_get_contents($filepath); + } + + /** + * @param $text + * + * @return float + */ + private function stringWidth($text) + { + return $this->textSizeCalculator->calculateWidth($text); + } + + /** + * @param string $render + * @param array $parameters + * @param string $format + * + * @return Image + */ + private function renderSvg($render, $parameters, $format) + { + foreach ($parameters as $key => $variable) { + $render = str_replace(sprintf('{{ %s }}', $key), $variable, $render); + } + + 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); + } + + /** + * @param Badge $badge + * + * @return array + */ + 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['vendorStartPosition'] = round($parameters['vendorWidth'] / 2, 1) + 1; + $parameters['valueStartPosition'] = $parameters['vendorWidth'] + round($parameters['valueWidth'] / 2, 1) - 1; + + return $parameters; + } +} diff --git a/src/Render/SvgFlatRender.php b/src/Render/SvgFlatRender.php index cd031c7..9ef9e93 100644 --- a/src/Render/SvgFlatRender.php +++ b/src/Render/SvgFlatRender.php @@ -11,131 +11,13 @@ namespace PUGX\Poser\Render; -use PUGX\Poser\Badge; -use PUGX\Poser\Calculator\TextSizeCalculatorInterface; -use PUGX\Poser\Calculator\GDTextSizeCalculator; -use PUGX\Poser\Image; /** * Class SvgFlatGenerator * * @author Giulio De Donato */ -class SvgFlatRender implements RenderInterface +class SvgFlatRender extends LocalSvgRenderer { - const VENDOR_COLOR = '#555'; - private $textSizeCalculator; -/* - private static $template = << - - - - - - - - - - - - - - {{ vendor }} - {{ vendor }} - {{ value }} - {{ value }} - - -EOF; - - -quasi ok -ù private static $template = << - - - - - - - - - - - - - - - - - {{ vendor }} - {{ vendor }} - {{ value }} - {{ value }} - - -EOF; -*/ - -private static $template = << - - - - - - - - - - - - - - {{ vendor }} - {{ vendor }} - {{ value }} - {{ value }} - - -EOF; - - /** - * Constructor. - * - * @param TextSizeCalculatorInterface $textSizeCalculator - */ - public function __construct(TextSizeCalculatorInterface $textSizeCalculator = null) - { - $this->textSizeCalculator = $textSizeCalculator; - - if (null === $this->textSizeCalculator) { - $this->textSizeCalculator = new GDTextSizeCalculator(); - } - } - - /** - * @param Badge $badge - * - * @return mixed - */ - public function render(Badge $badge) - { - $parameters = array(); - - $parameters['vendorWidth'] = $this->stringWidth($badge->getSubject()); - $parameters['valueWidth'] = $this->stringWidth($badge->getStatus()); - $parameters['totalWidth'] = $parameters['valueWidth'] + $parameters['vendorWidth']; - $parameters['vendorColor'] = self::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; - - return $this->renderSvg(self::$template, $parameters, $badge->getFormat()); - } - /** * A list of all supported formats. * @@ -146,17 +28,8 @@ public function supportedFormats() return array('flat', 'svg'); } - private function stringWidth($text) - { - return $this->textSizeCalculator->calculateWidth($text); - } - - private function renderSvg($render, $parameters, $format) + protected function getTemplateName() { - foreach ($parameters as $key => $variable) { - $render = str_replace(sprintf('{{ %s }}', $key), $variable, $render); - } - - return Image::createFromString($render, $format); + return 'flat'; } } diff --git a/src/Render/SvgFlatSquareRender.php b/src/Render/SvgFlatSquareRender.php index 902c09f..439fbb2 100644 --- a/src/Render/SvgFlatSquareRender.php +++ b/src/Render/SvgFlatSquareRender.php @@ -11,131 +11,13 @@ namespace PUGX\Poser\Render; -use PUGX\Poser\Badge; -use PUGX\Poser\Calculator\TextSizeCalculatorInterface; -use PUGX\Poser\Calculator\GDTextSizeCalculator; -use PUGX\Poser\Image; /** * Class SvgFlatGenerator * * @author Giulio De Donato */ -class SvgFlatSquareRender implements RenderInterface +class SvgFlatSquareRender extends LocalSvgRenderer { - const VENDOR_COLOR = '#555'; - private $textSizeCalculator; -/* - private static $template = << - - - - - - - - - - - - - - {{ vendor }} - {{ vendor }} - {{ value }} - {{ value }} - - -EOF; - - -quasi ok -ù private static $template = << - - - - - - - - - - - - - - - - - {{ vendor }} - {{ vendor }} - {{ value }} - {{ value }} - - -EOF; -*/ - -private static $template = << - - - - - - - - - - - - - - {{ vendor }} - {{ vendor }} - {{ value }} - {{ value }} - - -EOF; - - /** - * Constructor. - * - * @param TextSizeCalculatorInterface $textSizeCalculator - */ - public function __construct(TextSizeCalculatorInterface $textSizeCalculator = null) - { - $this->textSizeCalculator = $textSizeCalculator; - - if (null === $this->textSizeCalculator) { - $this->textSizeCalculator = new GDTextSizeCalculator(); - } - } - - /** - * @param Badge $badge - * - * @return mixed - */ - public function render(Badge $badge) - { - $parameters = array(); - - $parameters['vendorWidth'] = $this->stringWidth($badge->getSubject()); - $parameters['valueWidth'] = $this->stringWidth($badge->getStatus()); - $parameters['totalWidth'] = $parameters['valueWidth'] + $parameters['vendorWidth']; - $parameters['vendorColor'] = self::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; - - return $this->renderSvg(self::$template, $parameters, $badge->getFormat()); - } - /** * A list of all supported formats. * @@ -146,17 +28,8 @@ public function supportedFormats() return array('flat-square'); } - private function stringWidth($text) - { - return $this->textSizeCalculator->calculateWidth($text); - } - - private function renderSvg($render, $parameters, $format) + protected function getTemplateName() { - foreach ($parameters as $key => $variable) { - $render = str_replace(sprintf('{{ %s }}', $key), $variable, $render); - } - - return Image::createFromString($render, $format); + return 'flat-square'; } } diff --git a/src/Render/SvgRender.php b/src/Render/SvgRender.php index 7492301..64812ea 100644 --- a/src/Render/SvgRender.php +++ b/src/Render/SvgRender.php @@ -12,76 +12,15 @@ namespace PUGX\Poser\Render; use PUGX\Poser\Badge; -use PUGX\Poser\Calculator\TextSizeCalculatorInterface; -use PUGX\Poser\Calculator\GDTextSizeCalculator; -use PUGX\Poser\Image; + /** * Class SvgGenerator * * @author Claudio D'Alicandro * @author Giulio De Donato */ -class SvgRender implements RenderInterface +class SvgRender extends LocalSvgRenderer { - const VENDOR_COLOR = '#555'; - private $textSizeCalculator; - private static $template = << - - - - - - - - - - - - {{ vendor }} - {{ vendor }} - {{ value }} - {{ value }} - - -EOF; - - /** - * Constructor. - * - * @param TextSizeCalculatorInterface $textSizeCalculator - */ - public function __construct(TextSizeCalculatorInterface $textSizeCalculator = null) - { - $this->textSizeCalculator = $textSizeCalculator; - - if (null === $this->textSizeCalculator) { - $this->textSizeCalculator = new GDTextSizeCalculator(); - } - } - - /** - * @param Badge $badge - * - * @return mixed - */ - public function render(Badge $badge) - { - $parameters = array(); - - $parameters['vendorWidth'] = $this->stringWidth($badge->getSubject()); - $parameters['valueWidth'] = $this->stringWidth($badge->getStatus()); - $parameters['totalWidth'] = $parameters['valueWidth'] + $parameters['vendorWidth']; - $parameters['vendorColor'] = self::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; - - return $this->renderSvg(self::$template, $parameters, $badge->getFormat()); - } - /** * A list of all supported formats. * @@ -92,17 +31,8 @@ public function supportedFormats() return array('plastic'); } - private function stringWidth($text) + protected function getTemplateName() { - return $this->textSizeCalculator->calculateWidth($text); - } - - private function renderSvg($render, $parameters, $format) - { - foreach ($parameters as $key => $variable) { - $render = str_replace(sprintf('{{ %s }}', $key), $variable, $render); - } - - return Image::createFromString($render, $format); + return 'plastic'; } } diff --git a/src/Resources/templates/flat-square.svg b/src/Resources/templates/flat-square.svg new file mode 100644 index 0000000..8bb3772 --- /dev/null +++ b/src/Resources/templates/flat-square.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + {{ vendor }} + {{ vendor }} + {{ value }} + {{ value }} + + diff --git a/src/Resources/templates/flat.svg b/src/Resources/templates/flat.svg new file mode 100644 index 0000000..bf8eb64 --- /dev/null +++ b/src/Resources/templates/flat.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + {{ vendor }} + {{ vendor }} + {{ value }} + {{ value }} + + diff --git a/src/Resources/templates/plastic.svg b/src/Resources/templates/plastic.svg new file mode 100644 index 0000000..fc36097 --- /dev/null +++ b/src/Resources/templates/plastic.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + {{ vendor }} + {{ vendor }} + {{ value }} + {{ value }} + +