Completed
Push — master ( bccd9c...aad4fd )
by Dominik
03:34
created

AzineTemplateProvider::__construct()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 4

Importance

Changes 4
Bugs 0 Features 1
Metric Value
c 4
b 0
f 1
dl 0
loc 22
ccs 20
cts 20
cp 1
rs 8.9197
cc 4
eloc 16
nc 6
nop 3
crap 4
1
<?php
2
namespace Azine\EmailBundle\Services;
3
4
/**
5
 * This Service provides the templates and template-variables to be used for emails
6
 * @author Dominik Businger
7
 */
8
use Azine\EmailBundle\DependencyInjection\AzineEmailExtension;
9
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
10
use Symfony\Bundle\FrameworkBundle\Translation\Translator;
11
12
class AzineTemplateProvider implements TemplateProviderInterface
13
{
14
    const BASE_TEMPLATE 					= 'AzineEmailBundle::baseEmailLayout';
15
    const NEWSLETTER_TEMPLATE 				= 'AzineEmailBundle::newsletterEmailLayout';
16
    const NOTIFICATIONS_TEMPLATE			= 'AzineEmailBundle::notificationsEmailLayout';
17
    const CONTENT_ITEM_MESSAGE_TEMPLATE		= 'AzineEmailBundle:contentItem:message';
18
    const FOS_USER_PWD_RESETTING_TEMPLATE	= "FOSUserBundle:Resetting:email";
19
    const FOS_USER_REGISTRATION_TEMPLATE	= "FOSUserBundle:Registration:email";
20
    const SEND_IMMEDIATELY_FLAG             = "AzineEmailBundle_SendThisEmailImmediately";
21
22
    /**
23
     * Override this function for your template(s)!
24
     *
25
     * For each template you like to render, you need to supply the array with variables that can be passed to the twig renderer.
26
     * Those variables can then be used in the twig-template => {{ logo_png }}
27
     *
28
     * In this function you should fill a set of variables for each template.
29
     *
30
     * @param string $template the template id in standard-notation, without the ending ( .txt.twig) => "AcmeFooBundle:bar:default"
31
     * @return array
32
     */
33 10
    protected function getParamArrayFor($template)
34
    {
35
        // this implementation uses the same array for all templates.
36
        // override this function with a more sophisticated logic
37
        // if you need different styles for different templates.
38
39 10
        $newVars = array();
40
41
        // add template-specific stuff.
42 10
        if ($template == self::NOTIFICATIONS_TEMPLATE) {
43 1
            $newVars['subject'] = "Your notifications sent by AzineEmailBundle";
44 1
        }
45
46 10
        if ($template == self::NEWSLETTER_TEMPLATE) {
47 4
            $newVars['subject'] = "Newsletter sent by AzineEmailBundle";
48 4
        }
49
50
        // send some mails immediately instead of spooled
51 10
        if($template == self::FOS_USER_PWD_RESETTING_TEMPLATE || $template == self::FOS_USER_REGISTRATION_TEMPLATE){
52 3
            $newVars[self::SEND_IMMEDIATELY_FLAG] = true;
53 3
        }
54
55
        // add generic stuff needed for all templates
56
57
        // add images to be encoded and attached to the email
58
        // the absolute file-path will be replaced with the CID of
59
        // the attached image, so it will be rendered in the html-email.
60
        // => to render the logo inside your twig-template you can write:
61
        // <html><body> ... <img src="{{ logo_png }}" alt="logo"> ... </body></html>
62 10
        $imagesDir = $this->getTemplateImageDir();
63 10
        $newVars['logo_png'] 				= $imagesDir.'logo.png';
64 10
        $newVars['bottom_shadow_png']		= $imagesDir.'bottomshadow.png';
65 10
        $newVars['top_shadow_png']			= $imagesDir.'topshadow.png';
66 10
        $newVars['left_shadow_png']			= $imagesDir.'left-shadow.png';
67 10
        $newVars['right_shadow_png']		= $imagesDir.'right-shadow.png';
68 10
        $newVars['placeholder_png'] 		= $imagesDir.'placeholder.png';
69
70
        // define some colors to be reused in the following style-definitions
71 10
        $azGreen							= "green";
72 10
        $azBlue								= "blue";
73 10
        $blackColor							= "black";
74 10
        $lightGray 							= "#EEEEEE";
75 10
        $newVars["azGreen"] 				= $azGreen;
76 10
        $newVars["azBlue"] 					= $azBlue;
77 10
        $newVars["blackColor"]				= $blackColor;
78 10
        $newVars["lightGray"]				= $lightGray;
79 10
        $newVars["bodyBackgroundColor"]		= "#fdfbfa";
80 10
        $newVars["contentBackgroundColor"]  = "#f2f1f0";
81 10
        $fontFamily							= "Arial, Helvetica, sans-serif";
82 10
        $newVars["fontFamily"]				= $fontFamily;
83 10
        $newVars["emailWidth"]				= 640;// width for the whole email-body
84 10
        $newVars["shadowWidth"]				= 10; // width for the shadows left and right of the content
85 10
        $newVars["contentWidth"]			= 620;// width for the mail content
86 10
        $newVars["mediaQueryWidth"]			= 479;// width for the media-query for mobile devices
87 10
        $newVars["mobileEmailWidth"]		= 459;// width for the whole email-body for mobile devices
88 10
        $newVars["mobileContentWidth"]		= 439;// width for the mail content for mobile devices
89 10
        $newVars["footerBackgroundColor"]   = "#434343";
90
91
        // add html-styles for your html-emails
92
        // css does not work in html-emails, so all styles need to be
93
        // embedded directly into the html-elements
94 10
        $newVars["h2Style"]					= "style='padding:0; margin:0; font:bold 24px $fontFamily; color:$azBlue; text-decoration:none;'";
95 10
        $newVars["h3Style"]					= "style='margin:12px 0 5px 0; font:bold 18px $fontFamily; padding:0; color:$azGreen; text-decoration:none;'";
96 10
        $newVars["h4Style"]					= "style='padding:0; margin:0 0 20px 0; color:$blackColor; font-size:14px; text-decoration:none;'";
97 10
        $newVars["txtH1Style"]				= "////////////////////////////////////////////////////////////////////////////////";
98 10
        $newVars["txtH2Style"]				= "================================================================================";
99 10
        $newVars["txtH3Style"]				= "--------------------------------------------------------------------------------";
100 10
        $newVars["txtH4Style"]				= "''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''";
101 10
        $newVars["txtHR"]					= "________________________________________________________________________________";
102 10
        $newVars["smallGreyStyle"]			= "style='color: grey; font: $fontFamily 11px;'";
103 10
        $newVars["salutationStyle"]			= "style='color:$azBlue; font:bold 16px $fontFamily;'";
104 10
        $newVars["dateStyle"]				= "style='padding:0; margin:5px 0; color:$blackColor; font-weight:bold; font-size:12px;'";
105 10
        $newVars["smallerTextStyle"]		= "style='font: normal 13px/18px $fontFamily;'";
106
107 10
        return $newVars;
108
    }
109
110
    /**
111
     * Override this function for your template(s) if you use other "snippets" with embedded images.
112
     *
113
     * This function adds more complex elements to the array of variables that are passed
114
     * to the twig-renderer, just before sending the mail.
115
     *
116
     * In this implementation for example some reusable "snippets" are added to render
117
     * a nice shadow around content parts and add a "link to top" at the top of each part.
118
     *
119
     * As these "snippets" contain references to images that first had to be embedded into the
120
     * Message, these "snippets" are added after embedding/adding the attachments.
121
     *
122
     * This means, that here the variable "bottom_shadow_png" defined in AzineTemplateProvider.fillParamArrayFor()
123
     * does not contain the path to the image-file anymore but now contains the CID of the embedded image.
124
     *
125
     * @param  string     $template    the template id in standard-notation, without the ending ( .txt.twig) => "AcmeFooBundle:bar:default"
126
     * @param  array      $vars
127
     * @param  string     $emailLocale
128
     * @throws \Exception
129
     * @return array      of strings
130
     */
131 10
    protected function getSnippetArrayFor($template, array $vars, $emailLocale)
132
    {
133
        // this implementation uses the same snippets for all templates.
134
        // override this function with a more sophisticated logic
135
        // if you need different snippets for different templates.
136
137
        // the snippets added in this implementation depend on the
138
        // following images, so they must be present in the $vars-array
139
        if(
140 10
                !array_key_exists("bottom_shadow_png", $vars) ||
141 9
                !array_key_exists("top_shadow_png", $vars) ||
142 9
                !array_key_exists("left_shadow_png", $vars) ||
143 9
                !array_key_exists("right_shadow_png", $vars)
144 10
        ) {
145 1
            throw new \Exception("some required images are not yet added to the template-vars array.");
146
        }
147
148 9
        $snippets = array();
149
150
        // define some vars that are used several times
151 9
        $lightGray	= $vars["lightGray"];;
152 9
        $blackColor	= $vars["blackColor"];
153 9
        $upLinkTitle= $this->getTranslator($emailLocale)->trans("html.email.go.to.top.link.label", array(), 'messages', $emailLocale);
154 8
        $fontFamily	= $vars["fontFamily"];
155
156
        // create and add html-elements for easy reuse in the twig-templates
157 8
        $snippets["linkToTop"] 		= "<a href='#top' style='text-decoration:none;color:$blackColor' title='$upLinkTitle'>Λ</a>";
158 8
        $snippets["tableOpen"]		= "<table summary='box with shadows' class='emailWidth' width='".$vars["emailWidth"]."' border='0' align='center' cellpadding='0' cellspacing='0'  style='font: normal 14px/18px $fontFamily;'>";
159 8
        $snippets["topShadow"]		= $snippets["tableOpen"]."<tr><td class='emailWidth'  colspan='3' width='".$vars["emailWidth"]."'><img class='emailWidth' width='".$vars["emailWidth"]."' height='10' src='".$vars["top_shadow_png"]."' alt='' style='vertical-align: bottom;'/></td></tr>";
160 8
        $snippets["leftShadow"]		= "<tr><td width='10' style='border-right: 1px solid $lightGray; background-image: url(\"".$vars["left_shadow_png"]."\");'>&nbsp;</td>";
161 8
        $snippets["rightShadow"]	= "<td width='10' style='border-left: 1px solid $lightGray; background-image: url(\"".$vars["right_shadow_png"]."\");'>&nbsp;</td></tr>";
162 8
        $snippets["bottomShadow"]	= "	<tr><td colspan='3' class='emailWidth' width='".$vars["emailWidth"]."'><img src='".$vars["bottom_shadow_png"]."' class='emailWidth' width='".$vars["emailWidth"]."' height='10' alt='' style='vertical-align: top;'/></td></tr></table>";
163 8
        $snippets["linkToTopRow"]	= $snippets["leftShadow"]."<td width='610' bgcolor='white' style='text-align: right; padding: 5px 5px 0; border-top: 1px solid $lightGray;'>".$snippets["linkToTop"]."</td>".$snippets["rightShadow"];
164 8
        $snippets["cellSeparator"]	= "</td>".$snippets["rightShadow"].$snippets["bottomShadow"].$snippets["topShadow"].$snippets["linkToTopRow"].$snippets["leftShadow"]."<td bgcolor='white' width='580' align='left' valign='top' style='padding:10px 20px 20px 20px;'>";
165
166 8
        return $snippets;
167
    }
168
169
    /**
170
     * Override this function to define your own campaign-parameters
171
     * (non-PHPdoc)
172
     * @see Azine\EmailBundle\Services\TemplateProviderInterface::getCampaignParamsFor()
173
     */
174 7
    public function getCampaignParamsFor($templateId, array $params = null) {
175
        $campaignParams = array(
176 7
            $this->tracking_params_campaign_medium => "email",
177 7
            $this->tracking_params_campaign_name => date("y-m-d")
178 7
        );
179
180 7
        if ($templateId == self::NEWSLETTER_TEMPLATE) {
181 4
            $campaignParams[$this->tracking_params_campaign_source] = "newsletter";
182 7
        } else 	if ($templateId == self::NOTIFICATIONS_TEMPLATE) {
183 1
            $campaignParams[$this->tracking_params_campaign_source] = "mailnotify";
184 1
        }
185
186 7
        return $campaignParams;
187
    }
188
189
    /**
190
     * Override this function if you want to add extra headers to the messages sent.
191
     * (non-PHPdoc)
192
     * @see Azine\EmailBundle\Services.TemplateProviderInterface::addCustomHeaders()
193
     */
194 5
    public function addCustomHeaders($template, \Swift_Message $message, array $params)
195
    {
196
        //$headerSet = $message->getHeaders();
197
        //$headerSet->addTextHeader($name, $vale);
198 5
    }
199
200
    /**
201
     * (non-PHPdoc)
202
     * @see Azine\EmailBundle\Services.TemplateProviderInterface::saveWebViewFor()
203
     */
204 7
    public function saveWebViewFor($template)
205
    {
206 7
        if (array_search($template, $this->getTemplatesToStoreForWebView()) !== false ) {
207 4
            return true;
208
        }
209
210 4
        return false;
211
    }
212
213
    /**
214
     * Override this function to define which emails you want to make the web-view available and for which not.
215
     *
216
     * @return string[] of string => the template id in standard-notation, without the ending ( .txt.twig) => "AcmeFooBundle:bar:default"
217
     */
218 7
    protected function getTemplatesToStoreForWebView()
219
    {
220 7
        $include = array();
221 7
        $include[] = self::NEWSLETTER_TEMPLATE;
222
223 7
        return $include;
224
    }
225
226
    /**
227
     * Only override this method if you want to change the ID used in the twig-template for the web-view-link from 'azineEmailWebViewToken' to something else.
228
     * (non-PHPdoc)
229
     * @see Azine\EmailBundle\Services.TemplateProviderInterface::getWebViewTokenId()
230
     */
231 7
    public function getWebViewTokenId()
232
    {
233 7
        return self::EMAIL_WEB_VIEW_TOKEN;
234
    }
235
236
//////////////////////////////////////////////////////////////////////////
237
/* You probably don't need to change or override any of the stuff below */
238
//////////////////////////////////////////////////////////////////////////
239
240
    const CONTENT_ITEMS 		= 'contentItems';
241
    const EMAIL_WEB_VIEW_TOKEN 	= "azineEmailWebViewToken";
242
243
    /**
244
     * Full filesystem-path to the directory where you store your email-template images.
245
     * @var string
246
     */
247
    private $templateImageDir;
248
249
    /**
250
     * List of directories from which images are allowed to be embeded into emails
251
     * @var array of string
252
     */
253
    private $allowedImageFolders = array();
254
255
    /**
256
     * @var UrlGeneratorInterface
257
     */
258
    private $router;
259
260
    /**
261
     * @var Translator
262
     */
263
    private $translator;
264
265
    /**
266
     * Array to store all the arrays for the variables/parameters for all the different templates.
267
     * @var array of array
268
     */
269
    protected $paramArrays = array();
270
271
    /**
272
     * @var  string
273
     */
274
    protected $tracking_params_campaign_source;
275
276
    /**
277
     * @var  string
278
     */
279
    protected $tracking_params_campaign_medium;
280
281
    /**
282
     * @var  string
283
     */
284
    protected $tracking_params_campaign_content;
285
286
    /**
287
     * @var  string
288
     */
289
    protected $tracking_params_campaign_name;
290
291
    /**
292
     * @var  string
293
     */
294
    protected $tracking_params_campaign_term;
295
296
297
    /**
298
     * Array to store all the arrays for the code snippets for all the different temlpates.
299
     * @var unknown_type
300
     */
301
    protected $snippetArrays = array();
302
303 15
    public function __construct(UrlGeneratorInterface $router, Translator $translator, array $parameters)
304
    {
305 15
        $this->router = $router;
306 15
        $this->translator = $translator;
307 15
        $templateImageDir = realpath($parameters[AzineEmailExtension::TEMPLATE_IMAGE_DIR]);
308 15
        if ($this->templateImageDir !== false) {
309 15
            $this->templateImageDir = $templateImageDir."/";
310 15
        }
311
312 15
        foreach ($parameters[AzineEmailExtension::ALLOWED_IMAGES_FOLDERS] as $nextFolder) {
313 15
            $imageFolder = realpath($nextFolder);
314 15
            if ($imageFolder !== false) {
315 15
                $this->allowedImageFolders[md5($imageFolder)] = $imageFolder."/";
316 15
            }
317 15
        }
318 15
        $this->allowedImageFolders[md5($this->templateImageDir)] = $this->templateImageDir;
319 15
        $this->tracking_params_campaign_content = $parameters[AzineEmailExtension::TRACKING_PARAM_CAMPAIGN_CONTENT];
320 15
        $this->tracking_params_campaign_medium = $parameters[AzineEmailExtension::TRACKING_PARAM_CAMPAIGN_MEDIUM];
321 15
        $this->tracking_params_campaign_name = $parameters[AzineEmailExtension::TRACKING_PARAM_CAMPAIGN_NAME];
322 15
        $this->tracking_params_campaign_source = $parameters[AzineEmailExtension::TRACKING_PARAM_CAMPAIGN_SOURCE];
323 15
        $this->tracking_params_campaign_term = $parameters[AzineEmailExtension::TRACKING_PARAM_CAMPAIGN_TERM];
324 15
    }
325
326
    /**
327
     * (non-PHPdoc)
328
     * @see Azine\EmailBundle\Services.TemplateProviderInterface::getTemplateImageDir()
329
     */
330 10
    public function getTemplateImageDir()
331
    {
332 10
        return $this->templateImageDir;
333
    }
334
335
    /**
336
     * (non-PHPdoc)
337
     * @see Azine\EmailBundle\Services.TemplateProviderInterface::addTemplateVariablesFor()
338
     */
339 10
    public function addTemplateVariablesFor($template, array $contentVariables)
340
    {
341 10
        if (!array_key_exists($template, $this->paramArrays)) {
342 10
            $this->paramArrays[$template] = $this->getParamArrayFor($template);
343 10
        }
344
345
        // add vars for main template
346 10
        $contentVariables = array_merge($this->paramArrays[$template], $contentVariables);
347
348
        // add the template-variables to the contentItem-params-arrays
349 10 View Code Duplication
        if (array_key_exists(self::CONTENT_ITEMS, $contentVariables)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
350
351 5
            foreach ($contentVariables[self::CONTENT_ITEMS] as $key => $contentItem) {
352
                // get the key (=> template)
353 5
                reset($contentItem);
354 5
                $itemTemplate = key($contentItem);
355
356
                // get the params
357 5
                $itemParams = $contentItem[$itemTemplate];
358
359
                // add params for this template
360 5
                $contentItem[$itemTemplate] = $this->addTemplateVariablesFor($itemTemplate, $itemParams);
361
362
                // store back into the main array
363 5
                $contentVariables[self::CONTENT_ITEMS][$key] = $contentItem;
364 5
            }
365 5
        }
366
367 10
        return $contentVariables;
368
    }
369
370
    /**
371
     * (non-PHPdoc)
372
     * @see Azine\EmailBundle\Services.TemplateProviderInterface::addTemplateSnippetsWithImagesFor()
373
     */
374 10
    public function addTemplateSnippetsWithImagesFor($template, array $vars, $emailLocale, $forWebView = false)
375
    {
376 10
        $channel = $forWebView ? "webView" : "email";
377 10
        $templateKey = $channel.$template.$emailLocale;
378
379 10
        if (!array_key_exists($templateKey, $this->snippetArrays)) {
380 10
            $this->snippetArrays[$templateKey] = $this->getSnippetArrayFor($template, $vars, $emailLocale);
381 8
        }
382
383
        // add vars for main template
384 8
        $vars = array_merge($this->snippetArrays[$templateKey], $vars);
385
386
        // add the template-code-snippets to the contentItem-params-arrays
387 8 View Code Duplication
        if (array_key_exists(self::CONTENT_ITEMS, $vars)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
388
389 3
            foreach ($vars[self::CONTENT_ITEMS] as $key => $contentItem) {
390
                // get the key (=> template)
391 3
                reset($contentItem);
392 3
                $itemTemplate = key($contentItem);
393
394
                // get the params
395 3
                $itemParams = $contentItem[$itemTemplate];
396
397
                // add params for this template
398 3
                $contentItem[$itemTemplate] = $this->addTemplateSnippetsWithImagesFor($itemTemplate, $itemParams,  $emailLocale, $forWebView);
399
400
                // store back into the main array
401 3
                $vars[self::CONTENT_ITEMS][$key] = $contentItem;
402 3
            }
403 3
        }
404
405 8
        return $vars;
406
    }
407
408
    /**
409
     * @return UrlGeneratorInterface
410
     */
411 3
    protected function getRouter()
412
    {
413 3
        return $this->router;
414
    }
415
416
    /**
417
     * Only use the translator here when you already know in which language the user should get the email.
418
     * @param  string $emailLocale
419
     * @throws \Exception
420
     * @return Translator
421
     */
422 9
    protected function getTranslator($emailLocale)
423
    {
424 9
        if ($emailLocale == null) {
425 1
            throw new \Exception("Only use the translator here when you already know in which language the user should get the email.");
426
        }
427
428 8
        return $this->translator;
429
    }
430
431
    /**
432
     * Recursively replace all absolute image-file-paths with relative web-paths.
433
     * @param array $emailVars
434
     * @param string $locale
435
     * @return array
436
     */
437 3
    public function makeImagePathsWebRelative(array $emailVars, $locale)
438
    {
439 3
        foreach ($emailVars as $key => $value) {
440 3
            if (is_string($value) && is_file($value)) {
441
442
                // check if the file is in an allowed_images_folder
443 3
                $folderKey = $this->isFileAllowed($value);
444 3
                if ($folderKey !== false) {
445
446
                    // replace the fs-path with the web-path
447 3
                    $filename = substr($value, strrpos($value,"/")+1);
448 3
                    $newValue = $this->getRouter()->generate("azine_email_serve_template_image", array('folderKey' => $folderKey, 'filename' => $filename, '_locale' => $locale));
449 3
                    $emailVars[$key] = $newValue;
450 3
                }
451 3
            } elseif (is_array($value)) {
452
453 2
                $emailVars[$key] = $this->makeImagePathsWebRelative($value, $locale);
454 2
            }
455 3
        }
456
457 3
        return $emailVars;
458
    }
459
460
    /**
461
     * (non-PHPdoc)
462
     * @see Azine\EmailBundle\Services.TemplateProviderInterface::isFileAllowed()
463
     */
464 8
    public function isFileAllowed($filePath)
465
    {
466 8
        $filePath = realpath($filePath);
467 8
        foreach ($this->allowedImageFolders as $key => $nextFolder) {
468 8
            if (strpos($filePath, $nextFolder) === 0) {
469 8
                return $key;
470
            }
471 2
        }
472
473 2
        return false;
474
    }
475
476
    /**
477
     * (non-PHPdoc)
478
     * @see Azine\EmailBundle\Services.TemplateProviderInterface::getFolderFrom()
479
     */
480 1
    public function getFolderFrom($key)
481
    {
482 1
        if (array_key_exists($key, $this->allowedImageFolders)) {
483 1
            return $this->allowedImageFolders[$key];
484
        }
485
486 1
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the interface Azine\EmailBundle\Servic...nterface::getFolderFrom of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
487
    }
488
489
}
490