Passed
Push — master ( f0d0a7...1b0620 )
by Jan
10:32
created

placeholderPathToAssetPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
/**
3
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4
 *
5
 * Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as published
9
 * by the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
declare(strict_types=1);
22
23
/**
24
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
25
 *
26
 * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
27
 *
28
 * This program is free software; you can redistribute it and/or
29
 * modify it under the terms of the GNU General Public License
30
 * as published by the Free Software Foundation; either version 2
31
 * of the License, or (at your option) any later version.
32
 *
33
 * This program is distributed in the hope that it will be useful,
34
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36
 * GNU General Public License for more details.
37
 *
38
 * You should have received a copy of the GNU General Public License
39
 * along with this program; if not, write to the Free Software
40
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
41
 */
42
43
namespace App\Services\Attachments;
44
45
use App\Entity\Attachments\Attachment;
46
use InvalidArgumentException;
47
use Liip\ImagineBundle\Service\FilterService;
48
use RuntimeException;
49
use function strlen;
50
use Symfony\Component\Asset\Packages;
51
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
52
53
class AttachmentURLGenerator
54
{
55
    protected $assets;
56
    protected $public_path;
57
    protected $pathResolver;
58
    protected $urlGenerator;
59
    protected $attachmentHelper;
60
    protected $filterService;
61
62
    public function __construct(Packages $assets, AttachmentPathResolver $pathResolver,
63
                                UrlGeneratorInterface $urlGenerator, AttachmentManager $attachmentHelper,
64
                                FilterService $filterService)
65
    {
66
        $this->assets = $assets;
67
        $this->pathResolver = $pathResolver;
68
        $this->urlGenerator = $urlGenerator;
69
        $this->attachmentHelper = $attachmentHelper;
70
        $this->filterService = $filterService;
71
72
        //Determine a normalized path to the public folder (assets are relative to this folder)
73
        $this->public_path = $this->pathResolver->parameterToAbsolutePath('public');
74
    }
75
76
    /**
77
     * Converts the absolute file path to a version relative to the public folder, that can be passed to asset
78
     * Asset Component functions.
79
     *
80
     * @param string      $absolute_path the absolute path that should be converted
81
     * @param string|null $public_path   The public path to which the relative pathes should be created.
82
     *                                   The path must NOT have a trailing slash!
83
     *                                   If this is set to null, the global public/ folder is used.
84
     *
85
     * @return string|null The relative version of the string. Null if the absolute path was not a child folder
86
     *                     of public path
87
     */
88
    public function absolutePathToAssetPath(string $absolute_path, ?string $public_path = null): ?string
89
    {
90
        if (null === $public_path) {
91
            $public_path = $this->public_path;
92
        }
93
94
95
96
        //Our absolute path must begin with public path or we can not use it for asset pathes.
97
        if (0 !== strpos($absolute_path, $public_path)) {
98
            return null;
99
        }
100
101
        //Return the part relative after public path.
102
        return substr($absolute_path, strlen($public_path) + 1);
103
    }
104
105
    /**
106
     * Converts a placeholder path to a path to a image path.
107
     *
108
     * @param string      $placeholder_path the placeholder path that should be converted
109
     *
110
     * @return string|null
111
     */
112
    public function placeholderPathToAssetPath(string $placeholder_path): ?string
113
    {
114
        $absolute_path = $this->pathResolver->placeholderToRealPath($placeholder_path);
115
        return $this->absolutePathToAssetPath($absolute_path);
0 ignored issues
show
Bug introduced by
It seems like $absolute_path can also be of type null; however, parameter $absolute_path of App\Services\Attachments...solutePathToAssetPath() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

115
        return $this->absolutePathToAssetPath(/** @scrutinizer ignore-type */ $absolute_path);
Loading history...
116
    }
117
118
    /**
119
     * Returns a URL under which the attachment file can be viewed.
120
     */
121
    public function getViewURL(Attachment $attachment): string
122
    {
123
        $absolute_path = $this->attachmentHelper->toAbsoluteFilePath($attachment);
124
        if (null === $absolute_path) {
125
            throw new RuntimeException('The given attachment is external or has no valid file, so no URL can get generated for it!
126
                Use Attachment::getURL() to get the external URL!');
127
        }
128
129
        $asset_path = $this->absolutePathToAssetPath($absolute_path);
130
        //If path is not relative to public path or marked as secure, serve it via controller
131
        if (null === $asset_path || $attachment->isSecure()) {
132
            return $this->urlGenerator->generate('attachment_view', ['id' => $attachment->getID()]);
133
        }
134
135
        //Otherwise we can serve the relative path via Asset component
136
        return $this->assets->getUrl($asset_path);
137
    }
138
139
    /**
140
     * Returns a URL to an thumbnail of the attachment file.
141
     */
142
    public function getThumbnailURL(Attachment $attachment, string $filter_name = 'thumbnail_sm'): string
143
    {
144
        if (! $attachment->isPicture()) {
145
            throw new InvalidArgumentException('Thumbnail creation only works for picture attachments!');
146
        }
147
148
        if ($attachment->isExternal() && ! empty($attachment->getURL())) {
149
            return $attachment->getURL();
150
        }
151
152
        $absolute_path = $this->attachmentHelper->toAbsoluteFilePath($attachment);
153
        if (null === $absolute_path) {
154
            throw new RuntimeException('The given attachment is external or has no valid file, so no URL can get generated for it!');
155
        }
156
157
        $asset_path = $this->absolutePathToAssetPath($absolute_path);
158
        //If path is not relative to public path or marked as secure, serve it via controller
159
        if (null === $asset_path || $attachment->isSecure()) {
160
            return $this->urlGenerator->generate('attachment_view', ['id' => $attachment->getID()]);
161
        }
162
163
        //For builtin ressources it is not useful to create a thumbnail
164
        //because the footprints images are small and highly optimized already.
165
        if (('thumbnail_md' === $filter_name && $attachment->isBuiltIn())
166
            //GD can not work with SVG, so serve it directly...
167
            || $attachment->getExtension() === 'svg') {
168
            return $this->assets->getUrl($asset_path);
169
        }
170
171
        //Otherwise we can serve the relative path via Asset component
172
        return $this->filterService->getUrlOfFilteredImage($asset_path, $filter_name);
173
    }
174
175
    /**
176
     * Returns a download link to the file associated with the attachment.
177
     */
178
    public function getDownloadURL(Attachment $attachment): string
179
    {
180
        //Redirect always to download controller, which sets the correct headers for downloading:
181
        return $this->urlGenerator->generate('attachment_download', ['id' => $attachment->getID()]);
182
    }
183
}
184