Completed
Pull Request — master (#2)
by Tharanga
02:20
created

PeclMongoDbThirdPartyStorageRepository::getUser()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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