Completed
Pull Request — master (#356)
by Christian
09:45
created

TwitterEmbedTweetBlockService::configureEditForm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
rs 9.0254
c 0
b 0
f 0
cc 1
nc 1
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\SeoBundle\Block\Social;
15
16
use Guzzle\Http\Client;
17
use Guzzle\Http\Exception\CurlException;
18
use Sonata\BlockBundle\Block\BlockContextInterface;
19
use Sonata\BlockBundle\Block\Service\EditableBlockService;
20
use Sonata\BlockBundle\Form\Mapper\FormMapper;
21
use Sonata\BlockBundle\Meta\Metadata;
22
use Sonata\BlockBundle\Meta\MetadataInterface;
23
use Sonata\BlockBundle\Model\BlockInterface;
24
use Sonata\Form\Type\ImmutableArrayType;
25
use Sonata\Form\Validator\ErrorElement;
26
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
27
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
28
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
29
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
30
use Symfony\Component\Form\Extension\Core\Type\TextType;
31
use Symfony\Component\HttpFoundation\Response;
32
use Symfony\Component\OptionsResolver\OptionsResolver;
33
34
/**
35
 * This block service allows to embed a tweet by requesting the Twitter API.
36
 *
37
 * @see https://dev.twitter.com/docs/api/1/get/statuses/oembed
38
 *
39
 * @author Hugo Briand <[email protected]>
40
 */
41
class TwitterEmbedTweetBlockService extends BaseTwitterButtonBlockService implements EditableBlockService
42
{
43
    public const TWITTER_OEMBED_URI = 'https://api.twitter.com/1/statuses/oembed.json';
44
    private const TWEET_URL_PATTERN = '%^(https://)(www.)?(twitter.com/)(.*)(/status)(es)?(/)([0-9]*)$%i';
45
    private const TWEET_ID_PATTERN = '%^([0-9]*)$%';
46
47
    public function execute(BlockContextInterface $blockContext, Response $response = null): Response
48
    {
49
        $tweet = $blockContext->getSetting('tweet');
50
51
        if (($uriMatched = preg_match(self::TWEET_URL_PATTERN, $tweet))
52
            || preg_match(self::TWEET_ID_PATTERN, $tweet)) {
53
            // We matched an URL or an ID, we'll need to ask the API
54
            if (false === class_exists('Guzzle\Http\Client')) {
55
                throw new \RuntimeException('The guzzle http client library is required to call the Twitter API. Make sure to add guzzle/guzzle to your composer.json.');
56
            }
57
58
            // TODO cache API result
59
            $client = new Client();
60
            $client->setConfig(['curl.options' => [CURLOPT_CONNECTTIMEOUT_MS => 1000]]);
61
62
            try {
63
                $request = $client->get($this->buildUri($uriMatched, $blockContext->getSettings()));
0 ignored issues
show
Documentation introduced by
$uriMatched is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
64
                $apiTweet = json_decode($request->send()->getBody(true), true);
65
66
                $tweet = $apiTweet['html'];
67
            } catch (CurlException $e) {
68
                // log error
69
            }
70
        }
71
72
        return $this->renderResponse($blockContext->getTemplate(), [
73
            'block' => $blockContext->getBlock(),
74
            'tweet' => $tweet,
75
        ], $response);
76
    }
77
78
    public function configureSettings(OptionsResolver $resolver): void
79
    {
80
        $resolver->setDefaults([
81
            'template' => '@SonataSeo/Block/block_twitter_embed.html.twig',
82
            'tweet' => '',
83
            'maxwidth' => null,
84
            'hide_media' => false,
85
            'hide_thread' => false,
86
            'omit_script' => false,
87
            'align' => 'none',
88
            'related' => null,
89
            'lang' => null,
90
        ]);
91
    }
92
93
    public function configureCreateForm(FormMapper $form, BlockInterface $block): void
94
    {
95
        $this->configureEditForm($form, $block);
96
    }
97
98
    public function configureEditForm(FormMapper $form, BlockInterface $block): void
99
    {
100
        $form->add('settings', ImmutableArrayType::class, [
101
            'keys' => [
102
                ['tweet', TextareaType::class, [
103
                    'required' => true,
104
                    'label' => 'form.label_tweet',
105
                    'sonata_help' => 'form.help_tweet',
106
                ]],
107
                ['maxwidth', IntegerType::class, [
108
                    'required' => false,
109
                    'label' => 'form.label_maxwidth',
110
                    'sonata_help' => 'form.help_maxwidth',
111
                ]],
112
                ['hide_media', CheckboxType::class, [
113
                    'required' => false,
114
                    'label' => 'form.label_hide_media',
115
                    'sonata_help' => 'form.help_hide_media',
116
                ]],
117
                ['hide_thread', CheckboxType::class, [
118
                    'required' => false,
119
                    'label' => 'form.label_hide_thread',
120
                    'sonata_help' => 'form.help_hide_thread',
121
                ]],
122
                ['omit_script', CheckboxType::class, [
123
                    'required' => false,
124
                    'label' => 'form.label_omit_script',
125
                    'sonata_help' => 'form.help_omit_script',
126
                ]],
127
                ['align', ChoiceType::class, [
128
                    'required' => false,
129
                    'choices' => [
130
                        'left' => 'form.label_align_left',
131
                        'right' => 'form.label_align_right',
132
                        'center' => 'form.label_align_center',
133
                        'none' => 'form.label_align_none',
134
                    ],
135
                    'label' => 'form.label_align',
136
                ]],
137
                ['related', TextType::class, [
138
                    'required' => false,
139
                    'label' => 'form.label_related',
140
                    'sonata_help' => 'form.help_related',
141
                ]],
142
                ['lang', ChoiceType::class, [
143
                    'required' => true,
144
                    'choices' => $this->languageList,
145
                    'label' => 'form.label_lang',
146
                ]],
147
            ],
148
            'translation_domain' => 'SonataSeoBundle',
149
        ]);
150
    }
151
152
    public function validate(ErrorElement $errorElement, BlockInterface $block): void
153
    {
154
    }
155
156
    public function getMetadata(): MetadataInterface
157
    {
158
        return new Metadata('sonata.seo.block.twitter.embed', null, null, 'SonataSeoBundle', [
159
            'class' => 'fa fa-twitter',
160
        ]);
161
    }
162
163
    /**
164
     * Returns supported API parameters from settings.
165
     *
166
     * @return array
167
     */
168
    protected function getSupportedApiParams()
169
    {
170
        return [
171
            'maxwidth',
172
            'hide_media',
173
            'hide_thread',
174
            'omit_script',
175
            'align',
176
            'related',
177
            'lang',
178
            'url',
179
            'id',
180
        ];
181
    }
182
183
    /**
184
     * Builds the API query URI based on $settings.
185
     *
186
     * @param bool $uriMatched
187
     *
188
     * @return string
189
     */
190
    protected function buildUri($uriMatched, array $settings)
191
    {
192
        $apiParams = $settings;
193
        $supportedParams = $this->getSupportedApiParams();
194
195
        if ($uriMatched) {
196
            // We matched the uri
197
            $apiParams['url'] = $settings['tweet'];
198
        } else {
199
            $apiParams['id'] = $settings['tweet'];
200
        }
201
202
        unset($apiParams['tweet']);
203
204
        $parameters = [];
205
        foreach ($apiParams as $key => $value) {
206
            if ($value && \in_array($key, $supportedParams, true)) {
207
                $parameters[] = $key.'='.$value;
208
            }
209
        }
210
211
        return sprintf('%s?%s', self::TWITTER_OEMBED_URI, implode('&', $parameters));
212
    }
213
}
214