FileSystemThirdPartyStorageRepository::getUser()   A
last analyzed

Complexity

Conditions 5
Paths 6

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5.0042

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 15
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 25
rs 9.4555
ccs 17
cts 18
cp 0.9444
crap 5.0042
1
<?php
2
/**
3
 * @author Tharanga Kothalawala <[email protected]>
4
 * @date 30-12-2018
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
14
/**
15
 * @package TSK\SSO\Storage
16
 *
17
 * This will use the server file system to persist vendor data.
18
 */
19
class FileSystemThirdPartyStorageRepository implements ThirdPartyStorageRepository
20
{
21
    const FILE_NAME = 'tsk.sso.storage.json';
22
23
    /**
24
     * @var string
25
     */
26
    private $baseDirectory;
27
28
    /**
29
     * @param string $baseDirectory
30
     */
31 4
    public function __construct($baseDirectory = '/tmp')
32
    {
33 4
        $this->baseDirectory = $baseDirectory;
34 4
        $this->createFile();
35 4
    }
36
37
    /**
38
     * Returns a mapped full user record for a given vendor email address or null.
39
     *
40
     * @param string $emailAddress email address used within the given vendor system
41
     * @param string|null $vendorName [optional] name of the third party vendor for vendor filtering
42
     * @return MappedUser|null
43
     */
44 2
    public function getUser($emailAddress, $vendorName = null)
45
    {
46 2
        $fileDataDecoded = $this->getDecodedData();
47 2
        if (is_null($fileDataDecoded)) {
48
            return null;
49
        }
50
51 2
        foreach ($fileDataDecoded as $vendorAndEmail => $mappedUser) {
52 2
            $searchVendorName = is_null($vendorName) ? $mappedUser['vendor_name'] : $vendorName;
53
54 2
            $searchKey = sprintf('%s::%s', $searchVendorName, $emailAddress);
55 2
            if ($vendorAndEmail !== $searchKey) {
56 1
                continue;
57
            }
58
59 2
            return new MappedUser(
60 2
                $mappedUser['app_user_id'],
61 2
                $mappedUser['vendor_name'],
62 2
                $mappedUser['vendor_email'],
63 2
                $mappedUser['vendor_access_token'],
64 2
                $mappedUser['vendor_data']
65 2
            );
66 2
        }
67
68 2
        return null;
69
    }
70
71
    /**
72
     * Returns any vendor MappedUser list for a given Application user.
73
     * Use this to display all the vendor connections.
74
     *
75
     * @param AppUser $appUser
76
     * @return MappedUser[]
77
     */
78 1
    public function getByAppUser(AppUser $appUser)
79
    {
80 1
        $fileDataDecoded = $this->getDecodedData();
81 1
        if (is_null($fileDataDecoded)) {
82
            return array();
83
        }
84
85 1
        $connections = array();
86 1
        foreach ($fileDataDecoded as $vendorAndEmail => $mappedUser) {
87 1
            if ($mappedUser['app_user_id'] != $appUser->id()) {
88 1
                continue;
89
            }
90
91 1
            $connections[] = new MappedUser(
92 1
                $mappedUser['app_user_id'],
93 1
                $mappedUser['vendor_name'],
94 1
                $mappedUser['vendor_email'],
95 1
                $mappedUser['vendor_access_token'],
96 1
                $mappedUser['vendor_data']
97 1
            );
98 1
        }
99
100 1
        return $connections;
101
    }
102
103
    /**
104
     * @param AppUser $appUser
105
     * @param ThirdPartyUser $thirdPartyUser
106
     * @param CommonAccessToken $accessToken
107
     * @throws DataCannotBeStoredException
108
     */
109 1
    public function save(
110
        AppUser $appUser,
111
        ThirdPartyUser $thirdPartyUser,
112
        CommonAccessToken $accessToken
113
    ) {
114 1
        $data = $this->getDecodedData();
115 1
        if (is_null($data)) {
116
            return;
117
        }
118
119 1
        $key = sprintf('%s::%s', $accessToken->vendor(), $thirdPartyUser->email());
120 1
        $data[$key] = array(
121 1
            'app_user_id' => $appUser->id(),
122 1
            'vendor_name' => $accessToken->vendor(),
123 1
            'vendor_email' => $thirdPartyUser->email(),
124 1
            'vendor_access_token' => $accessToken->token(),
125 1
            'vendor_refresh_token' => $accessToken->getRefreshToken(),
126 1
            'vendor_data' => json_encode($thirdPartyUser->toArray()),
127 1
            'created_at' => date('Y-m-d H:i:00'),
128
        );
129
130 1
        $written = file_put_contents($this->fileAbsolutePath(), json_encode($data));
131 1
        if (!$written) {
132
            throw new DataCannotBeStoredException("Couldn't save the third party user data due to a file system error");
133
        }
134 1
    }
135
136
    /**
137
     * Use this to clean the storage after revoking access to a third party for example.
138
     *
139
     * @param string $emailAddress email address used within the given vendor system
140
     * @param string $vendorName name of the third party where the given email belongs to
141
     * @return bool
142
     */
143 1
    public function remove($emailAddress, $vendorName)
144
    {
145 1
        $data = $this->getDecodedData();
146 1
        if (is_null($data)) {
147
            return false;
148
        }
149
150 1
        $key = sprintf('%s::%s', $vendorName, $emailAddress);
151 1
        unset($data[$key]);
152 1
        return file_put_contents($this->fileAbsolutePath(), json_encode($data));
0 ignored issues
show
Bug Best Practice introduced by
The expression return file_put_contents...(), json_encode($data)) returns the type integer which is incompatible with the documented return type boolean.
Loading history...
153
    }
154
155
    /**
156
     * Returns an array containing raw third party user mappings.
157
     *
158
     * @return array|null
159
     */
160 4
    private function getDecodedData()
161
    {
162 4
        $fileData = file_get_contents($this->fileAbsolutePath());
163 4
        if (empty($fileData)) {
164
            return null;
165
        }
166
167 4
        $fileDataDecoded = @json_decode($fileData, true);
168 4
        if ($fileDataDecoded === null && json_last_error() !== JSON_ERROR_NONE) {
169
            return null;
170
        }
171
172 4
        if (!is_array($fileDataDecoded)) {
173
            return null;
174
        }
175
176 4
        return $fileDataDecoded;
177
    }
178
179
    /**
180
     * Creates a new storage file in the file system. empty json object will be added if the file is empty.
181
     */
182 4
    private function createFile()
183
    {
184 4
        if (!file_exists($this->fileAbsolutePath())) {
185 1
            file_put_contents($this->fileAbsolutePath(), '{}');
186 1
        }
187
188 4
        $contents = file_get_contents($this->fileAbsolutePath());
189 4
        if (empty($contents)) {
190
            file_put_contents($this->fileAbsolutePath(), '{}');
191
        }
192 4
    }
193
194
    /**
195
     * @return string
196
     */
197 4
    private function fileAbsolutePath()
198
    {
199 4
        return sprintf('%s/%s', $this->baseDirectory, self::FILE_NAME);
200
    }
201
}
202