Passed
Push — develop ( e8f94c...f7bbc0 )
by Andrew
04:36
created

Recipe::getVideoUploadedDate()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 6
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 11
rs 10
1
<?php
2
/**
3
 * Recipe plugin for Craft CMS 3.x
4
 *
5
 * A comprehensive recipe FieldType for Craft CMS that includes metric/imperial
6
 * conversion, portion calculation, and JSON-LD microdata support
7
 *
8
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
9
 * @copyright Copyright (c) 2017 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
10
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
11
12
namespace nystudio107\recipe\models;
13
14
use nystudio107\recipe\helpers\Json;
15
use nystudio107\recipe\helpers\PluginTemplate;
16
use nystudio107\seomatic\Seomatic;
0 ignored issues
show
Bug introduced by
The type nystudio107\seomatic\Seomatic was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use nystudio107\seomatic\models\MetaJsonLd;
0 ignored issues
show
Bug introduced by
The type nystudio107\seomatic\models\MetaJsonLd was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
19
use Craft;
20
use craft\base\Model;
21
use craft\helpers\StringHelper;
22
use craft\helpers\Template;
23
use craft\validators\ArrayValidator;
24
25
use Twig\Markup;
26
27
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
28
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
29
 * @package   Recipe
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
30
 * @since     1.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
31
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
32
class Recipe extends Model
33
{
34
    // Constants
35
    // =========================================================================
36
37
    const SEOMATIC_PLUGIN_HANDLE = 'seomatic';
38
    const MAIN_ENTITY_KEY = 'mainEntityOfPage';
39
40
    const US_RDA = [
41
        'calories' => 2000,
42
        'carbohydrateContent' => 275,
43
        'cholesterolContent' => 300,
44
        'fatContent' => 78,
45
        'fiberContent' => 28,
46
        'proteinContent' => 50,
47
        'saturatedFatContent' => 20,
48
        'sodiumContent' => 2300,
49
        'sugarContent' => 50,
50
    ];
51
52
    // Mapping to convert any of the incorrect plural values
53
    const NORMALIZE_PLURALS = [
54
        'tsps' => 'tsp',
55
        'tbsps' => 'tbsp',
56
        'flozs' => 'floz',
57
        'cups' => 'cups',
58
        'ozs' => 'oz',
59
        'lbs' => 'lb',
60
        'mls' => 'ml',
61
        'ls' => 'l',
62
        'mgs' => 'mg',
63
        'gs' => 'g',
64
        'kg' => 'kg',
65
    ];
66
67
    // Public Properties
68
    // =========================================================================
69
70
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
71
     * @var string
72
     */
73
    public $name;
74
75
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
76
     * @var string
77
     */
78
    public $description;
79
80
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
81
     * @var string
82
     */
83
    public $recipeCategory;
84
85
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
86
     * @var string
87
     */
88
    public $recipeCuisine;
89
90
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
91
     * @var string
92
     */
93
    public $skill = 'intermediate';
94
95
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
96
     * @var int
97
     */
98
    public $serves = 1;
99
100
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
101
     * @var string
102
     */
103
    public $servesUnit = '';
104
105
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
106
     * @var array
107
     */
108
    public $ingredients = [];
109
110
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
111
     * @var array
112
     */
113
    public $directions = [];
114
115
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
116
     * @var array
117
     */
118
    public $equipment = [];
119
120
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
121
     * @var int
122
     */
123
    public $imageId = 0;
124
125
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
126
     * @var int
127
     */
128
    public $videoId = 0;
129
130
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
131
     * @var int
132
     */
133
    public $prepTime;
134
135
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
136
     * @var int
137
     */
138
    public $cookTime;
139
140
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
141
     * @var int
142
     */
143
    public $totalTime;
144
145
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
146
     * @var array
147
     */
148
    public $ratings = [];
149
150
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
151
     * @var string
152
     */
153
    public $servingSize;
154
155
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
156
     * @var int
157
     */
158
    public $calories;
159
160
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
161
     * @var int
162
     */
163
    public $carbohydrateContent;
164
165
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
166
     * @var int
167
     */
168
    public $cholesterolContent;
169
170
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
171
     * @var int
172
     */
173
    public $fatContent;
174
175
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
176
     * @var int
177
     */
178
    public $fiberContent;
179
180
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
181
     * @var int
182
     */
183
    public $proteinContent;
184
185
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
186
     * @var int
187
     */
188
    public $saturatedFatContent;
189
190
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
191
     * @var int
192
     */
193
    public $sodiumContent;
194
195
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
196
     * @var int
197
     */
198
    public $sugarContent;
199
200
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
201
     * @var int
202
     */
203
    public $transFatContent;
204
205
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
206
     * @var int
207
     */
208
    public $unsaturatedFatContent;
209
210
    // Public Methods
211
    // =========================================================================
212
213
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
214
     * @inheritdoc
215
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
216
    public function init()
217
    {
218
        parent::init();
219
        // Fix any of the incorrect plural values
220
        if (!empty($this->ingredients)) {
221
            foreach ($this->ingredients as &$row) {
222
                if (!empty($row['units']) && !empty(self::NORMALIZE_PLURALS[$row['units']])) {
223
                    $row['units'] = self::NORMALIZE_PLURALS[$row['units']];
224
                }
225
            }
226
            unset($row);
227
        }
228
    }
229
230
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
231
     * @inheritdoc
232
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
233
    public function rules()
234
    {
235
        return [
236
            ['name', 'string'],
237
            ['name', 'default', 'value' => ''],
238
            ['description', 'string'],
239
            ['recipeCategory', 'string'],
240
            ['recipeCuisine', 'string'],
241
            ['skill', 'string'],
242
            ['serves', 'integer'],
243
            ['imageId', 'integer'],
244
            ['videoId', 'integer'],
245
            ['prepTime', 'integer'],
246
            ['cookTime', 'integer'],
247
            ['totalTime', 'integer'],
248
            ['servingSize', 'string'],
249
            ['calories', 'integer'],
250
            ['carbohydrateContent', 'integer'],
251
            ['cholesterolContent', 'integer'],
252
            ['fatContent', 'integer'],
253
            ['fiberContent', 'integer'],
254
            ['proteinContent', 'integer'],
255
            ['saturatedFatContent', 'integer'],
256
            ['sodiumContent', 'integer'],
257
            ['sugarContent', 'integer'],
258
            ['transFatContent', 'integer'],
259
            ['unsaturatedFatContent', 'integer'],
260
            [
261
                [
262
                    'ingredients',
263
                    'directions',
264
                    'equipment',
265
                ],
266
                ArrayValidator::class,
267
            ],
268
269
        ];
270
    }
271
272
    /**
273
     * Return the JSON-LD Structured Data for this recipe
274
     *
275
     * @return array
276
     */
277
    public function getRecipeJSONLD(): array
278
    {
279
        $recipeJSONLD = [
280
            'context' => 'http://schema.org',
281
            'type' => 'Recipe',
282
            'name' => $this->name,
283
            'image' => $this->getImageUrl(),
284
            'description' => $this->description,
285
            'recipeCategory' => $this->recipeCategory,
286
            'recipeCuisine' => $this->recipeCuisine,
287
            'recipeYield' => $this->getServes(),
288
            'recipeIngredient' => $this->getIngredients('imperial', 0, false),
289
            'recipeInstructions' => $this->getDirections(false),
290
            'tool' => $this->getEquipment(false),
291
        ];
292
        $recipeJSONLD = array_filter($recipeJSONLD);
293
294
        $videoUrl = $this->getVideoUrl();
295
        if (!empty($videoUrl)) {
296
            $video = [
297
                'type' => 'VideoObject',
298
                'name' => $this->name,
299
                'description' => $this->description,
300
                'contentUrl' => $videoUrl,
301
                'thumbnailUrl' => $this->getImageUrl(),
302
                'uploadDate' => $this->getVideoUploadedDate()
303
            ];
304
            $video = array_filter($video);
305
            $recipeJSONLD['video'] = $video;
306
        }
307
308
        $nutrition = [
309
            'type' => 'NutritionInformation',
310
            'servingSize' => $this->servingSize,
311
            'calories' => $this->calories,
312
            'carbohydrateContent' => $this->carbohydrateContent,
313
            'cholesterolContent' => $this->cholesterolContent,
314
            'fatContent' => $this->fatContent,
315
            'fiberContent' => $this->fiberContent,
316
            'proteinContent' => $this->proteinContent,
317
            'saturatedFatContent' => $this->saturatedFatContent,
318
            'sodiumContent' => $this->sodiumContent,
319
            'sugarContent' => $this->sugarContent,
320
            'transFatContent' => $this->transFatContent,
321
            'unsaturatedFatContent' => $this->unsaturatedFatContent,
322
        ];
323
        $nutrition = array_filter($nutrition);
324
        $recipeJSONLD['nutrition'] = $nutrition;
325
        if (count($recipeJSONLD['nutrition']) === 1) {
326
            unset($recipeJSONLD['nutrition']);
327
        }
328
        $aggregateRating = $this->getAggregateRating();
329
        if ($aggregateRating) {
330
            $aggregateRatings = [
331
                'type' => 'AggregateRating',
332
                'ratingCount' => $this->getRatingsCount(),
333
                'bestRating' => '5',
334
                'worstRating' => '1',
335
                'ratingValue' => $aggregateRating,
336
            ];
337
            $aggregateRatings = array_filter($aggregateRatings);
338
            $recipeJSONLD['aggregateRating'] = $aggregateRatings;
339
340
            $reviews = [];
341
            foreach ($this->ratings as $rating) {
342
                $review = [
343
                    'type' => 'Review',
344
                    'author' => $rating['author'],
345
                    'name' => $this->name . ' ' . Craft::t('recipe', 'Review'),
346
                    'description' => $rating['review'],
347
                    'reviewRating' => [
348
                        'type' => 'Rating',
349
                        'bestRating' => '5',
350
                        'worstRating' => '1',
351
                        'ratingValue' => $rating['rating'],
352
                    ],
353
                ];
354
                $reviews[] = $review;
355
            }
356
            $reviews = array_filter($reviews);
357
            $recipeJSONLD['review'] = $reviews;
358
        }
359
360
        if ($this->prepTime) {
361
            $recipeJSONLD['prepTime'] = 'PT' . $this->prepTime . 'M';
362
        }
363
        if ($this->cookTime) {
364
            $recipeJSONLD['cookTime'] = 'PT' . $this->cookTime . 'M';
365
        }
366
        if ($this->totalTime) {
367
            $recipeJSONLD['totalTime'] = 'PT' . $this->totalTime . 'M';
368
        }
369
370
        return $recipeJSONLD;
371
    }
372
373
    /**
374
     * Create the SEOmatic MetaJsonLd object for this recipe
375
     *
376
     * @param bool $add
0 ignored issues
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
Coding Style introduced by
Doc comment for parameter $add does not match actual variable name $key
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
377
     * @param null $key
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $key is correct as it would always require null to be passed?
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Doc comment for parameter $key does not match actual variable name $add
Loading history...
378
     * @return null|MetaJsonLd
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
379
     */
380
    public function createRecipeMetaJsonLd($key = null, bool $add = true)
381
    {
382
        $result = null;
383
        if (Craft::$app->getPlugins()->getPlugin(self::SEOMATIC_PLUGIN_HANDLE)) {
384
            $seomatic = Seomatic::getInstance();
385
            if ($seomatic !== null) {
386
                $recipeJson = $this->getRecipeJSONLD();
387
                // If we're adding the MetaJsonLd to the container, and no key is provided, give it a random key
388
                if ($add && $key === null) {
389
                    try {
390
                        $key = StringHelper::UUID();
391
                    } catch (\Exception $e) {
392
                        // That's okay
393
                    }
394
                }
395
                if ($key !== null) {
396
                    $recipeJson['key'] = $key;
397
                }
398
                // If the key is `mainEntityOfPage` add in the URL
399
                if ($key === self::MAIN_ENTITY_KEY) {
400
                    $mainEntity = Seomatic::$plugin->jsonLd->get(self::MAIN_ENTITY_KEY);
401
                    if ($mainEntity) {
402
                        $recipeJson[self::MAIN_ENTITY_KEY] = $mainEntity[self::MAIN_ENTITY_KEY];
403
                    }
404
                }
405
406
                $result = Seomatic::$plugin->jsonLd->create(
407
                    $recipeJson,
408
                    $add
409
                );
410
            }
411
        }
412
413
        return $result;
414
    }
415
416
    /**
417
     * Render the JSON-LD Structured Data for this recipe
418
     *
419
     * @param bool $raw
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
420
     *
421
     * @return string|\Twig_Markup
422
     */
423
    public function renderRecipeJSONLD($raw = true)
424
    {
425
        return $this->renderJsonLd($this->getRecipeJSONLD(), $raw);
426
    }
427
428
    /**
429
     * Get the URL to the recipe's image
430
     *
431
     * @param null $transform
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Documentation Bug introduced by
Are you sure the doc-type for parameter $transform is correct as it would always require null to be passed?
Loading history...
432
     *
433
     * @return null|string
434
     */
435
    public function getImageUrl($transform = null)
436
    {
437
        $result = '';
438
        if (isset($this->imageId) && $this->imageId) {
439
            $image = Craft::$app->getAssets()->getAssetById($this->imageId[0]);
440
            if ($image) {
441
                $result = $image->getUrl($transform);
442
            }
443
        }
444
445
        return $result;
446
    }
447
448
    /**
449
     * Get the URL to the recipe's video
450
     *
451
     * @return null|string
452
     */
453
    public function getVideoUrl()
454
    {
455
        $result = '';
456
        if (isset($this->videoId) && $this->videoId) {
457
            $video = Craft::$app->getAssets()->getAssetById($this->videoId[0]);
458
            if ($video) {
459
                $result = $video->getUrl();
460
            }
461
        }
462
463
        return $result;
464
    }
465
466
    /**
467
     * Get the URL to the recipe's uploaded date
468
     *
469
     * @return null|string
470
     */
471
    public function getVideoUploadedDate()
472
    {
473
        $result = '';
474
        if (isset($this->videoId) && $this->videoId) {
475
            $video = Craft::$app->getAssets()->getAssetById($this->videoId[0]);
476
            if ($video) {
477
                $result = $video->dateCreated->format('c');
478
            }
479
        }
480
481
        return $result;
482
    }
483
484
    /**
485
     * Render the Nutrition Facts template
486
     *
487
     * @param array $rda
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
488
     * @return Markup
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
489
     */
490
    public function renderNutritionFacts(array $rda = self::US_RDA): Markup {
0 ignored issues
show
Coding Style introduced by
Opening brace should be on a new line
Loading history...
491
        return PluginTemplate::renderPluginTemplate(
492
            'recipe-nutrition-facts',
493
            [
494
                'value' => $this,
495
                'rda' => $rda,
496
            ]
497
        );
498
    }
499
500
    /**
501
     * Get all of the ingredients for this recipe
502
     *
503
     * @param string $outputUnits
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
504
     * @param int    $serving
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
505
     * @param bool   $raw
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
506
     *
507
     * @return array
508
     */
509
    public function getIngredients($outputUnits = 'imperial', $serving = 0, $raw = true): array
510
    {
511
        $result = [];
512
513
        if (!empty($this->ingredients)) {
514
            foreach ($this->ingredients as $row) {
515
                $convertedUnits = '';
516
                $ingredient = '';
517
                if ($row['quantity']) {
518
                    // Multiply the quantity by how many servings we want
519
                    $multiplier = 1;
520
                    if ($serving > 0) {
521
                        $multiplier = $serving / $this->serves;
522
                    }
523
                    $quantity = $row['quantity'] * $multiplier;
524
                    $originalQuantity = $quantity;
525
526
                    // Do the imperial->metric units conversion
527
                    if ($outputUnits === 'imperial') {
528
                        switch ($row['units']) {
529
                            case 'ml':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
530
                                $convertedUnits = 'tsp';
531
                                $quantity *= 0.2;
532
                                break;
533
                            case 'l':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
534
                                $convertedUnits = 'cups';
535
                                $quantity *= 4.2;
536
                                break;
537
                            case 'mg':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
538
                                $convertedUnits = 'oz';
539
                                $quantity *= 0.000035274;
540
                                break;
541
                            case 'g':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
542
                                $convertedUnits = 'oz';
543
                                $quantity *= 0.035274;
544
                                break;
545
                            case 'kg':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
546
                                $convertedUnits = 'lb';
547
                                $quantity *= 2.2046226218;
548
                                break;
549
                        }
550
                    }
551
                    // Do the metric->imperial units conversion
552
                    if ($outputUnits === 'metric') {
553
                        switch ($row['units']) {
554
                            case 'tsp':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
555
                                $convertedUnits = 'ml';
556
                                $quantity *= 4.929;
557
                                break;
558
                            case 'tbsp':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
559
                                $convertedUnits = 'ml';
560
                                $quantity *= 14.787;
561
                                break;
562
                            case 'floz':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
563
                                $convertedUnits = 'ml';
564
                                $quantity *= 29.574;
565
                                break;
566
                            case 'cups':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
567
                                $convertedUnits = 'l';
568
                                $quantity *= 0.236588;
569
                                break;
570
                            case 'oz':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
571
                                $convertedUnits = 'g';
572
                                $quantity *= 28.3495;
573
                                break;
574
                            case 'lb':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
575
                                $convertedUnits = 'kg';
576
                                $quantity *= 0.45359237;
577
                                break;
578
                        }
579
580
                        $quantity = round($quantity, 1);
581
                    }
582
583
                    // Convert units to nice fractions
584
                    $quantity = $this->convertToFractions($quantity);
585
586
                    $ingredient .= $quantity;
587
588
                    if ($row['units']) {
589
                        $units = $row['units'];
590
                        if ($convertedUnits) {
591
                            $units = $convertedUnits;
592
                        }
593
                        if ($originalQuantity <= 1) {
594
                            $units = rtrim($units);
595
                            $units = rtrim($units, 's');
596
                        }
597
                        $ingredient .= ' ' . $units;
598
                    }
599
                }
600
                if ($row['ingredient']) {
601
                    $ingredient .= ' ' . $row['ingredient'];
602
                }
603
                if ($raw) {
604
                    $ingredient = Template::raw($ingredient);
605
                }
606
                $result[] = $ingredient;
607
            }
608
        }
609
610
        return $result;
611
    }
612
613
    /**
614
     * Convert decimal numbers into fractions
615
     *
616
     * @param $quantity
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
617
     *
618
     * @return string
619
     */
620
    private function convertToFractions($quantity)
0 ignored issues
show
Coding Style introduced by
Private method name "Recipe::convertToFractions" must be prefixed with an underscore
Loading history...
621
    {
622
        $whole = floor($quantity);
623
        // Round the mantissa so we can do a floating point comparison without
624
        // weirdness, per: https://www.php.net/manual/en/language.types.float.php#113703
625
        $fraction = round($quantity - $whole, 3);
626
        switch ($fraction) {
627
            case 0:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
628
                $fraction = '';
629
                break;
630
            case 0.25:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
631
                $fraction = ' &frac14;';
632
                break;
633
            case 0.33:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
634
                $fraction = ' &frac13;';
635
                break;
636
            case 0.66:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
637
                $fraction = ' &frac23;';
638
                break;
639
            case 0.165:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
640
                $fraction = ' &frac16;';
641
                break;
642
            case 0.5:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
643
                $fraction = ' &frac12;';
644
                break;
645
            case 0.75:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
646
                $fraction = ' &frac34;';
647
                break;
648
            case 0.125:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
649
                $fraction = ' &#x215B;';
650
                break;
651
            case 0.375:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
652
                $fraction = ' &#x215C;';
653
                break;
654
            case 0.625:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
655
                $fraction = ' &#x215D;';
656
                break;
657
            case 0.875:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
658
                $fraction = ' &#x215E;';
659
                break;
660
            default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
661
                $precision = 1;
662
                $pnum = round($fraction, $precision);
663
                $denominator = 10 ** $precision;
664
                $numerator = $pnum * $denominator;
665
                $fraction = ' <sup>'
666
                    .$numerator
667
                    . '</sup>&frasl;<sub>'
668
                    .$denominator
669
                    . '</sub>';
670
                break;
671
        }
672
        if ($whole == 0) {
673
            $whole = '';
674
        }
675
676
        return $whole.$fraction;
677
    }
678
679
    /**
680
     * Get all of the directions for this recipe
681
     *
682
     * @param bool $raw
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
683
     *
684
     * @return array
685
     */
686
    public function getDirections($raw = true)
687
    {
688
        $result = [];
689
        if (!empty($this->directions)) {
690
            foreach ($this->directions as $row) {
691
                $direction = $row['direction'];
692
                if ($raw) {
693
                    $direction = Template::raw($direction);
694
                }
695
                $result[] = $direction;
696
            }
697
        }
698
699
        return $result;
700
    }
701
702
    /**
703
     * Get all of the equipment for this recipe
704
     *
705
     * @param bool $raw
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
706
     *
707
     * @return array
708
     */
709
    public function getEquipment($raw = true)
710
    {
711
        $result = [];
712
        if (!empty($this->equipment)) {
713
            foreach ($this->equipment as $row) {
714
                $equipment = $row['equipment'];
715
                if ($raw) {
716
                    $equipment = Template::raw(equipment);
0 ignored issues
show
Bug introduced by
The constant nystudio107\recipe\models\equipment was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
717
                }
718
                $result[] = $equipment;
719
            }
720
        }
721
722
        return $result;
723
    }
724
725
    /**
726
     * Get the aggregate rating from all of the ratings
727
     *
728
     * @return float|int|string
729
     */
730
    public function getAggregateRating()
731
    {
732
        $result = 0;
733
        $total = 0;
734
        if (isset($this->ratings) && !empty($this->ratings)) {
735
            foreach ($this->ratings as $row) {
736
                $result += $row['rating'];
737
                $total++;
738
            }
739
            $result /= $total;
740
        } else {
741
            $result = '';
742
        }
743
744
        return $result;
745
    }
746
747
    /**
748
     * Get the total number of ratings
749
     *
750
     * @return int
751
     */
752
    public function getRatingsCount(): int
753
    {
754
        return count($this->ratings);
755
    }
756
757
    /**
758
     * Returns concatenated serves with its unit
759
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
760
    public function getServes(): string
761
    {
762
        if(!empty($this->servesUnit)) {
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if(...) {\n"
Loading history...
763
            return $this->serves . ' ' . $this->servesUnit;
764
        }
765
766
        return $this->serves;
767
    }
768
769
    // Private Methods
770
    // =========================================================================
771
772
    /**
773
     * Renders a JSON-LD representation of the schema
774
     *
775
     * @param      $json
0 ignored issues
show
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 1 spaces but found 6
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
776
     * @param bool $raw
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
777
     *
778
     * @return string|\Twig_Markup
779
     */
780
    private function renderJsonLd($json, $raw = true)
0 ignored issues
show
Coding Style introduced by
Private method name "Recipe::renderJsonLd" must be prefixed with an underscore
Loading history...
781
    {
782
        $linebreak = '';
783
784
        // If `devMode` is enabled, make the JSON-LD human-readable
785
        if (Craft::$app->getConfig()->getGeneral()->devMode) {
786
            $linebreak = PHP_EOL;
787
        }
788
789
        // Render the resulting JSON-LD
790
        $result = '<script type="application/ld+json">'
791
            .$linebreak
792
            .Json::encode($json)
793
            .$linebreak
794
            .'</script>';
795
796
        if ($raw === true) {
797
            $result = Template::raw($result);
798
        }
799
800
        return $result;
801
    }
802
}
803