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