Index    |    2. Content integration with PresentationObject Factories >
--- # 1. PresentationObjects and Components > **Hint:** This section describes the manual creation of PresentationObjects, Pseudo-Enums and PresentationObject components. All of these patterns can also be scaffolded by the [Kickstarter](./05_Kickstarter.md). In this tutorial, we're going to write a PresentationObject for an image component. Our image consists of a `src`, an `alt` and an optional `title` property. ## Writing the PresentationObject The most important function of PresentationObjects is to enforce the interface between domain and presentation layer. For a single component that interface is represented by an actual PHP interface. So let's start with that: *`EXAMPLE: PresentationObject Interface`* ```php *`EXAMPLE: PresentationObject`* ```php src = $src; $this->alt = $alt; $this->title = $title; } public function getSrc(): string { return $this->src; } public function getAlt(): string { return $this->alt; } /** * Tip: * PresentationObjects are immutable. In order to perform change actions * you need to implement a copy-on-write mechanism like this one. * * Such with*-methods are optional however. * * @param string $alt * @return self */ public function withAlt(string $alt): self { return new self($this->src, $alt, $this->title); } public function getTitle(): string { return $this->title; } } ``` ## Writing the PresentationObject component For our component we need to extend `PackageFactory.AtomicFusion.PresentationObjects:PresentationObjectComponent`, which works similarly to `Neos.Fusion:Component`. The first difference to `Neos.Fusion:Component` is the mandatory `@presentationObjectInterface` annotation which connects our component to the PHP interface from above. The second difference is, that besides the usual `props`-Context, your renderer can now also access the special `presentationObject`-Context, which holds our verified data. *`EXAMPLE: Resources/Private/Fusion/Presentation/Component/Image/Image.fusion`* ```fusion prototype(Vendor.Site:Component.Image) < prototype(PackageFactory.AtomicFusion.PresentationObjects:PresentationObjectComponent) { @presentationObjectInterface = 'Vendor\\Site\\Presentation\\Image\\ImageInterface' renderer = afx` {presentationObject.alt} ` } ``` That's it! Our `Vendor.Site:Component.Image` can now be used like this (AFX): ```afx myImage = afx`` ``` Or like this (Plain Fusion): ```fusion myImage = Vendor.Site:Component.Image { presentationObject = ${someObject} } ``` An exception will be thrown, if `someObject` does not implement `Vendor\Site\Presentation\Image\ImageInterface`. ## (Pseudo) Enums It is recommended to model discrete values for presentation object properties as objects themselves. Since PHP does not support enums yet, this package provides an interface to be implemented by classes that behave similarly to enums. > **Hint:** For more information on enums in PHP, see https://stitcher.io/blog/php-enums *`EXAMPLE: Pseudo-enum`* Given we have a presentation object Headline with properties type and content. While content can be an arbitrary string, in our project by specification we only support h1-h3 as types for headlines. To prevent accidental use of h4 (or other tag names) for headlines, we model the headline type as a pseudo enum as follows: ```php |self[] */ private static array $instances = []; private string $value; private function __construct(string $value) { $this->value = $value; } public static function from(string $string): self { if (!isset(self::$instances[$string])) { if ($string !== self::TYPE_H1 && $string !== self::TYPE_H2 && $string !== self::TYPE_H3) { throw HeadlineTypeIsInvalid::becauseItMustBeOneOfTheDefinedConstants($string); } self::$instances[$string] = new self($string); } return self::$instances[$string]; } public static function h1(): self { return self::from(self::TYPE_H1); } public static function h2(): self { return self::from(self::TYPE_H2); } public static function h3(): self { return self::from(self::TYPE_H3); } public function getIsH1(): bool { return $this->value === self::TYPE_H1; } public function getIsH2(): bool { return $this->value === self::TYPE_H2; } public function getIsH3(): bool { return $this->value === self::TYPE_H3; } /** * @return array|self[] */ public static function cases(): array { return [ self::from(self::TYPE_H1), self::from(self::TYPE_H2), self::from(self::TYPE_H3) ]; } public function getValue(): string { return $this->value; } public function __toString(): string { return $this->value; } } ``` Now instead of having a string typed property in our headline, we can model it as follows: ```php **Hint:** Pseudo-enums can also be used in Neos' inspector select box editor. Please refer to [Integration Recipes](./04_IntegrationRecipes.md) to learn how it is done. ---