Completed
Push — 6.7 ( 89be23...66cf4e )
by
unknown
11:17
created

BinaryContent::parseImageId()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 1
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the BinaryContent controller class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\REST\Server\Controller;
10
11
use eZ\Publish\Core\REST\Common\Exceptions;
12
use eZ\Publish\Core\REST\Server\Controller as RestController;
13
use eZ\Publish\Core\REST\Server\Values\CachedValue;
14
use eZ\Publish\SPI\Variation\VariationHandler;
15
use eZ\Publish\API\Repository\Exceptions\InvalidVariationException;
16
17
/**
18
 * Binary content controller.
19
 */
20
class BinaryContent extends RestController
21
{
22
    /**
23
     * @var \eZ\Publish\SPI\Variation\VariationHandler
24
     */
25
    protected $imageVariationHandler;
26
27
    /**
28
     * Construct controller.
29
     *
30
     * @param \eZ\Publish\SPI\Variation\VariationHandler $imageVariationHandler
31
     */
32
    public function __construct(VariationHandler $imageVariationHandler)
33
    {
34
        $this->imageVariationHandler = $imageVariationHandler;
35
    }
36
37
    /**
38
     * Returns data about the image variation $variationIdentifier of image field $fieldId.
39
     * Will generate the alias if it hasn't been generated yet.
40
     *
41
     * @param mixed  $imageId A custom ID that identifies the image field.
42
     *                        Until v6.9, the format is {contentId}-{fieldId}.
43
     *                        since v6.9, the format is {contentId}-{fieldId}-{versionNumber}.
44
     *                        If the version number isn't specified, the default one is used.
45
     * @param string $variationIdentifier
46
     *
47
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException
48
     *
49
     * @return \eZ\Publish\SPI\Variation\Values\Variation
50
     */
51
    public function getImageVariation($imageId, $variationIdentifier)
52
    {
53
        list($contentId, $fieldId, $versionNumber) = $this->parseImageId($imageId);
54
        $content = $this->repository->getContentService()->loadContent($contentId, null, $versionNumber);
55
56
        $fieldFound = false;
57
        /** @var $field \eZ\Publish\API\Repository\Values\Content\Field */
58
        foreach ($content->getFields() as $field) {
59
            if ($field->id == $fieldId) {
60
                $fieldFound = true;
61
                break;
62
            }
63
        }
64
65
        if (!$fieldFound) {
66
            throw new Exceptions\NotFoundException("No image field with ID $fieldId could be found");
67
        }
68
69
        // check the field's value
70
        if ($field->value->uri === null) {
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
The variable $field seems to be defined by a foreach iteration on line 58. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
71
            throw new Exceptions\NotFoundException("Image file {$field->value->id} doesn't exist");
0 ignored issues
show
Documentation introduced by
The property $value is declared protected in eZ\Publish\API\Repository\Values\Content\Field. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
72
        }
73
74
        try {
75
            $variation = $this->imageVariationHandler->getVariation($field, $content->getVersionInfo(), $variationIdentifier);
76
77
            if ($content->contentInfo->mainLocationId === null || $versionNumber !== $content->contentInfo->currentVersionNo) {
78
                return $variation;
79
            }
80
81
            return new CachedValue(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \eZ\Publish\C...Info->mainLocationId)); (eZ\Publish\Core\REST\Server\Values\CachedValue) is incompatible with the return type documented by eZ\Publish\Core\REST\Ser...tent::getImageVariation of type eZ\Publish\SPI\Variation\Values\Variation.

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...
82
                $variation,
83
                array('locationId' => $content->contentInfo->mainLocationId)
84
            );
85
        } catch (InvalidVariationException $e) {
86
            throw new Exceptions\NotFoundException("Invalid image variation $variationIdentifier");
87
        }
88
    }
89
90
    /**
91
     * Parses an imageId string into contentId, fieldId and versionNumber.
92
     *
93
     * @param string $imageId Either {contentId}-{fieldId} or {contentId}-{fieldId}-{versionNumber}
94
     *
95
     * @return array An array with 3 keys: contentId, fieldId and versionNumber.
96
     *               If the versionNumber wasn't set, it is returned as null.
97
     *
98
     * @throws \eZ\Publish\Core\REST\Common\Exceptions\NotFoundException If the imageId format is invalid
99
     */
100
    private function parseImageId($imageId)
101
    {
102
        $idArray = explode('-', $imageId);
103
104
        if (count($idArray) == 2) {
105
            return array_merge($idArray, [null]);
106
        } elseif (count($idArray) == 3) {
107
            return $idArray;
108
        }
109
110
        throw new Exceptions\NotFoundException("Invalid image ID {$imageId}");
111
    }
112
}
113