-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- added services for rendering positions (banners) - added default rendering bridge for `.phtml` template with the default templates for all types of positions - added unit tests for renderer
- Loading branch information
Showing
52 changed files
with
2,024 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\AmpClient\Exception; | ||
|
||
use RuntimeException; | ||
use Throwable; | ||
use function sprintf; | ||
|
||
final class RendererException extends RuntimeException implements AmpExceptionInterface | ||
{ | ||
public static function unableToCreateFingerprint(string $positionCode, string $bannerId, ?Throwable $previous = null): self | ||
{ | ||
return new self( | ||
sprintf( | ||
'Unable to create fingerprint for banner %s on the position %s. %s', | ||
$bannerId, | ||
$positionCode, | ||
null !== $previous ? $previous->getMessage() : '', | ||
), | ||
0, | ||
$previous, | ||
); | ||
} | ||
|
||
/** | ||
* @param class-string $rendererBridgeClassname | ||
*/ | ||
public static function rendererBridgeThrownError(string $rendererBridgeClassname, string $positionCode, Throwable $previous): self | ||
{ | ||
return new self( | ||
sprintf( | ||
'Renderer bridge of type %s thrown an exception while rendering a position %s: %s', | ||
$rendererBridgeClassname, | ||
$positionCode, | ||
$previous->getMessage(), | ||
), | ||
0, | ||
$previous, | ||
); | ||
} | ||
|
||
public static function templateFileNotFound(string $filename): self | ||
{ | ||
return new self( | ||
sprintf( | ||
'Template file "%s" not found.', | ||
$filename, | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\AmpClient\Renderer; | ||
|
||
use SixtyEightPublishers\AmpClient\Response\ValueObject\Banner; | ||
use SixtyEightPublishers\AmpClient\Response\ValueObject\Position; | ||
use function array_map; | ||
use function array_search; | ||
use function count; | ||
use function max; | ||
use function mt_getrandmax; | ||
use function mt_rand; | ||
use function usort; | ||
|
||
class BannersResolver implements BannersResolverInterface | ||
{ | ||
public function resolveSingle(Position $position): ?Banner | ||
{ | ||
$banners = $position->getBanners(); | ||
|
||
if (0 >= count($banners)) { | ||
return null; | ||
} | ||
|
||
$scores = array_map( | ||
static fn (Banner $banner) => $banner->getScore(), | ||
$banners, | ||
); | ||
$firstHighestScoreKey = array_search(max($scores), $scores, true); | ||
|
||
return $banners[$firstHighestScoreKey] ?? null; | ||
} | ||
|
||
public function resolveRandom(Position $position): ?Banner | ||
{ | ||
$banners = $position->getBanners(); | ||
|
||
if (0 >= count($banners)) { | ||
return null; | ||
} | ||
|
||
$distributions = []; | ||
$weightTotal = 0; | ||
|
||
foreach ($banners as $banner) { | ||
$weightTotal += $banner->getScore(); | ||
} | ||
|
||
foreach ($banners as $index => $banner) { | ||
$distributions[$index] = $banner->getScore() / $weightTotal; | ||
} | ||
|
||
$key = 0; | ||
$selector = mt_rand() / mt_getrandmax(); | ||
|
||
while (0 < $selector) { | ||
$selector -= $distributions[$key]; | ||
$key++; | ||
} | ||
|
||
$key--; | ||
|
||
return $banners[$key] ?? $banners[0]; | ||
} | ||
|
||
public function resolveMultiple(Position $position): array | ||
{ | ||
$banners = $position->getBanners(); | ||
|
||
if (0 >= count($banners)) { | ||
return []; | ||
} | ||
|
||
usort( | ||
$banners, | ||
static fn (Banner $left, Banner $right): int => $right->getScore() <=> $left->getScore(), | ||
); | ||
|
||
return $banners; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\AmpClient\Renderer; | ||
|
||
use SixtyEightPublishers\AmpClient\Response\ValueObject\Banner; | ||
use SixtyEightPublishers\AmpClient\Response\ValueObject\Position; | ||
|
||
interface BannersResolverInterface | ||
{ | ||
public function resolveSingle(Position $position): ?Banner; | ||
|
||
public function resolveRandom(Position $position): ?Banner; | ||
|
||
/** | ||
* @return array<int, Banner> | ||
*/ | ||
public function resolveMultiple(Position $position): array; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\AmpClient\Renderer\BreakpointStyle; | ||
|
||
use SixtyEightPublishers\AmpClient\Renderer\Phtml\Helpers; | ||
use SixtyEightPublishers\AmpClient\Response\ValueObject\Banner; | ||
use SixtyEightPublishers\AmpClient\Response\ValueObject\Position; | ||
use function array_map; | ||
use function count; | ||
use function implode; | ||
use function krsort; | ||
use function ksort; | ||
use function sprintf; | ||
|
||
final class BreakpointStyle | ||
{ | ||
/** @var array<int, Selector> */ | ||
private array $selectors = []; | ||
|
||
/** @var array<int, Media> */ | ||
private array $media = []; | ||
|
||
public function __construct(Position $position, Banner $banner) | ||
{ | ||
$selectorMask = sprintf( | ||
'[data-amp-banner="%s"] [data-amp-content-breakpoint="%s"]', | ||
Helpers::escapeHtmlAttr($position->getCode()), | ||
'%s', | ||
); | ||
|
||
$defaultContent = null; | ||
$alternativeContents = []; | ||
|
||
foreach ($banner->getContents() as $content) { | ||
if (null === $content->getBreakpoint()) { | ||
$defaultContent = $content; | ||
} else { | ||
$alternativeContents[$content->getBreakpoint()] = $content; | ||
} | ||
} | ||
|
||
if (Position::BreakpointTypeMax === $position->getBreakpointType()) { | ||
$mediaRuleMask = 'max-width: %dpx'; | ||
krsort($alternativeContents); | ||
} else { | ||
$mediaRuleMask = 'min-width: %dpx'; | ||
ksort($alternativeContents); | ||
} | ||
|
||
foreach ($alternativeContents as $alternativeContent) { | ||
$this->selectors[] = $selector = new Selector(sprintf( | ||
$selectorMask, | ||
$alternativeContent->getBreakpoint(), | ||
)); | ||
|
||
$selector->properties[] = new Property('display', 'none'); | ||
|
||
$this->media[] = $media = new Media(sprintf( | ||
$mediaRuleMask, | ||
$alternativeContent->getBreakpoint(), | ||
)); | ||
|
||
if (null !== $defaultContent) { | ||
$media->selectors[] = $selectorInMedia = new Selector(sprintf( | ||
$selectorMask, | ||
'default', | ||
)); | ||
|
||
$selectorInMedia->properties[] = new Property('display', 'none'); | ||
} | ||
|
||
foreach ($alternativeContents as $alternativeContentInner) { | ||
$media->selectors[] = $selectorInMedia = new Selector(sprintf( | ||
$selectorMask, | ||
$alternativeContentInner->getBreakpoint(), | ||
)); | ||
|
||
$selectorInMedia->properties[] = new Property('display', $alternativeContentInner === $alternativeContent ? 'block' : 'none'); | ||
} | ||
} | ||
} | ||
|
||
public function __toString(): string | ||
{ | ||
return $this->getCss(); | ||
} | ||
|
||
public function getCss(): string | ||
{ | ||
if (0 >= count($this->selectors) && 0 >= count($this->media)) { | ||
return ''; | ||
} | ||
|
||
$styles = []; | ||
|
||
foreach ($this->selectors as $selector) { | ||
$styles[] = $this->stringifySelector($selector); | ||
} | ||
|
||
foreach ($this->media as $media) { | ||
$styles[] = $this->stringifyMedia($media); | ||
} | ||
|
||
return '<style>' . implode('', $styles) . '</style>'; | ||
} | ||
|
||
private function stringifySelector(Selector $selector): string | ||
{ | ||
$properties = array_map( | ||
static fn (Property $property): string => $property->name . ':' . $property->value, | ||
$selector->properties, | ||
); | ||
|
||
return sprintf( | ||
'%s{%s}', | ||
$selector->selector, | ||
implode(';', $properties), | ||
); | ||
} | ||
|
||
private function stringifyMedia(Media $media): string | ||
{ | ||
$selectors = array_map( | ||
fn (Selector $selector): string => $this->stringifySelector($selector), | ||
$media->selectors, | ||
); | ||
|
||
return sprintf( | ||
'@media(%s){%s}', | ||
$media->rule, | ||
implode('', $selectors), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\AmpClient\Renderer\BreakpointStyle; | ||
|
||
final class Media | ||
{ | ||
public string $rule; | ||
|
||
/** @var array<int, Selector> */ | ||
public array $selectors = []; | ||
|
||
public function __construct(string $rule) | ||
{ | ||
$this->rule = $rule; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\AmpClient\Renderer\BreakpointStyle; | ||
|
||
final class Property | ||
{ | ||
public string $name; | ||
|
||
public string $value; | ||
|
||
public function __construct(string $name, string $value) | ||
{ | ||
$this->name = $name; | ||
$this->value = $value; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace SixtyEightPublishers\AmpClient\Renderer\BreakpointStyle; | ||
|
||
final class Selector | ||
{ | ||
public string $selector; | ||
|
||
/** @var array<int, Property> */ | ||
public array $properties = []; | ||
|
||
public function __construct(string $selector) | ||
{ | ||
$this->selector = $selector; | ||
} | ||
} |
Oops, something went wrong.