/
ImageShortcodeProvider.php
182 lines (161 loc) · 5.99 KB
/
ImageShortcodeProvider.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<?php
namespace SilverStripe\Assets\Shortcodes;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Assets\File;
use SilverStripe\Assets\Image;
use SilverStripe\Assets\Storage\AssetStore;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Flushable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\View\HTML;
use SilverStripe\View\Parsers\ShortcodeHandler;
use SilverStripe\View\Parsers\ShortcodeParser;
/**
* Class ImageShortcodeProvider
*
* @package SilverStripe\Forms\HtmlEditor
*/
class ImageShortcodeProvider extends FileShortcodeProvider implements ShortcodeHandler, Flushable
{
/**
* Gets the list of shortcodes provided by this handler
*
* @return mixed
*/
public static function get_shortcodes()
{
return ['image'];
}
/**
* Replace"[image id=n]" shortcode with an image reference.
* Permission checks will be enforced by the file routing itself.
*
* @param array $args Arguments passed to the parser
* @param string $content Raw shortcode
* @param ShortcodeParser $parser Parser
* @param string $shortcode Name of shortcode used to register this handler
* @param array $extra Extra arguments
* @return string Result of the handled shortcode
*/
public static function handle_shortcode($args, $content, $parser, $shortcode, $extra = [])
{
$allowSessionGrant = static::config()->allow_session_grant;
$cache = static::getCache();
$cacheKey = static::getCacheKey($args);
$item = $cache->get($cacheKey);
if ($item) {
// Initiate a protected asset grant if necessary
if (!empty($item['filename']) && $allowSessionGrant) {
Injector::inst()->get(AssetStore::class)->grant($item['filename'], $item['hash']);
}
return $item['markup'];
}
// Find appropriate record, with fallback for error handlers
$fileFound = true;
$record = static::find_shortcode_record($args, $errorCode);
if ($errorCode) {
$fileFound = false;
$record = static::find_error_record($errorCode);
}
if (!$record) {
return null; // There were no suitable matches at all.
}
// Check if a resize is required
$src = $record->getURL($allowSessionGrant);
if ($record instanceof Image) {
$width = isset($args['width']) ? (int) $args['width'] : null;
$height = isset($args['height']) ? (int) $args['height'] : null;
$hasCustomDimensions = ($width && $height);
if ($hasCustomDimensions && (($width != $record->getWidth()) || ($height != $record->getHeight()))) {
$resized = $record->ResizedImage($width, $height);
// Make sure that the resized image actually returns an image
if ($resized) {
$src = $resized->getURL($allowSessionGrant);
}
}
}
// Build the HTML tag
$attrs = array_merge(
// Set overrideable defaults ('alt' must be present regardless of contents)
['src' => '', 'alt' => ''],
// Use all other shortcode arguments
$args,
// But enforce some values
['id' => '', 'src' => $src]
);
// If file was not found then use the Title value from static::find_error_record() for the alt attr
if (!$fileFound) {
$attrs['alt'] = $record->Title;
}
// Clean out any empty attributes (aside from alt)
$attrs = array_filter($attrs, function ($k, $v) {
return strlen(trim($v)) || $k === 'alt';
}, ARRAY_FILTER_USE_BOTH);
$markup = HTML::createTag('img', $attrs);
// cache it for future reference
if ($fileFound) {
$cache->set($cacheKey, [
'markup' => $markup,
'filename' => $record instanceof File ? $record->getFilename() : null,
'hash' => $record instanceof File ? $record->getHash() : null,
]);
}
return $markup;
}
/**
* Regenerates "[image id=n]" shortcode with new src attribute prior to being edited within the CMS.
*
* @param array $args Arguments passed to the parser
* @param string $content Raw shortcode
* @param ShortcodeParser $parser Parser
* @param string $shortcode Name of shortcode used to register this handler
* @param array $extra Extra arguments
* @return string Result of the handled shortcode
*/
public static function regenerate_shortcode($args, $content, $parser, $shortcode, $extra = [])
{
// Check if there is a suitable record
$record = static::find_shortcode_record($args);
if ($record) {
$args['src'] = $record->getURL();
}
// Rebuild shortcode
$parts = [];
foreach ($args as $name => $value) {
$htmlValue = Convert::raw2att($value ?: $name);
$parts[] = sprintf('%s="%s"', $name, $htmlValue);
}
return sprintf("[%s %s]", $shortcode, implode(' ', $parts));
}
/**
* Helper method to regenerate all shortcode links.
*
* @param string $value HTML value
* @return string value with links resampled
*/
public static function regenerate_html_links($value)
{
// Create a shortcode generator which only regenerates links
$regenerator = ShortcodeParser::get('regenerator');
return $regenerator->parse($value);
}
/**
* Gets the cache used by this provider
*
* @return CacheInterface
*/
public static function getCache()
{
/** @var CacheInterface $cache */
return Injector::inst()->get(CacheInterface::class . '.ImageShortcodeProvider');
}
/**
* @inheritdoc
*/
protected static function find_error_record($errorCode)
{
return Image::create([
'Title' => _t(__CLASS__ . '.IMAGENOTFOUND', 'Image not found'),
]);
}
}