Skip to content

Instantly share code, notes, and snippets.

@Kcko
Last active February 12, 2022 22:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kcko/ac2597460499cf811f8fe89a80d29978 to your computer and use it in GitHub Desktop.
Save Kcko/ac2597460499cf811f8fe89a80d29978 to your computer and use it in GitHub Desktop.
<?php
abstract class Content {
protected $filePath;
public function __construct (string $filePath) {
$this->filePath = $filePath;
}
abstract public function getHtml (): string;
abstract public function getCss (): string;
}
class Image extends Content {
public function getCss (): string {
return <<<IMG
.content {
width: 100%;
border-style: dotted dashed solid double;
border-radius: 50px;
}
IMG;
}
public function getHtml (): string {
return "<img class='content' src='$this->filePath' />";
}
}
class Video extends Content {
public function getCss (): string {
return <<<VID
.content {
width: 100%;
}
video::-webkit-media-controls-start-playback-button {
display: none;
}
VID;
}
public function getHtml (): string {
return "<video class='content' src='$this->filePath' autoplay muted loop></video>";
}
}
abstract class Display {
protected $content;
public function __construct (Content $content) {
$this->content = $content;
}
abstract public function render (): string;
}
class Standard extends Display {
public function render (): string {
$html = $this->content->getHtml();
$css = $this->content->getCss();
return <<<CONTENT
$html;
<style>
$css
</style>
CONTENT;
}
}
class Blurred extends Display {
private $blurredRules = <<<CSS
.content {
filter: blur(5px);
-webkit-filter: blur(5px);
}
CSS;
public function render (): string
{
$html = $this->content->getHtml();
$css = $this->content->getCss();
return <<<CONTENT
$html;
<style>
$css
$this->blurredRules
</style>
CONTENT;
}
}
$vid = new Video("demo.mp4");
$img = new Image("demo.png");
$displayVid = new Standard($vid);
$blurredDisplayVid = new Blurred($vid);
$displayImg = new Standard($img);
$blurredDisplayImg = new Blurred($img);
echo($displayVid->render() . PHP_EOL);
echo($blurredDisplayVid->render() . PHP_EOL);
echo($displayImg->render() . PHP_EOL);
echo($blurredDisplayImg->render() . PHP_EOL);
// USAGE
<?php
interface Formatter
{
public function format(string $text): string;
}
class PlainTextFormatter implements Formatter
{
public function format(string $text): string
{
return $text;
}
}
class HtmlFormatter implements Formatter
{
public function format(string $text): string
{
return sprintf('<p>%s</p>', $text);
}
}
abstract class Service
{
protected Formatter $implementation;
public function __construct(Formatter $printer)
{
$this->implementation = $printer;
}
public function setImplementation(Formatter $printer)
{
$this->implementation = $printer;
}
abstract public function get(): string;
}
class HelloWorldService extends Service
{
public function get(): string
{
return $this->implementation->format('Hello World');
}
}
class PingService extends Service
{
public function get(): string
{
return $this->implementation->format('pong');
}
}
// USAGE:
$service = new HelloWorldService(new PlainTextFormatter());
$service = new HelloWorldService(new HtmlFormatter());
<?php
/**
* The Abstraction.
*/
abstract class Page
{
/**
* @var Renderer
*/
protected $renderer;
/**
* The Abstraction is usually initialized with one of the Implementation
* objects.
*/
public function __construct(Renderer $renderer)
{
$this->renderer = $renderer;
}
/**
* The Bridge pattern allows replacing the attached Implementation object
* dynamically.
*/
public function changeRenderer(Renderer $renderer): void
{
$this->renderer = $renderer;
}
/**
* The "view" behavior stays abstract since it can only be provided by
* Concrete Abstraction classes.
*/
abstract public function view(): string;
}
/**
* This Concrete Abstraction represents a simple page.
*/
class SimplePage extends Page
{
protected $title;
protected $content;
public function __construct(Renderer $renderer, string $title, string $content)
{
parent::__construct($renderer);
$this->title = $title;
$this->content = $content;
}
public function view(): string
{
return $this->renderer->renderParts([
$this->renderer->renderHeader(),
$this->renderer->renderTitle($this->title),
$this->renderer->renderTextBlock($this->content),
$this->renderer->renderFooter()
]);
}
}
/**
* This Concrete Abstraction represents a more complex page.
*/
class ProductPage extends Page
{
protected $product;
public function __construct(Renderer $renderer, Product $product)
{
parent::__construct($renderer);
$this->product = $product;
}
public function view(): string
{
return $this->renderer->renderParts([
$this->renderer->renderHeader(),
$this->renderer->renderTitle($this->product->getTitle()),
$this->renderer->renderTextBlock($this->product->getDescription()),
$this->renderer->renderImage($this->product->getImage()),
$this->renderer->renderLink("/cart/add/" . $this->product->getId(), "Add to cart"),
$this->renderer->renderFooter()
]);
}
}
/**
* A helper class for the ProductPage class.
*/
class Product
{
private $id, $title, $description, $image, $price;
public function __construct(
string $id,
string $title,
string $description,
string $image,
float $price
) {
$this->id = $id;
$this->title = $title;
$this->description = $description;
$this->image = $image;
$this->price = $price;
}
public function getId(): string { return $this->id; }
public function getTitle(): string { return $this->title; }
public function getDescription(): string { return $this->description; }
public function getImage(): string { return $this->image; }
public function getPrice(): float { return $this->price; }
}
/**
* The Implementation declares a set of "real", "under-the-hood", "platform"
* methods.
*
* In this case, the Implementation lists rendering methods that can be used to
* compose any web page. Different Abstractions may use different methods of the
* Implementation.
*/
interface Renderer
{
public function renderTitle(string $title): string;
public function renderTextBlock(string $text): string;
public function renderImage(string $url): string;
public function renderLink(string $url, string $title): string;
public function renderHeader(): string;
public function renderFooter(): string;
public function renderParts(array $parts): string;
}
/**
* This Concrete Implementation renders a web page as HTML.
*/
class HTMLRenderer implements Renderer
{
public function renderTitle(string $title): string
{
return "<h1>$title</h1>";
}
public function renderTextBlock(string $text): string
{
return "<div class='text'>$text</div>";
}
public function renderImage(string $url): string
{
return "<img src='$url'>";
}
public function renderLink(string $url, string $title): string
{
return "<a href='$url'>$title</a>";
}
public function renderHeader(): string
{
return "<html><body>";
}
public function renderFooter(): string
{
return "</body></html>";
}
public function renderParts(array $parts): string
{
return implode("\n", $parts);
}
}
/**
* This Concrete Implementation renders a web page as JSON strings.
*/
class JsonRenderer implements Renderer
{
public function renderTitle(string $title): string
{
return '"title": "' . $title . '"';
}
public function renderTextBlock(string $text): string
{
return '"text": "' . $text . '"';
}
public function renderImage(string $url): string
{
return '"img": "' . $url . '"';
}
public function renderLink(string $url, string $title): string
{
return '"link": {"href": "' . $title . '", "title": "' . $title . '""}';
}
public function renderHeader(): string
{
return '';
}
public function renderFooter(): string
{
return '';
}
public function renderParts(array $parts): string
{
return "{\n" . implode(",\n", array_filter($parts)) . "\n}";
}
}
/**
* The client code usually deals only with the Abstraction objects.
*/
function clientCode(Page $page)
{
// ...
echo $page->view();
// ...
}
/**
* The client code can be executed with any pre-configured combination of the
* Abstraction+Implementation.
*/
$HTMLRenderer = new HTMLRenderer;
$JSONRenderer = new JsonRenderer;
$page = new SimplePage($HTMLRenderer, "Home", "Welcome to our website!");
echo "HTML view of a simple content page:\n";
clientCode($page);
echo "\n\n";
/**
* The Abstraction can change the linked Implementation at runtime if needed.
*/
$page->changeRenderer($JSONRenderer);
echo "JSON view of a simple content page, rendered with the same client code:\n";
clientCode($page);
echo "\n\n";
$product = new Product("123", "Star Wars, episode1",
"A long time ago in a galaxy far, far away...",
"/images/star-wars.jpeg", 39.95);
$page = new ProductPage($HTMLRenderer, $product);
echo "HTML view of a product page, same client code:\n";
clientCode($page);
echo "\n\n";
$page->changeRenderer($JSONRenderer);
echo "JSON view of a simple content page, with the same client code:\n";
clientCode($page);
/*
Output.txt: Execution result
HTML view of a simple content page:
<html><body>
<h1>Home</h1>
<div class='text'>Welcome to our website!</div>
</body></html>
JSON view of a simple content page, rendered with the same client code:
{
"title": "Home",
"text": "Welcome to our website!"
}
HTML view of a product page, same client code:
<html><body>
<h1>Star Wars, episode1</h1>
<div class='text'>A long time ago in a galaxy far, far away...</div>
<img src='/images/star-wars.jpeg'>
<a href='/cart/add/123'>Add to cart</a>
</body></html>
JSON view of a simple content page, with the same client code:
{
"title": "Star Wars, episode1",
"text": "A long time ago in a galaxy far, far away...",
"img": "/images/star-wars.jpeg",
"link": {"href": "Add to cart", "title": "Add to cart""}
}
*/
<?php
interface DeviceInterface {
public function setSender(MessagingInterface $sender);
public function send($body);
}
abstract class Device implements DeviceInterface {
protected $sender;
public function setSender(MessagingInterface $sender) {
$this->sender = $sender;
}
}
class Phone extends Device {
public function send($body) {
$body .= "\n\n Sent from a phone.";
return $this->sender->send($body);
}
}
class Tablet extends Device {
public function send($body) {
$body .= "\n\n Sent from a Tablet.";
return $this->sender->send($body);
}
}
interface MessagingInterface {
public function send($body);
}
class Skype implements MessagingInterface {
public function send($body) {
// Send a message through the Skype API
}
}
class Whatsapp implements MessagingInterface {
public function send($body) {
// Send a message through the Whatsapp API
}
}
$phone = new Phone;
$phone->setSender(new Skype);
$phone->send("Hey Buddy");

BAD: GOOD:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment