isUserHasConnection()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 9
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 16
rs 9.9666
1
<?php
2
/**
3
 * @author Tharanga Kothalawala <[email protected]>
4
 * @date 27-01-2019
5
 */
6
7
namespace TSK\SSO\Storage;
8
9
use TSK\SSO\AppUser\AppUser;
10
use TSK\SSO\Storage\Exception\DataCannotBeStoredException;
11
use TSK\SSO\ThirdParty\CommonAccessToken;
12
use TSK\SSO\ThirdParty\ThirdPartyUser;
13
use MongoDB\BSON\ObjectID;
14
use MongoDB\Driver\BulkWrite;
15
use MongoDB\Driver\Exception\Exception;
16
use MongoDB\Driver\Exception\InvalidArgumentException;
17
use MongoDB\Driver\Manager as MongoManager;
18
use MongoDB\Driver\Query;
19
20
/**
21
 * @codeCoverageIgnore
22
 * @package TSK\SSO\Storage
23
 *
24
 * This will connect to a MongoDB database using the pecl/mongodb driver to persist vendor data.
25
 * The collection will be created on the fly.
26
 */
27
class PeclMongoDbThirdPartyStorageRepository implements ThirdPartyStorageRepository
28
{
29
    /**
30
     * @var MongoManager
31
     */
32
    private $mongoManager;
33
34
    /**
35
     * @var string name of the database in the MongoDB server
36
     */
37
    private $dbName;
38
39
    /**
40
     * @var string name of the collection in the application database
41
     */
42
    private $collection;
43
44
    /**
45
     * @param MongoManager $mongoManager
46
     * @param string $dbName
47
     * @param string $collection [optional] name of the collection in the MongoDB database
48
     */
49
    public function __construct(MongoManager $mongoManager, $dbName, $collection = 'thirdparty_connections')
50
    {
51
        $this->mongoManager = $mongoManager;
52
        $this->dbName = $dbName;
53
        $this->collection = $collection;
54
    }
55
56
    /**
57
     * Returns a mapped full user record for a given vendor email address or null.
58
     *
59
     * @param string $emailAddress email address used within the given vendor system
60
     * @param string|null $vendorName [optional] name of the third party vendor for vendor filtering
61
     * @return MappedUser|null
62
     */
63
    public function getUser($emailAddress, $vendorName = null)
64
    {
65
        if (is_null($vendorName)) {
66
            $cursor = $this->mongoManager->executeQuery(
67
                $this->collectionName(),
68
                new Query(array(
69
                    'vendor_email' => $emailAddress,
70
                ))
71
            );
72
        } else {
73
            $cursor = $this->mongoManager->executeQuery(
74
                $this->collectionName(),
75
                new Query(array(
76
                    'vendor_email' => $emailAddress,
77
                    'vendor_name' => $vendorName,
78
                ))
79
            );
80
        }
81
82
        foreach ($cursor as $mappedUserDoc) {
83
            return new MappedUser(
84
                $mappedUserDoc->app_user_id,
85
                $mappedUserDoc->vendor_name,
86
                $mappedUserDoc->vendor_email,
87
                $mappedUserDoc->vendor_access_token,
88
                $mappedUserDoc->vendor_data
89
            );
90
        }
91
92
        return null;
93
    }
94
95
    /**
96
     * Returns any vendor MappedUser list for a given Application user.
97
     *
98
     * @param AppUser $appUser
99
     * @return MappedUser[]
100
     * @throws InvalidArgumentException
101
     */
102
    public function getByAppUser(AppUser $appUser)
103
    {
104
        $cursor = $this->mongoManager->executeQuery(
105
            $this->collectionName(),
106
            new Query(array('app_user_id' => $appUser->id()))
107
        );
108
109
        $connections = array();
110
        foreach ($cursor as $mappedUserDoc) {
111
            $connections[] = new MappedUser(
112
                $mappedUserDoc->app_user_id,
113
                $mappedUserDoc->vendor_name,
114
                $mappedUserDoc->vendor_email,
115
                $mappedUserDoc->vendor_access_token,
116
                $mappedUserDoc->vendor_data
117
            );
118
        }
119
120
        return $connections;
121
    }
122
123
    /**
124
     * @param AppUser $appUser
125
     * @param ThirdPartyUser $thirdPartyUser
126
     * @param CommonAccessToken $accessToken
127
     * @throws DataCannotBeStoredException
128
     */
129
    public function save(
130
        AppUser $appUser,
131
        ThirdPartyUser $thirdPartyUser,
132
        CommonAccessToken $accessToken
133
    ) {
134
        $isUserHasConnection = $this->isUserHasConnection(
135
            $appUser->id(),
136
            $accessToken->vendor(),
137
            $thirdPartyUser->email()
138
        );
139
140
        $bulk = new BulkWrite();
141
142
        if ($isUserHasConnection) {
143
            $bulk->update(
144
                array(
145
                    'app_user_id' => $appUser->id(),
146
                    'vendor_name' => $thirdPartyUser->email(),
147
                    'vendor_email' => $accessToken->token(),
148
                ),
149
                array(
150
                    '$set' => array(
151
                        'vendor_access_token' => $accessToken->token(),
152
                        'vendor_refresh_token' => $accessToken->getRefreshToken(),
153
                        'vendor_data' => json_encode($thirdPartyUser->toArray()),
154
                    ),
155
                )
156
            );
157
        } else {
158
            $bulk->insert(array(
159
                '_id' => new ObjectID(),
160
                'app_user_id' => $appUser->id(),
161
                'vendor_name' => $accessToken->vendor(),
162
                'vendor_email' => $thirdPartyUser->email(),
163
                'vendor_access_token' => $accessToken->token(),
164
                'vendor_refresh_token' => $accessToken->getRefreshToken(),
165
                'vendor_data' => json_encode($thirdPartyUser->toArray()),
166
                'created_at' => date('Y-m-d H:i:s'),
167
            ));
168
        }
169
170
        try {
171
            $this->mongoManager->executeBulkWrite($this->collectionName(), $bulk);
172
        } catch (Exception $ex) {
173
            throw new DataCannotBeStoredException(
174
                sprintf("Couldn't save the third party user data. Error : %s", $ex->getMessage()),
175
                $ex->getCode(),
176
                $ex
177
            );
178
        }
179
    }
180
181
    /**
182
     * Use this to clean the storage after revoking access to a third party for example.
183
     *
184
     * @param string $emailAddress email address used within the given vendor system
185
     * @param string $vendorName name of the third party where the given email belongs to
186
     * @return bool
187
     */
188
    public function remove($emailAddress, $vendorName)
189
    {
190
        $bulk = new BulkWrite();
191
        $bulk->delete(array('vendor_email' => $emailAddress, 'vendor_name' => $vendorName));
192
193
        $writeResult = $this->mongoManager->executeBulkWrite($this->collectionName(), $bulk);
194
195
        return $writeResult->getDeletedCount() === 1;
196
    }
197
198
    /**
199
     * Check if the given user has a mapping to a requested vendor connection.
200
     *
201
     * @param string $appUserId
202
     * @param string $vendorName
203
     * @param string $vendorEmail
204
     * @return bool
205
     */
206
    private function isUserHasConnection($appUserId, $vendorName, $vendorEmail)
207
    {
208
        $cursor = $this->mongoManager->executeQuery(
209
            $this->collectionName(),
210
            new Query(array(
211
                'app_user_id' => $appUserId,
212
                'vendor_name' => $vendorName,
213
                'vendor_email' => $vendorEmail,
214
            ))
215
        );
216
217
        foreach ($cursor as $_) {
218
            return true;
219
        }
220
221
        return false;
222
    }
223
224
    /**
225
     * Returns a namespaced collection name.
226
     *
227
     * @return string
228
     */
229
    private function collectionName()
230
    {
231
        return sprintf('%s.%s', $this->dbName, $this->collection);
232
    }
233
}
234