1<?php
2
3/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
4
5/**
6 * Hook-Class for exporting data-collections (used in SOAP-Class)
7 * This Class avoids duplicated code by routing the request to the right place
8 *
9 * @author  Michael Herren <mh@studer-raimann.ch>
10 * @ingroup ModulesDataCollection
11 */
12class ilDclContentExporter
13{
14    const SOAP_FUNCTION_NAME = 'exportDataCollectionContent';
15    const EXPORT_EXCEL = 'xlsx';
16    const IN_PROGRESS_POSTFIX = '.prog';
17    /**
18     * @var int $ref_id Ref-ID of DataCollection
19     */
20    protected $ref_id;
21    /**
22     * @var int $table_id Table-Id for export
23     */
24    protected $table_id;
25    /**
26     * @var array $filter Array with filters
27     */
28    protected $filter;
29    /**
30     * @var ilObjDataCollection
31     */
32    protected $dcl;
33    /**
34     * @var ilLanguage
35     */
36    protected $lng;
37    /**
38     * @var ilDclTable
39     */
40    protected $table;
41
42
43    public function __construct($ref_id, $table_id = null, $filter = array())
44    {
45        global $DIC;
46        $lng = $DIC['lng'];
47
48        $this->ref_id = $ref_id;
49        $this->table_id = $table_id;
50        $this->filter = $filter;
51
52        $this->dcl = new ilObjDataCollection($ref_id);
53        $this->tables = ($table_id) ? array($this->dcl->getTableById($table_id)) : $this->dcl->getTables();
54
55        $lng->loadLanguageModule('dcl');
56        $this->lng = $lng;
57    }
58
59
60    /**
61     * Sanitize the given filename
62     * The ilUtil::_sanitizeFilemame() does not clean enough
63     *
64     * @param $filename
65     *
66     * @return string
67     */
68    public function sanitizeFilename($filename)
69    {
70        $dangerous_filename_characters = array(" ", '"', "'", "&", "/", "\\", "?", "#", "`");
71
72        return str_replace($dangerous_filename_characters, "_", iconv("utf-8", "ascii//TRANSLIT", $filename));
73    }
74
75
76    /**
77     * Return export path
78     *
79     * @param $format
80     *
81     * @return string
82     */
83    public function getExportContentPath($format)
84    {
85        return ilExport::_getExportDirectory($this->dcl->getId(), $format, 'dcl') . '/';
86    }
87
88
89    /**
90     * Fill a excel row
91     *
92     * @param ilDclTable           $table
93     * @param ilExcel              $worksheet
94     * @param ilDclBaseRecordModel $record
95     * @param                      $row
96     */
97    protected function fillRowExcel(ilDclTable $table, ilExcel $worksheet, ilDclBaseRecordModel $record, $row)
98    {
99        $col = 0;
100        foreach ($table->getFields() as $field) {
101            if ($field->getExportable()) {
102                $record->fillRecordFieldExcelExport($worksheet, $row, $col, $field->getId());
103            }
104        }
105    }
106
107
108    /**
109     * Fill Excel header
110     *
111     * @param ilDclTable $table
112     * @param ilExcel    $worksheet
113     * @param            $row
114     */
115    protected function fillHeaderExcel(ilDclTable $table, ilExcel $worksheet, $row)
116    {
117        $col = 0;
118
119        foreach ($table->getFields() as $field) {
120            if ($field->getExportable()) {
121                $field->fillHeaderExcel($worksheet, $row, $col);
122            }
123        }
124    }
125
126
127    /**
128     * Fill Excel meta-data
129     *
130     * @param $table
131     * @param $worksheet
132     * @param $row
133     */
134    protected function fillMetaExcel($table, $worksheet, $row)
135    {
136    }
137
138
139    /**
140     * Creates an export of a specific datacollection table
141     *
142     * @param string     $format
143     * @param null       $filepath
144     * @param bool|false $send
145     *
146     * @return null|string|void
147     */
148    public function export($format = self::EXPORT_EXCEL, $filepath = null, $send = false)
149    {
150        if (count($this->tables) == 0) {
151            return;
152        }
153
154        if (empty($filepath)) {
155            $filepath = $this->getExportContentPath($format);
156            ilUtil::makeDirParents($filepath);
157
158            $basename = (isset($this->table_id)) ? $this->tables[0]->getTitle() : 'complete';
159            $filename = time() . '__' . $basename . "_" . date("Y-m-d_H-i");
160
161            $filepath .= $this->sanitizeFilename($filename);
162        } else {
163            $filename = pathinfo($filepath, PATHINFO_FILENAME);
164        }
165
166        $in_progress_file = $filepath . self::IN_PROGRESS_POSTFIX;
167        file_put_contents($in_progress_file, "");
168
169        $data_available = false;
170        $fields_available = false;
171        switch ($format) {
172            case self::EXPORT_EXCEL:
173                $adapter = new ilExcel();
174                foreach ($this->tables as $table) {
175                    ilDclCache::resetCache();
176
177                    $list = $table->getPartialRecords(null, null, null, 0, $this->filter);
178                    $data_available = $data_available || ($list['total'] > 0);
179                    $fields_available = $fields_available || (count($table->getExportableFields()) > 0);
180                    if ($list['total'] > 0 && count($table->getExportableFields()) > 0) {
181                        // only 31 character-long table-titles are allowed
182                        $title = substr($table->getTitle(), 0, 31);
183                        $adapter->addSheet($title);
184                        $row = 1;
185
186                        $this->fillMetaExcel($table, $adapter, $row);
187
188                        // #14813
189                        $pre = $row;
190                        $this->fillHeaderExcel($table, $adapter, $row);
191                        if ($pre == $row) {
192                            $row++;
193                        }
194
195                        foreach ($list['records'] as $set) {
196                            $this->fillRowExcel($table, $adapter, $set, $row);
197                            $row++; // #14760
198                        }
199
200                        $data_available = true;
201                    }
202                }
203                break;
204        }
205
206        if (file_exists($in_progress_file)) {
207            unlink($in_progress_file);
208        }
209
210        if (!$data_available) {
211            ilUtil::sendInfo($this->lng->txt('dcl_no_export_content_available'));
212
213            return false;
214        }
215
216        if (!$fields_available) {
217            global $ilCtrl;
218            ilUtil::sendInfo(
219                sprintf(
220                    $this->lng->txt('dcl_no_export_fields_available'),
221                    $ilCtrl->getLinkTargetByClass(array('ilDclTableListGUI', 'ilDclTableEditGUI', 'ilDclFieldListGUI'), 'listFields')
222                )
223            );
224
225            return false;
226        }
227
228        if ($send) {
229            $adapter->sendToClient($filename);
230            exit;
231        } else {
232            $adapter->writeToFile($filepath);
233        }
234    }
235
236
237    /**
238     * Start Export async
239     *
240     * @param string $format
241     * @param null   $filepath
242     *
243     * @return mixed
244     * @throws ilDclException
245     */
246    public function exportAsync($format = self::EXPORT_EXCEL, $filepath = null)
247    {
248        global $DIC;
249        $ilLog = $DIC['ilLog'];
250
251        $method = self::SOAP_FUNCTION_NAME;
252
253        $soap_params = array($this->dcl->getRefId());
254        array_push($soap_params, $this->table_id, $format, $filepath);
255
256        $new_session_id = ilSession::_duplicate($_COOKIE[session_name()]);
257        $client_id = $_COOKIE['ilClientId'];
258
259        // Start cloning process using soap call
260        $soap_client = new ilSoapClient();
261        $soap_client->setResponseTimeout(5);
262        $soap_client->enableWSDL(true);
263
264        $ilLog->write(__METHOD__ . ': Trying to call Soap client...');
265
266        array_unshift($soap_params, $new_session_id . '::' . $client_id);
267
268        if ($soap_client->init()) {
269            $ilLog->info('Calling soap ' . $method . ' method with params ' . print_r($soap_params, true));
270            $res = $soap_client->call($method, $soap_params);
271        } else {
272            $ilLog->warning('SOAP clone call failed. Calling clone method manually');
273            require_once('./webservice/soap/include/inc.soap_functions.php');
274            if (method_exists('ilSoapFunctions', $method)) {
275                $res = ilSoapFunctions::$method($new_session_id . '::' . $client_id, $this->dcl->getRefId(), $this->table_id, $format, $filepath);
276            } else {
277                throw new ilDclException("SOAP call " . $method . " does not exists!");
278            }
279        }
280
281        return $res;
282    }
283}
284