Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
37.50% covered (danger)
37.50%
3 / 8
CRAP
50.00% covered (danger)
50.00%
15 / 30
APIManager
0.00% covered (danger)
0.00%
0 / 1
37.50% covered (danger)
37.50%
3 / 8
53.12
50.00% covered (danger)
50.00%
15 / 30
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.03
80.00% covered (danger)
80.00%
4 / 5
 getInstance
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 runAutoUpdate
0.00% covered (danger)
0.00%
0 / 1
13.15
41.67% covered (danger)
41.67%
5 / 12
 loadAPIConfig
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
2 / 2
 getEndpointsFromRegistry
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 updateEndpointsRegistry
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 updateEndpointData
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getEndpointData
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
1<?php
2
3namespace CeculaSyncApiClient;
4
5use Requests;
6
7class APIManager
8{
9    private static APIManager $obj;
10    public string $endpointData;
11    private static string $endpointsRegister = "endpoints.json";
12
13
14    private function __construct()
15    {
16        // Load Configuration
17        $this->loadAPIConfig();
18
19        // Check when last the registry was updated. 
20        // If registry file has not been updated in the last 24 hours update the file
21        if (!file_exists(__DIR__."/../".self::$endpointsRegister)) {
22            self::updateEndpointsRegistry($this->endpointData);
23        } else {
24            // Auto Update Register
25            $this->runAutoUpdate();
26        }
27    }
28
29    /**
30     * @return APIManager
31     */
32    public static function getInstance(): APIManager
33    {
34        if (!isset(self::$obj)) {
35            self::$obj = new APIManager();
36        } 
37        return self::$obj;
38    }
39
40
41    /**
42     * Run Auto-Update
43     * This method is invoked on class load to check for updates to API and effect the changes on client.
44     *
45     * @return void
46     */
47    private function runAutoUpdate(): void
48    {
49        $localData = json_decode($this->endpointData);
50
51            // Disable last update check if last check time is not registered
52            if (empty($localData->lastUpdateCheck) || !is_numeric($localData->lastUpdateCheck)) {
53                $localData->lastUpdateCheck = time() - (10 + $localData->updateInterval);
54            }
55
56            if ((time() - filemtime(__DIR__."/../".self::$endpointsRegister) > $localData->updateInterval) && (time() - $localData->lastUpdateCheck > $localData->updateInterval)) {
57                $remoteDataString = $this->getEndpointsFromRegistry();
58                $remoteData = json_decode($remoteDataString);
59                if ($localData->version == $remoteData->version) {
60                    $localData->lastUpdateCheck = time();
61                    self::updateEndpointsRegistry($this->endpointData);
62                } else {
63                    self::updateEndpointsRegistry($remoteDataString);
64                    $this->updateEndpointData($remoteDataString);
65                }
66            }
67    }
68
69    /**
70     * Load API Configuration
71     * This method checks if API Configuration file exists on client. If file is not found, it reads configuration
72     * from the API Server.
73     *
74     * @return void
75     */
76    private function loadAPIConfig(): void
77    {
78        // Load endpoints from the remote register if the local version is not found.
79            $this->endpointData = file_exists(__DIR__."/../".self::$endpointsRegister) ? file_get_contents(__DIR__."/../".self::$endpointsRegister) : $this->getEndpointsFromRegistry();
80    }
81
82
83    /**
84     * Get Endpoints From Registry
85     * This method reads endpoints from the API server
86     *
87     * @return string
88     */
89    private function getEndpointsFromRegistry(): string
90    {
91        $endpointData = !is_null($this->endpointData) ? json_decode($this->endpointData) : json_decode("");
92        $serviceConfig = Requests::get($endpointData->serviceAPIs ?? "https://cecula.com/sync/api/endpoints.json");
93        return $serviceConfig->body;
94    }
95
96
97    /**
98     * Update Endpoint Registry
99     * This method is used to update the local endpoint registry with values from the remote server.
100     *
101     * @param string $newData A JSON string of the API endpoints
102     * @return void
103     */
104    private static function updateEndpointsRegistry(string $newData): void
105    {
106        file_put_contents(__DIR__."/../".self::$endpointsRegister, $newData);
107    }
108
109    /**
110     * Update Endpoint Data
111     * A setter for loading the endpoints into memory.
112     *
113     * @param string $data  A JSON string of the API endpoints
114     * @return void
115     */
116    public function updateEndpointData(string $data): void
117    {
118        $this->endpointData = $data;
119    }
120
121
122    /**
123     * Get Endpoint Data
124     * A getter method for loading the API endpoints
125     *
126     * @return string
127     */
128    public function getEndpointData(): string
129    {
130        return $this->endpointData;
131    }
132}