Issues (3627)

bundles/WebhookBundle/Helper/CampaignHelper.php (1 issue)

1
<?php
2
3
/*
4
 * @copyright   2014 Mautic Contributors. All rights reserved
5
 * @author      Mautic
6
 *
7
 * @link        http://mautic.org
8
 *
9
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
10
 */
11
12
namespace Mautic\WebhookBundle\Helper;
13
14
use Doctrine\Common\Collections\Collection;
15
use Joomla\Http\Http;
16
use Mautic\CoreBundle\Helper\AbstractFormFieldHelper;
17
use Mautic\LeadBundle\Entity\Lead;
18
use Mautic\LeadBundle\Helper\TokenHelper;
19
use Mautic\LeadBundle\Model\CompanyModel;
20
use Mautic\WebhookBundle\Event\WebhookRequestEvent;
21
use Mautic\WebhookBundle\WebhookEvents;
22
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
23
24
class CampaignHelper
25
{
26
    /**
27
     * @var Http
28
     */
29
    protected $connector;
30
31
    /**
32
     * @var CompanyModel
33
     */
34
    protected $companyModel;
35
36
    /**
37
     * Cached contact values in format [contact_id => [key1 => val1, key2 => val1]].
38
     *
39
     * @var array
40
     */
41
    private $contactsValues = [];
42
43
    /**
44
     * @var EventDispatcher
45
     */
46
    private $dispatcher;
47
48
    public function __construct(Http $connector, $companyModel, EventDispatcherInterface $dispatcher)
49
    {
50
        $this->connector    = $connector;
51
        $this->companyModel = $companyModel;
52
        $this->dispatcher   = $dispatcher;
53
    }
54
55
    /**
56
     * Prepares the neccessary data transformations and then makes the HTTP request.
57
     */
58
    public function fireWebhook(array $config, Lead $contact)
59
    {
60
        $payload = $this->getPayload($config, $contact);
61
        $headers = $this->getHeaders($config, $contact);
62
        $url     = rawurldecode(TokenHelper::findLeadTokens($config['url'], $this->getContactValues($contact), true));
63
64
        $webhookRequestEvent = new WebhookRequestEvent($contact, $url, $headers, $payload);
65
        $this->dispatcher->dispatch(WebhookEvents::WEBHOOK_ON_REQUEST, $webhookRequestEvent);
66
67
        $this->makeRequest(
68
            $webhookRequestEvent->getUrl(),
69
            $config['method'],
70
            $config['timeout'],
71
            $webhookRequestEvent->getHeaders(),
72
            $webhookRequestEvent->getPayload()
73
        );
74
    }
75
76
    /**
77
     * Gets the payload fields from the config and if there are tokens it translates them to contact values.
78
     *
79
     * @return array
80
     */
81
    private function getPayload(array $config, Lead $contact)
82
    {
83
        $payload = !empty($config['additional_data']['list']) ? $config['additional_data']['list'] : '';
84
        $payload = array_flip(AbstractFormFieldHelper::parseList($payload));
85
86
        return $this->getTokenValues($payload, $contact);
87
    }
88
89
    /**
90
     * Gets the payload fields from the config and if there are tokens it translates them to contact values.
91
     *
92
     * @return array
93
     */
94
    private function getHeaders(array $config, Lead $contact)
95
    {
96
        $headers = !empty($config['headers']['list']) ? $config['headers']['list'] : '';
97
        $headers = array_flip(AbstractFormFieldHelper::parseList($headers));
98
99
        return $this->getTokenValues($headers, $contact);
100
    }
101
102
    /**
103
     * @param string $url
104
     * @param string $method
105
     * @param int    $timeout
106
     *
107
     * @throws \InvalidArgumentException
108
     * @throws \OutOfRangeException
109
     */
110
    private function makeRequest($url, $method, $timeout, array $headers, array $payload)
111
    {
112
        switch ($method) {
113
            case 'get':
114
                $payload  = $url.(parse_url($url, PHP_URL_QUERY) ? '&' : '?').http_build_query($payload);
115
                $response = $this->connector->get($payload, $headers, $timeout);
116
                break;
117
            case 'post':
118
            case 'put':
119
            case 'patch':
120
                $headers = array_change_key_case($headers);
121
                if (array_key_exists('content-type', $headers) && 'application/json' == strtolower($headers['content-type'])) {
122
                    $payload                 = json_encode($payload);
123
                }
124
                $response = $this->connector->$method($url, $payload, $headers, $timeout);
125
                break;
126
            case 'delete':
127
                $response = $this->connector->delete($url, $headers, $timeout, $payload);
128
                break;
129
            default:
130
                throw new \InvalidArgumentException('HTTP method "'.$method.' is not supported."');
131
        }
132
133
        if (!in_array($response->code, [200, 201])) {
134
            throw new \OutOfRangeException('Campaign webhook response returned error code: '.$response->code);
135
        }
136
    }
137
138
    /**
139
     * Translates tokens to values.
140
     *
141
     * @return array
142
     */
143
    private function getTokenValues(array $rawTokens, Lead $contact)
144
    {
145
        $values        = [];
146
        $contactValues = $this->getContactValues($contact);
147
148
        foreach ($rawTokens as $key => $value) {
149
            $values[$key] = rawurldecode(TokenHelper::findLeadTokens($value, $contactValues, true));
0 ignored issues
show
It seems like Mautic\LeadBundle\Helper..., $contactValues, true) can also be of type array; however, parameter $string of rawurldecode() 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

149
            $values[$key] = rawurldecode(/** @scrutinizer ignore-type */ TokenHelper::findLeadTokens($value, $contactValues, true));
Loading history...
150
        }
151
152
        return $values;
153
    }
154
155
    /**
156
     * Gets array of contact values.
157
     *
158
     * @return array
159
     */
160
    private function getContactValues(Lead $contact)
161
    {
162
        if (empty($this->contactsValues[$contact->getId()])) {
163
            $this->contactsValues[$contact->getId()]              = $contact->getProfileFields();
164
            $this->contactsValues[$contact->getId()]['ipAddress'] = $this->ipAddressesToCsv($contact->getIpAddresses());
165
            $this->contactsValues[$contact->getId()]['companies'] = $this->companyModel->getRepository()->getCompaniesByLeadId($contact->getId());
166
        }
167
168
        return $this->contactsValues[$contact->getId()];
169
    }
170
171
    /**
172
     * @return string
173
     */
174
    private function ipAddressesToCsv(Collection $ipAddresses)
175
    {
176
        $addresses = [];
177
        foreach ($ipAddresses as $ipAddress) {
178
            $addresses[] = $ipAddress->getIpAddress();
179
        }
180
181
        return implode(',', $addresses);
182
    }
183
}
184