<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Martin Bean</title>
    <description>The latest articles on Forem by Martin Bean (@martinbean).</description>
    <link>https://forem.com/martinbean</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F156228%2F74a006ca-e5b1-4096-a5c8-a2c3919a35d0.jpg</url>
      <title>Forem: Martin Bean</title>
      <link>https://forem.com/martinbean</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/martinbean"/>
    <language>en</language>
    <item>
      <title>Dynamic named slots in Vue 3</title>
      <dc:creator>Martin Bean</dc:creator>
      <pubDate>Fri, 22 Nov 2024 01:40:06 +0000</pubDate>
      <link>https://forem.com/martinbean/dynamic-named-slots-in-vue-3-5e9i</link>
      <guid>https://forem.com/martinbean/dynamic-named-slots-in-vue-3-5e9i</guid>
      <description>&lt;p&gt;I’ve recently been re-building an admin panel in a personal &lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt;-based project, convering it from “traditional” &lt;a href="https://laravel.com/docs/blade" rel="noopener noreferrer"&gt;Blade&lt;/a&gt; views to an &lt;a href="https://inertiajs.com" rel="noopener noreferrer"&gt;Inertia&lt;/a&gt;-based solution. As part of this, I’ve been identifying repeating elements that can be extracted into reusable &lt;a href="https://vuejs.org" rel="noopener noreferrer"&gt;Vue&lt;/a&gt; components.&lt;/p&gt;

&lt;p&gt;One such component is a table, listing records. In my application, I’ve named this a &lt;code&gt;ResourceTable&lt;/code&gt;. My first pass at this was to just pass headers and items as props. Headers was a map of the model attribute name and the human-friendly name for those attributes; and items was an array of models.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nx"&gt;defineProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;v-bind:key=&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"(value, key) in headers"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;scope=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="na"&gt;v-bind:key=&lt;/span&gt;&lt;span class="s"&gt;"index"&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"(item, index) in items"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;v-bind:key=&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"(value, key) in headers"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;For the table header, the component just loops over &lt;code&gt;headers&lt;/code&gt; prop and outputs the value in a &lt;code&gt;&amp;lt;th&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;For the table body, the component loops over each item in the &lt;code&gt;items&lt;/code&gt; prop, and then iterates over the &lt;code&gt;headers&lt;/code&gt; again to print the attribute value for each headers’ key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example of using this component looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ResourceTable&lt;/span&gt;
    &lt;span class="na"&gt;v-bind:headers=&lt;/span&gt;&lt;span class="s"&gt;"{
        'name': 'Name',
        'birth_date': 'Birthday'
    }"&lt;/span&gt;
    &lt;span class="na"&gt;v-bind:items=&lt;/span&gt;&lt;span class="s"&gt;"[
        { 'name': 'John Doe', 'birth_date': null },
        { 'name': 'Jane Doe', 'birth_date': '1984-03-21' },
        { 'name': 'Joe Bloggs', 'birth_date' null }
    ]"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, data is not always necessarily consistent. For example, the items above all have a &lt;code&gt;birth_date&lt;/code&gt; property, but the property value can be either a string or &lt;code&gt;null&lt;/code&gt;. It would be nice to handle these cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling &lt;code&gt;null&lt;/code&gt; values
&lt;/h2&gt;

&lt;p&gt;The first case I handled was &lt;code&gt;null&lt;/code&gt; values. I decided to output an em dash, with a more helpful label for those using assistive technologies like screen readers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  &amp;lt;template v-bind:key="key" v-for="(value, key) in headers"&amp;gt;
&lt;span class="gd"&gt;-     &amp;lt;td&amp;gt;{{ item[key] }}&amp;lt;/td&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+     &amp;lt;td&amp;gt;
+         &amp;lt;template v-if="item[key] === null"&amp;gt;
+             &amp;lt;span aria-label="No value"&amp;gt;&amp;amp;mdash;&amp;lt;/span&amp;gt;
+         &amp;lt;/template&amp;gt;
+         &amp;lt;template v-else&amp;gt;{{ item[key] }}&amp;lt;/template&amp;gt;
+     &amp;lt;/td&amp;gt;
&lt;/span&gt;  &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using dynamic named slots for each cell
&lt;/h2&gt;

&lt;p&gt;Next, to have full control over how individual cells rendered, I used a slot with a dynamic name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  &amp;lt;td&amp;gt;
      &amp;lt;template v-if="item[key] === null"&amp;gt;
          &amp;lt;span aria-label="No value"&amp;gt;&amp;amp;mdash;&amp;lt;/span&amp;gt;
      &amp;lt;/template&amp;gt;
&lt;span class="gd"&gt;-     &amp;lt;template v-else&amp;gt;{{ item[key] }}&amp;lt;/template&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+     &amp;lt;template v-else&amp;gt;
+         &amp;lt;slot v-bind:name="`cell(${key})`" v-bind:value="item[key]"&amp;gt;{{ item.key }}&amp;lt;/slot&amp;gt;
+     &amp;lt;/template&amp;gt;
&lt;/span&gt;  &amp;lt;/td&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each cell, a new slot is defined. So for cells for the attribute &lt;code&gt;name&lt;/code&gt;, there would be a corresponding slot with the name &lt;code&gt;cell(name)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If I don’t use these slots in my template, then they’ll just get the default value as before. But now if I &lt;em&gt;do&lt;/em&gt; use these slots in my template, I can control have the value is displayed. So for &lt;code&gt;birth_date&lt;/code&gt; values, I may want to do some formatting, or use a completely different component to handle the rendering of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  &amp;lt;ResourceTable
      v-bind:headers="{
          'name': 'Name',
          'birth_date': 'Birthday'
      }"
      v-bind:items="[
          { 'name': 'John Doe', 'birth_date': null },
          { 'name': 'Jane Doe', 'birth_date': '1984-03-21' },
          { 'name': 'Joe Bloggs', 'birth_date' null }
      ]"
&lt;span class="gd"&gt;- /&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ &amp;gt;
+     &amp;lt;template v-slot:cell(birth_date)="{ value }"&amp;gt;
+         &amp;lt;FormattedDate v-model="value" /&amp;gt;
+     &amp;lt;/template&amp;gt;
+ &amp;lt;/ResourceTable&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding row actions
&lt;/h2&gt;

&lt;p&gt;It’s common in web applications for each row to have associated actions, i.e. edit that record, delete that record, etc. To accomplish this, I used an optional slot. If I defined a slot named &lt;code&gt;actions&lt;/code&gt; in my template, then it would automatically add a new table heading, and a cell at the end of each row to hold the defined actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  &amp;lt;thead&amp;gt;
      &amp;lt;tr&amp;gt;
          &amp;lt;template v-bind:key="key" v-for="(value, key) in headers"&amp;gt;
              &amp;lt;th scope="col"&amp;gt;{{ value }}&amp;lt;/th&amp;gt;
&lt;span class="gi"&gt;+             &amp;lt;template v-if="'actions' in $slots"&amp;gt;
+                 &amp;lt;th scope="col"&amp;gt;Actions&amp;lt;/th&amp;gt;
+             &amp;lt;/template&amp;gt;
&lt;/span&gt;          &amp;lt;/template&amp;gt;
      &amp;lt;/tr&amp;gt;
  &amp;lt;/thead&amp;gt;
  &amp;lt;tbody&amp;gt;
      &amp;lt;tr&amp;gt;
          &amp;lt;template v-bind:key="index" v-for="(item, index) in items"&amp;gt;
              &amp;lt;template v-bind:key="key" v-for="(value, key) in headers"&amp;gt;
                  &amp;lt;td&amp;gt;{{ item[key] }}&amp;lt;/td&amp;gt;
              &amp;lt;/template&amp;gt;
&lt;span class="gi"&gt;+             &amp;lt;template v-if="'actions' in $slots"&amp;gt;
+                 &amp;lt;td&amp;gt;
+                     &amp;lt;slot name="actions" v-bind:item="{ item }"&amp;gt;&amp;lt;/slot&amp;gt;
+                 &amp;lt;/td&amp;gt;
+             &amp;lt;/template&amp;gt;
&lt;/span&gt;          &amp;lt;/template&amp;gt;
      &amp;lt;/tr&amp;gt;
  &amp;lt;/tbody&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;actions&lt;/code&gt; slot is a scoped slot that makes the &lt;code&gt;item&lt;/code&gt; available, so that I can use its attributes, i.e. for building URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  &amp;lt;ResourceTable
      v-bind:headers="{
          'name': 'Name',
          'birth_date': 'Birthday'
      }"
      v-bind:items="[
          { 'name': 'John Doe', 'birth_date': null },
          { 'name': 'Jane Doe', 'birth_date': '1984-03-21' },
          { 'name': 'Joe Bloggs', 'birth_date' null }
      ]"
  &amp;gt;
      &amp;lt;template v-slot:cell(birth_date)="{ value }"&amp;gt;
          &amp;lt;FormattedDate v-model="value" /&amp;gt;
      &amp;lt;/template&amp;gt;
&lt;span class="gi"&gt;+     &amp;lt;template v-slot:actions="{ item }"&amp;gt;
+         &amp;lt;ResourceTableAction
+             title="Edit"
+             v-bind:url="editUrl(item)"
+         /&amp;gt;
+         &amp;lt;ResourceTableAction
+             confirm="Are you sure you want to delete this item?"
+             method="delete"
+             title="Delete"
+             v-bind:url="deleteUrl(item)"
+         /&amp;gt;
+     &amp;lt;/template&amp;gt;
&lt;/span&gt;  &amp;lt;/ResourceTable&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I now have a re-usable “resource table” component that will handle most cases by default, but also gives me the ability to have full control over cell values if I need it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Test models for SwiftUI previews</title>
      <dc:creator>Martin Bean</dc:creator>
      <pubDate>Tue, 28 Jul 2020 21:49:58 +0000</pubDate>
      <link>https://forem.com/martinbean/test-models-for-swiftui-previews-9a7</link>
      <guid>https://forem.com/martinbean/test-models-for-swiftui-previews-9a7</guid>
      <description>&lt;p&gt;In my spare time, I’m currently building an iOS app for a video on demand platform I operate, &lt;a href="https://vod.yourfightsite.com/" rel="noopener noreferrer"&gt;Your Fight Site VOD&lt;/a&gt;.&lt;br&gt;
I’m using SwiftUI and absolutely &lt;em&gt;love&lt;/em&gt; its declarative way of building iOS apps.&lt;/p&gt;

&lt;p&gt;Having worked a lot with component-based JavaScript frameworks such as &lt;a href="//https//vuejs.org/"&gt;Vue.js&lt;/a&gt; I’m accustomed to small, discreet components that can be reused and composed to make up larger views. In this vein, my app has a &lt;code&gt;VideoListItem&lt;/code&gt; view. This view represents a single row in a list of videos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;VideoListView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Video&lt;/span&gt;

  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;NavigationLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;VideoDetailsView&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above is a simplified version of the actual view, but it shows the video details, and when tapped navigates the user to the view the details of that particular video. The important thing to note is that the view requires a well-formed &lt;code&gt;Video&lt;/code&gt; struct instance.&lt;/p&gt;

&lt;p&gt;SwiftUI also offers the ability to “preview” views directly in Xcode without the need for using the device simulator or running on a physical device. However, if the view you’re previewing requires data, so in turn do the previews.&lt;/p&gt;

&lt;p&gt;Instead of retrieving data over the network for the purpose of previews, I’ve taken to defining static &lt;code&gt;test&lt;/code&gt; methods in my structs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Identifiable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UUID&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;Video&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Video&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Test Video"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can then use these &lt;code&gt;test&lt;/code&gt; methods to populate previews with well-defined instances of my application’s models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;VideoListView_Previews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PreviewProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;previews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;VideoListView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swift is pretty clever in that it infers the &lt;code&gt;video&lt;/code&gt; argument takes a &lt;code&gt;Video&lt;/code&gt; instance, so therefore I can call methods (such as &lt;code&gt;test&lt;/code&gt;) using the shorthand notation seen above. Nice!&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
    </item>
    <item>
      <title>Using Value Objects to Give Meaning</title>
      <dc:creator>Martin Bean</dc:creator>
      <pubDate>Thu, 07 Nov 2019 13:51:53 +0000</pubDate>
      <link>https://forem.com/martinbean/using-value-objects-to-give-meaning-3f8m</link>
      <guid>https://forem.com/martinbean/using-value-objects-to-give-meaning-3f8m</guid>
      <description>&lt;p&gt;I’m currently re-building a video on demand platform I currently operate, &lt;a href="https://vod.yourfightsite.com/?utm_source=martinbean&amp;amp;utm_medium=website&amp;amp;utm_campaign=post" rel="noopener noreferrer"&gt;Your Fight Site VOD&lt;/a&gt;. During the build, I’ve found myself using more and more &lt;em&gt;value objects&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you’re unfamiliar with value objects, they’re simply objects that represent simple things, but not &lt;em&gt;specific&lt;/em&gt; things. An object representing a specific thing would be an entity. These two terms are usually found when discussing &lt;em&gt;Domain-driven design&lt;/em&gt; (or “DDD”).&lt;/p&gt;

&lt;p&gt;An example highlighting the difference between a value object and an entity can be found in money. For example, if I had £10 and you had £10, then those two &lt;em&gt;values&lt;/em&gt; would be equal. However, individual bank notes are numbered; we can’t have the same note, so individual notes would be represented as &lt;em&gt;entities&lt;/em&gt; (and probably use their serial numbers as their identifiers).&lt;/p&gt;

&lt;h2&gt;
  
  
  Value objects for single properties
&lt;/h2&gt;

&lt;p&gt;In my application, I’ve been unearthing values that can be elevated from simple, primitive values to a value object. One is a video’s duration. I store this as a simple integer (representing the number of seconds), but this presented the opportunity to create a &lt;code&gt;Duration&lt;/code&gt; object. Now that number (i.e. 3,600) has &lt;strong&gt;meaning&lt;/strong&gt;. The class looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$seconds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$seconds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;asMinutes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;asTimeString&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toTimeString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class is instantiated with an integer value (and can’t be created with any other value). As it’s a class, I can then define methods for common operations, such as getting different representations of the value (i.e. as minutes, or as a HH:MM:SS-formatted time string).&lt;/p&gt;

&lt;p&gt;I’ve also defined as &lt;code&gt;__toString()&lt;/code&gt; method. This is so I can use it in &lt;a href="https://laravel.com/docs/master/eloquent" rel="noopener noreferrer"&gt;Eloquent&lt;/a&gt; models. I can add a &lt;a href="https://laravel.com/docs/master/eloquent-mutators#defining-a-mutator" rel="noopener noreferrer"&gt;mutator&lt;/a&gt; for my &lt;code&gt;duration&lt;/code&gt; attribute to instead return this new value object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Video&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getDurationAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;?Duration&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when I call &lt;code&gt;$video-&amp;gt;duration&lt;/code&gt;, I’ll get a &lt;code&gt;Duration&lt;/code&gt; instance (if the duration is greater than zero). If I use this attribute in a &lt;a href="https://laravel.com/docs/master/blade" rel="noopener noreferrer"&gt;Blade&lt;/a&gt; template, then it’ll just be cast to a string and the original value presented thanks to the &lt;code&gt;__toString()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Duration: {{ $video-&amp;gt;duration }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Value objects for multiple properties
&lt;/h2&gt;

&lt;p&gt;In my application, a video can also be rented and streamed for a predetermined length of time and monetary amount. This time and amount is set by the content owner. I have three properties representing this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rental_amount&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rental_interval&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rental_interval_count&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Their names are influenced by &lt;a href="https://stripe.com/docs/api/plans/object" rel="noopener noreferrer"&gt;Stripe’s &lt;code&gt;plan&lt;/code&gt; object&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rental_amount&lt;/code&gt; is an integer, representing the price in pence.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rental_interval&lt;/code&gt; is a constant; one of day, week, month, or year.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rental_interval_count&lt;/code&gt; is the number of days/weeks/months/years a customer can rent the video.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these make up what I’ve called the &lt;em&gt;rental terms&lt;/em&gt;. I’ve therefore created a class that takes the values of these three properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RentalTerms&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$interval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$intervalCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$intervalCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ensureIntervalIsValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$interval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;intervalCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$intervalCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getAmountFormatted&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Cashier&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;formatAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getIntervalFormatted&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s1"&gt;'day'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans_choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1 day|:count days'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;intervalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s1"&gt;'week'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans_choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1 week|:count weeks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;intervalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s1"&gt;'month'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans_choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1 month|:count months'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;intervalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s1"&gt;'year'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trans_choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1 year|:count years'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;intervalCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;ensureIntervalIsValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'day'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'week'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'month'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'year'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Interval is invalid'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As this class doesn’t map to a single value, I just added a “getter” to my &lt;code&gt;Video&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Video&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getRentalTerms&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;RentalTerms&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RentalTerms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rental_amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rental_interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rental_interval_count&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, I can use methods on the object to get the rental terms in a variety of helpful formats throughout the application, and in Blade templates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Example: Rent for £3.99 for 1 month --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  Rent for {{ $terms-&amp;gt;getAmountFormatted() }}
  for {{ $terms-&amp;gt;getIntervalFormatted() }}
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully this gives you some ideas if you’ve not used value objects in your projects before!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>ddd</category>
    </item>
  </channel>
</rss>
