Passed
Push — develop ( f7bbc0...50eb60 )
by Andrew
04:58
created

Recipe::init()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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