| Total Complexity | 46 | 
| Total Lines | 280 | 
| Duplicated Lines | 0 % | 
| Changes | 2 | ||
| Bugs | 0 | Features | 0 | 
Complex classes like EmbedShortcodeProvider often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use EmbedShortcodeProvider, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 29 | class EmbedShortcodeProvider implements ShortcodeHandler  | 
            ||
| 30 | { | 
            ||
| 31 | |||
| 32 | /**  | 
            ||
| 33 | * Gets the list of shortcodes provided by this handler  | 
            ||
| 34 | *  | 
            ||
| 35 | * @return mixed  | 
            ||
| 36 | */  | 
            ||
| 37 | public static function get_shortcodes()  | 
            ||
| 38 |     { | 
            ||
| 39 | return ['embed'];  | 
            ||
| 40 | }  | 
            ||
| 41 | |||
| 42 | /**  | 
            ||
| 43 | * Embed shortcode parser from Oembed. This is a temporary workaround.  | 
            ||
| 44 | * Oembed class has been replaced with the Embed external service.  | 
            ||
| 45 | *  | 
            ||
| 46 | * @param array $arguments  | 
            ||
| 47 | * @param string $content  | 
            ||
| 48 | * @param ShortcodeParser $parser  | 
            ||
| 49 | * @param string $shortcode  | 
            ||
| 50 | * @param array $extra  | 
            ||
| 51 | *  | 
            ||
| 52 | * @return string  | 
            ||
| 53 | */  | 
            ||
| 54 | public static function handle_shortcode($arguments, $content, $parser, $shortcode, $extra = [])  | 
            ||
| 55 |     { | 
            ||
| 56 | // Get service URL  | 
            ||
| 57 |         if (!empty($content)) { | 
            ||
| 58 | $serviceURL = $content;  | 
            ||
| 59 |         } elseif (!empty($arguments['url'])) { | 
            ||
| 60 | $serviceURL = $arguments['url'];  | 
            ||
| 61 |         } else { | 
            ||
| 62 | return '';  | 
            ||
| 63 | }  | 
            ||
| 64 | |||
| 65 | // Try to use cached result  | 
            ||
| 66 | $cache = static::getCache();  | 
            ||
| 67 | $key = static::deriveCacheKey($serviceURL);  | 
            ||
| 68 |         try { | 
            ||
| 69 |             if ($cache->has($key)) { | 
            ||
| 70 | return $cache->get($key);  | 
            ||
| 71 | }  | 
            ||
| 72 |         } catch (InvalidArgumentException $e) { | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 73 | }  | 
            ||
| 74 | |||
| 75 | // See https://github.com/oscarotero/Embed#example-with-all-options for service arguments  | 
            ||
| 76 | $serviceArguments = [];  | 
            ||
| 77 |         if (!empty($arguments['width'])) { | 
            ||
| 78 | $serviceArguments['min_image_width'] = $arguments['width'];  | 
            ||
| 79 | }  | 
            ||
| 80 |         if (!empty($arguments['height'])) { | 
            ||
| 81 | $serviceArguments['min_image_height'] = $arguments['height'];  | 
            ||
| 82 | }  | 
            ||
| 83 | |||
| 84 | /** @var EmbedResource $embed */  | 
            ||
| 85 | $embed = Injector::inst()->create(Embeddable::class, $serviceURL);  | 
            ||
| 86 |         if (!empty($serviceArguments)) { | 
            ||
| 87 | $embed->setOptions(array_merge($serviceArguments, (array) $embed->getOptions()));  | 
            ||
| 88 | }  | 
            ||
| 89 | |||
| 90 | // Allow resolver to be mocked  | 
            ||
| 91 | $dispatcher = null;  | 
            ||
| 92 |         if (isset($extra['resolver'])) { | 
            ||
| 93 | $dispatcher = Injector::inst()->create(  | 
            ||
| 94 | $extra['resolver']['class'],  | 
            ||
| 95 | $serviceURL,  | 
            ||
| 96 | $extra['resolver']['config']  | 
            ||
| 97 | );  | 
            ||
| 98 |         } elseif (Injector::inst()->has(DispatcherInterface::class)) { | 
            ||
| 99 | $dispatcher = Injector::inst()->get(DispatcherInterface::class);  | 
            ||
| 100 | }  | 
            ||
| 101 | |||
| 102 |         if ($dispatcher) { | 
            ||
| 103 | $embed->setDispatcher($dispatcher);  | 
            ||
| 104 | }  | 
            ||
| 105 | |||
| 106 | // Process embed  | 
            ||
| 107 |         try { | 
            ||
| 108 | $embed = $embed->getEmbed();  | 
            ||
| 109 |         } catch (InvalidUrlException $e) { | 
            ||
| 110 | $message = (Director::isDev())  | 
            ||
| 111 | ? $e->getMessage()  | 
            ||
| 112 | : _t(__CLASS__ . '.INVALID_URL', 'There was a problem loading the media.');  | 
            ||
| 113 | |||
| 114 | $attr = [  | 
            ||
| 115 | 'class' => 'ss-media-exception embed'  | 
            ||
| 116 | ];  | 
            ||
| 117 | |||
| 118 | $result = HTML::createTag(  | 
            ||
| 119 | 'div',  | 
            ||
| 120 | $attr,  | 
            ||
| 121 |                 HTML::createTag('p', [], $message) | 
            ||
| 122 | );  | 
            ||
| 123 | return $result;  | 
            ||
| 124 | }  | 
            ||
| 125 | |||
| 126 | // Convert embed object into HTML  | 
            ||
| 127 |         if ($embed && $embed instanceof Adapter) { | 
            ||
| 128 | $result = static::embedForTemplate($embed, $arguments);  | 
            ||
| 129 | }  | 
            ||
| 130 | // Fallback to link to service  | 
            ||
| 131 |         if (!$result) { | 
            ||
| 132 | $result = static::linkEmbed($arguments, $serviceURL, $serviceURL);  | 
            ||
| 133 | }  | 
            ||
| 134 | // Cache result  | 
            ||
| 135 |         if ($result) { | 
            ||
| 136 |             try { | 
            ||
| 137 | $cache->set($key, $result);  | 
            ||
| 138 |             } catch (InvalidArgumentException $e) { | 
            ||
| 139 | }  | 
            ||
| 140 | }  | 
            ||
| 141 | return $result;  | 
            ||
| 142 | }  | 
            ||
| 143 | |||
| 144 | /**  | 
            ||
| 145 | * @param Adapter $embed  | 
            ||
| 146 | * @param array $arguments Additional shortcode params  | 
            ||
| 147 | * @return string  | 
            ||
| 148 | */  | 
            ||
| 149 | public static function embedForTemplate($embed, $arguments)  | 
            ||
| 150 |     { | 
            ||
| 151 |         switch ($embed->getType()) { | 
            ||
| 152 | case 'video':  | 
            ||
| 153 | case 'rich':  | 
            ||
| 154 | // Attempt to inherit width (but leave height auto)  | 
            ||
| 155 |                 if (empty($arguments['width']) && $embed->getWidth()) { | 
            ||
| 156 | $arguments['width'] = $embed->getWidth();  | 
            ||
| 157 | }  | 
            ||
| 158 | return static::videoEmbed($arguments, $embed->getCode());  | 
            ||
| 159 | case 'link':  | 
            ||
| 160 | return static::linkEmbed($arguments, $embed->getUrl(), $embed->getTitle());  | 
            ||
| 161 | case 'photo':  | 
            ||
| 162 | return static::photoEmbed($arguments, $embed->getUrl());  | 
            ||
| 163 | default:  | 
            ||
| 164 | return null;  | 
            ||
| 165 | }  | 
            ||
| 166 | }  | 
            ||
| 167 | |||
| 168 | /**  | 
            ||
| 169 | * Build video embed tag  | 
            ||
| 170 | *  | 
            ||
| 171 | * @param array $arguments  | 
            ||
| 172 | * @param string $content Raw HTML content  | 
            ||
| 173 | * @return string  | 
            ||
| 174 | */  | 
            ||
| 175 | protected static function videoEmbed($arguments, $content)  | 
            ||
| 176 |     { | 
            ||
| 177 | // Ensure outer div has given width (but leave height auto)  | 
            ||
| 178 |         if (!empty($arguments['width'])) { | 
            ||
| 179 | $arguments['style'] = 'width: ' . intval($arguments['width']) . 'px;';  | 
            ||
| 180 | }  | 
            ||
| 181 | |||
| 182 | // override iframe dimension attributes provided by webservice with ones specified in shortcode arguments  | 
            ||
| 183 |         foreach (['width', 'height'] as $attr) { | 
            ||
| 184 |             if (!($value = $arguments[$attr] ?? false)) { | 
            ||
| 185 | continue;  | 
            ||
| 186 | }  | 
            ||
| 187 |             foreach (['"', "'"] as $quote) { | 
            ||
| 188 | $rx = "/(<iframe .*?)$attr=$quote([0-9]+)$quote([^>]+>)/";  | 
            ||
| 189 |                 $content = preg_replace($rx, "$1{$attr}={$quote}{$value}{$quote}$3", $content); | 
            ||
| 190 | }  | 
            ||
| 191 | }  | 
            ||
| 192 | |||
| 193 | $data = [  | 
            ||
| 194 | 'Arguments' => $arguments,  | 
            ||
| 195 | 'Attributes' => static::buildAttributeListFromArguments($arguments, ['width', 'height', 'url', 'caption']),  | 
            ||
| 196 |             'Content' => DBField::create_field('HTMLFragment', $content) | 
            ||
| 197 | ];  | 
            ||
| 198 | |||
| 199 | return ArrayData::create($data)->renderWith(self::class . '_video')->forTemplate();  | 
            ||
| 200 | }  | 
            ||
| 201 | |||
| 202 | /**  | 
            ||
| 203 | * Build <a> embed tag  | 
            ||
| 204 | *  | 
            ||
| 205 | * @param array $arguments  | 
            ||
| 206 | * @param string $href  | 
            ||
| 207 | * @param string $title Default title  | 
            ||
| 208 | * @return string  | 
            ||
| 209 | */  | 
            ||
| 210 | protected static function linkEmbed($arguments, $href, $title)  | 
            ||
| 211 |     { | 
            ||
| 212 | $data = [  | 
            ||
| 213 | 'Arguments' => $arguments,  | 
            ||
| 214 | 'Attributes' => static::buildAttributeListFromArguments($arguments, ['width', 'height', 'url', 'caption']),  | 
            ||
| 215 | 'Href' => $href,  | 
            ||
| 216 | 'Title' => !empty($arguments['caption']) ? ($arguments['caption']) : $title  | 
            ||
| 217 | ];  | 
            ||
| 218 | |||
| 219 | return ArrayData::create($data)->renderWith(self::class . '_link')->forTemplate();  | 
            ||
| 220 | }  | 
            ||
| 221 | |||
| 222 | /**  | 
            ||
| 223 | * Build img embed tag  | 
            ||
| 224 | *  | 
            ||
| 225 | * @param array $arguments  | 
            ||
| 226 | * @param string $src  | 
            ||
| 227 | * @return string  | 
            ||
| 228 | */  | 
            ||
| 229 | protected static function photoEmbed($arguments, $src)  | 
            ||
| 230 |     { | 
            ||
| 231 | $data = [  | 
            ||
| 232 | 'Arguments' => $arguments,  | 
            ||
| 233 | 'Attributes' => static::buildAttributeListFromArguments($arguments, ['url']),  | 
            ||
| 234 | 'Src' => $src  | 
            ||
| 235 | ];  | 
            ||
| 236 | |||
| 237 | return ArrayData::create($data)->renderWith(self::class . '_photo')->forTemplate();  | 
            ||
| 238 | }  | 
            ||
| 239 | |||
| 240 | /**  | 
            ||
| 241 | * Build a list of HTML attributes from embed arguments - used to preserve backward compatibility  | 
            ||
| 242 | *  | 
            ||
| 243 |      * @deprecated 4.5.0 Use {$Arguments.name} directly in shortcode templates to access argument values | 
            ||
| 244 | * @param array $arguments List of embed arguments  | 
            ||
| 245 | * @param array $exclude List of attribute names to exclude from the resulting list  | 
            ||
| 246 | * @return ArrayList  | 
            ||
| 247 | */  | 
            ||
| 248 | private static function buildAttributeListFromArguments(array $arguments, array $exclude = []): ArrayList  | 
            ||
| 263 | }  | 
            ||
| 264 | |||
| 265 | /**  | 
            ||
| 266 | * @param ShortcodeParser $parser  | 
            ||
| 267 | * @param string $content  | 
            ||
| 268 | */  | 
            ||
| 269 | public static function flushCachedShortcodes(ShortcodeParser $parser, string $content): void  | 
            ||
| 289 | }  | 
            ||
| 290 | }  | 
            ||
| 291 | }  | 
            ||
| 292 | |||
| 293 | /**  | 
            ||
| 294 | * @return CacheInterface  | 
            ||
| 295 | */  | 
            ||
| 296 | private static function getCache(): CacheInterface  | 
            ||
| 299 | }  | 
            ||
| 300 | |||
| 301 | /**  | 
            ||
| 302 | * @param string $url  | 
            ||
| 303 | * @return string  | 
            ||
| 304 | */  | 
            ||
| 305 | private static function deriveCacheKey(string $url): string  | 
            ||
| 311 |