Completed
Push — master ( 9745cb...81e988 )
by Paul
06:43
created

FileHandler::prepareMedia()   C

Complexity

Conditions 7
Paths 16

Size

Total Lines 32
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 32
rs 6.7272
c 1
b 1
f 0
cc 7
eloc 24
nc 16
nop 1
1
<?php
2
3
namespace Victoire\Bundle\MediaBundle\Helper\File;
4
5
use Gaufrette\Adapter\Local;
6
use Gaufrette\Filesystem;
7
use Gedmo\Sluggable\Util\Urlizer;
8
use Symfony\Component\HttpFoundation\File\File;
9
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
10
use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser;
11
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface;
12
use Symfony\Component\HttpFoundation\File\UploadedFile;
13
use Victoire\Bundle\MediaBundle\Entity\Media;
14
use Victoire\Bundle\MediaBundle\Form\File\FileType;
15
use Victoire\Bundle\MediaBundle\Helper\Media\AbstractMediaHandler;
16
17
/**
18
 * FileHandler.
19
 */
20
class FileHandler extends AbstractMediaHandler
21
{
22
    /**
23
     * @var string
24
     */
25
    const TYPE = 'file';
26
27
    /**
28
     * @var Filesystem
29
     */
30
    public $fileSystem = null;
31
32
    /**
33
     * @var MimeTypeGuesserInterface
34
     */
35
    public $mimeTypeGuesser = null;
36
    public $urlizer;
37
38
    /**
39
     * constructor.
40
     */
41
    public function __construct()
42
    {
43
        $this->fileSystem = new Filesystem(new \Gaufrette\Adapter\Local('uploads/media/', true));
44
        //we use a specific symfony mimetypeguesser because de default (FileinfoMimeTypeGuesser) is unable to recognize MS documents
45
        $this->mimeTypeGuesser = new FileBinaryMimeTypeGuesser();
46
        $this->urlizer = new Urlizer();
47
    }
48
49
    /**
50
     * @return string
51
     */
52
    public function getName()
53
    {
54
        return 'File Handler';
55
    }
56
57
    /**
58
     * @return string
59
     */
60
    public function getType()
61
    {
62
        return self::TYPE;
63
    }
64
65
    /**
66
     * @return FileType
67
     */
68
    public function getFormType()
69
    {
70
        return FileType::class;
71
    }
72
73
    /**
74
     * @param mixed $object
75
     *
76
     * @return bool
77
     */
78
    public function canHandle($object)
79
    {
80
        if ($object instanceof File || ($object instanceof Media && (is_file($object->getContent()) || $object->getLocation() == 'local'))) {
81
            return true;
82
        }
83
84
        return false;
85
    }
86
87
    /**
88
     * @param Media $media
89
     *
90
     * @return FileHelper
91
     */
92
    public function getFormHelper(Media $media)
93
    {
94
        return new FileHelper($media);
95
    }
96
97
    /**
98
     * @param Media $media
99
     *
100
     * @throws \RuntimeException when the file does not exist
101
     */
102
    public function prepareMedia(Media $media)
103
    {
104
        if (null === $media->getUuid()) {
105
            $uuid = uniqid();
106
            $media->setUuid($uuid);
107
        }
108
        $content = $media->getContent();
109
        if (empty($content)) {
110
            return;
111
        }
112
        if (!$content instanceof File) {
113
            if (!is_file($content)) {
114
                throw new \RuntimeException('Invalid file');
115
            }
116
            $file = new File($content);
117
            $media->setContent($file);
118
        }
119
        if ($content instanceof UploadedFile) {
120
            $pathInfo = pathinfo($content->getClientOriginalName());
121
            $media->setOriginalFilename($this->urlizer->urlize($pathInfo['filename']).'.'.$pathInfo['extension']);
122
            $name = $media->getName();
123
            if (empty($name)) {
124
                $media->setName($media->getOriginalFilename());
125
            }
126
        }
127
        $media->setFileSize(filesize($media->getContent()));
128
        $contentType = $this->mimeTypeGuesser->guess($media->getContent()->getPathname());
129
        $media->setContentType($contentType);
130
        $relativePath = sprintf('/%s.%s', $media->getUuid(), ExtensionGuesser::getInstance()->guess($media->getContentType()));
131
        $media->setUrl('/uploads/media'.$relativePath);
132
        $media->setLocation('local');
133
    }
134
135
    /**
136
     * @param Media $media
137
     */
138
    public function saveMedia(Media $media)
139
    {
140
        if (!$media->getContent() instanceof File) {
141
            return;
142
        }
143
144
        $originalFile = $this->getOriginalFile($media);
145
        $originalFile->setContent(file_get_contents($media->getContent()->getRealPath()));
146
    }
147
148
    /**
149
     * @param Media $media
150
     *
151
     * @return \Gaufrette\File
152
     */
153
    public function getOriginalFile(Media $media)
154
    {
155
        $relativePath = sprintf('/%s.%s', $media->getUuid(), ExtensionGuesser::getInstance()->guess($media->getContentType()));
156
157
        return $this->fileSystem->get($relativePath, true);
158
    }
159
160
    /**
161
     * @param Media $media
162
     */
163
    public function removeMedia(Media $media)
164
    {
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170
    public function updateMedia(Media $media)
171
    {
172
        $this->saveMedia($media);
173
    }
174
175
    /**
176
     * @param File $data
177
     *
178
     * @return Media
179
     */
180
    public function createNew($data)
181
    {
182
        if ($data instanceof File) {
183
            /* @var $data File */
184
185
            $media = new Media();
186
            if (method_exists($media, 'getClientOriginalName')) {
187
                $media->setName($data->getClientOriginalName());
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\HttpFoundation\File\File as the method getClientOriginalName() does only exist in the following sub-classes of Symfony\Component\HttpFoundation\File\File: Symfony\Component\HttpFoundation\File\UploadedFile. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
188
            } else {
189
                $media->setName($data->getFilename());
190
            }
191
            $media->setContent($data);
192
193
            return $media;
194
        }
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200
    public function getShowTemplate(Media $media)
201
    {
202
        return 'VictoireMediaBundle:Media\File:show.html.twig';
203
    }
204
205
    /**
206
     * @return array
207
     */
208
    public function getAddFolderActions()
209
    {
210
        return [
211
                self::TYPE => [
212
                        'type' => self::TYPE,
213
                        'name' => 'media.file.add', ],
214
        ];
215
    }
216
}
217