Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Csv
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 6
462
0.00% covered (danger)
0.00%
0 / 1
 store
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 cleanInputData
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 openFile
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 getColumns
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 update
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
72
 flush
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2015 (original work) Open Assessment Technologies SA;
19 *
20 *
21 */
22
23namespace oat\taoClientDiagnostic\model\storage;
24
25use oat\oatbox\service\ConfigurableService;
26use oat\taoClientDiagnostic\exception\StorageException;
27
28/**
29 * Class Csv
30 * @package oat\taoClientDiagnostic\model\storage
31 */
32class Csv extends ConfigurableService implements Storage
33{
34    /**
35     * Csv file handle
36     * @var stream
37     */
38    private $handle;
39
40    /**
41     * Merge id and data array
42     * Clean input data by adding empty column
43     * Open csv and create new entry
44     * @param $id
45     * @param $data
46     * @return $this
47     */
48    public function store($id, $data = array())
49    {
50        $data = array_merge(
51            [self::DIAGNOSTIC_ID => $id],
52            $data
53        );
54
55        $data = $this->cleanInputData($data);
56
57        $this->openFile();
58        $this->update($id, $data);
59
60        return $this;
61    }
62
63    /**
64     * Check if $input keys are constants of Storage
65     * Set input keys as empty value if not exists
66     * @param array $input
67     * @return array
68     */
69    protected function cleanInputData(array $input)
70    {
71        $columns = $this->getColumns();
72        foreach ($columns as $column) {
73            if (!isset($input[$column])) {
74                $input[$column] = '';
75            }
76        }
77        return $input;
78    }
79
80    /**
81     * Handle csv file, create it if not exists (with column name)
82     * @throws StorageException
83     * @return string
84     */
85    private function openFile()
86    {
87        $file = $this->getOption('filename');
88        $fileExists = file_exists($file);
89        if (($this->handle = fopen($file, 'a+')) !== false) {
90            if (!$fileExists) {
91                fputcsv($this->handle, $this->getColumns(), ';');
92                fseek($this->handle, 0);
93            }
94            return;
95        }
96        throw new StorageException('Unable to open csv file');
97    }
98
99    /**
100     * Return an array of Storage constant var
101     * @return array
102     * @throws StorageException
103     */
104    private function getColumns()
105    {
106        $class = new \ReflectionClass(__CLASS__);
107        $constants = $class->getConstants();
108        $columns = [];
109        foreach ($constants as $constant => $value) {
110            if (strpos($constant, 'DIAGNOSTIC_') === 0) {
111                array_push($columns, $value);
112            }
113        }
114        if (empty($columns)) {
115            throw new StorageException('No column to fill into CSV storage');
116        }
117        return $columns;
118    }
119
120    /**
121     * Copy csv data into tmp file with updated line referenced by $id
122     * Copy tmp file to csv && remove tmp file
123     * @param $id
124     * @param $entityData
125     * @return bool|string|void
126     * @throws StorageException
127     */
128    private function update($id, $entityData = [])
129    {
130        $tmpFile = \tao_helpers_File::createTempDir() . 'store.csv';
131        $tmpHandle = fopen($tmpFile, 'w');
132        $line = 1;
133        $index = 0;
134
135        while (($data = fgetcsv($this->handle, 1000, ";")) !== false) {
136            if ($line === 1) {
137                $keys = $data;
138                if (($index = array_search('id', $keys, true)) === false) {
139                    return false;
140                }
141            }
142
143            if ($data[$index] == $id) {
144                foreach ($data as $index => $value) {
145                    if (empty($entityData[$keys[$index]])) {
146                        $entityData[$keys[$index]] = $value;
147                    }
148                }
149            } else {
150                fputcsv($tmpHandle, $data, ';');
151            }
152            $line++;
153        }
154        $entityData = array_merge(array_flip($keys), $entityData);
155        fputcsv($tmpHandle, $entityData, ';');
156        fclose($tmpHandle);
157        fclose($this->handle);
158        \tao_helpers_File::copy($tmpFile, $this->getOption('filename')) && unlink($tmpFile);
159        return;
160    }
161
162    public function flush()
163    {
164        $file = $this->getOption('filename');
165        if (file_exists($file)) {
166            return unlink($file);
167        }
168        return true;
169    }
170}