Added Feature #16641: Here comes FAL - beta2 version
[Packages/TYPO3.CMS.git] / typo3 / sysext / fal / classes / controller / class.tx_fal_migrationcontroller.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010 FAL development team <fal@wmdb.de>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * File Abtraction Layer Migration controller
30 *
31 * @author FAL development team <fal@wmdb.de>
32 * @package TYPO3
33 * @subpackage tx_fal
34 * @version $Id: $
35 */
36 class tx_fal_MigrationController {
37
38 /**
39 * Iterator to use
40 *
41 * @var tx_fal_DatabaseFieldnameIterator
42 */
43 protected $fieldnameIterator = null;
44
45 /**
46 * Limit for iterations
47 *
48 * @var integer
49 */
50 protected $limit = 500;
51
52 /**
53 * Iteration count on how many references were checked
54 *
55 * @var integer
56 */
57 protected $fileReferencesIteration = 0;
58
59 /**
60 * Mount to use as base for the index
61 *
62 * @var tx_fal_Mount
63 */
64 protected $mount = null;
65
66 /**
67 * Contructor of the controller
68 *
69 * @return void
70 */
71 public function __construct() {
72 $this->mount = tx_fal_Mount::getInstanceForUid(0);
73 }
74
75 /**
76 * Setter for fieldname iterator
77 *
78 * @param array/tx_fal_DatabaseFieldnameIterator $fieldnameIterator DESCRIPTION
79 * @return tx_fal_MigrationController DESCRIPTION
80 */
81 public function setFieldnameIterator($fieldnameIterator) {
82 $this->fieldnameIterator = $fieldnameIterator;
83
84 return $this;
85 }
86
87 /**
88 * Setter for record iterator
89 *
90 * @param array/tx_fal_RecordIterator $recordIterator DESCRIPTION
91 * @return tx_fal_MigrationController DESCRIPTION
92 */
93 public function setRecordIterator($recordIterator) {
94 $this->recordIterator = $recordIterator;
95
96 return $this;
97 }
98
99 /**
100 * Setter for limit
101 *
102 * @param integer $limit DESCRIPTION
103 * @return tx_fal_MigrationController DESCRIPTION
104 */
105 public function setLimit($limit) {
106 $this->limit = $limit;
107
108 return $this;
109 }
110
111 /**
112 * Execution of the migration
113 *
114 * @return void
115 */
116 public function execute() {
117 // fetch combination of tablename and fieldname
118 foreach ($this->fieldnameIterator as $tableName => $fieldName) {
119 $sourcePath = $this->getSourcePath($tableName, $fieldName);
120 // fetch records for tablename and fieldname and loop over them
121 $this->recordIterator->fetchRecordsForTableAndField($tableName, $fieldName);
122 foreach ($this->recordIterator as $recordUid => $filenameList) {
123
124 // explode filenameList and check each name
125 $fileNames = t3lib_div::trimExplode(',', $filenameList);
126 foreach ($fileNames as $filenamePosition => $fileName) {
127 $assetUid = 0;
128 $duplicateRecord = $this->fetchDuplicateRecord($fileName, $sourcePath, $tableName, $fieldName);
129
130 if ($duplicateRecord == FALSE) {
131 $destinationPath = $this->getDestinationPath($tableName, $fieldName, $recordUid);
132 if (is_file($sourcePath . $fileName)) {
133
134 @copy($sourcePath . $fileName, $destinationPath . $fileName);
135
136 t3lib_div::fixPermissions($destinationPath . $fileName);
137 $newfile = tx_fal_Indexer::addFileToIndex($this->mount, $destinationPath . $fileName);
138
139 $assetUid = $newfile;
140 $this->fileMoved++;
141 } else {
142 t3lib_div::devLog('copy file ', __CLASS__, 1, array('FILE NOT FOUND'));
143 }
144 } else {
145 $assetUid = $duplicateRecord['uid'];
146 $this->doublicatedFound++;
147 }
148
149 if ($assetUid) {
150 $sorting = $filenamePosition + 1;
151 #t3lib_div::devLog('create reference ', __CLASS__, 1, array($tableName, $fieldName, $recordUid, $assetUid, $sorting));
152 $this->createReference($tableName, $fieldName, $recordUid, $assetUid, $sorting);
153 }
154
155 $this->fileReferencesIteration++;
156 if ($this->fileReferencesIteration >= $this->limit) {
157 break 3;
158 }
159 }
160
161 // after migrating ever file for this field cound the references and write them back
162 $referenceCount = $this->fetchReferenceCount($tableName, $fieldName, $recordUid);
163 $this->updateReferenceCount($tableName, $fieldName, $recordUid, $referenceCount);
164 }
165 }
166 }
167
168 /**
169 * Render the destination path
170 *
171 * @param string $tableName DESCRIPTION
172 * @param string $fieldName DESCRIPTION
173 * @param string $recordUid DESCRIPTION
174 * @return string DESCRIPTION
175 */
176 protected function getDestinationPath($tableName, $fieldName, $recordUid) {
177 $fileadminDir = PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'];
178 // fix folder
179 if ($fileadminDir{strlen($fileadminDir)-1} == '/') {
180 $fileadminDir = substr($fileadminDir, 0, strlen($fileadminDir) - 1);
181 }
182 $destinationPath = $fileadminDir . '/FAL_Migration/' . $tableName . '/' . $fieldName;
183
184 if (is_array($GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['fal/classes/controller/class.tx_fal_migrationcontroller.php']['copyFileToPath'])) {
185 $params = array(
186 'tableName' => $tableName,
187 'fieldName' => $fieldName,
188 'recordUid' => $recordUid,
189 );
190
191 foreach ($GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['fal/classes/controller/class.tx_fal_migrationcontroller.php']['copyFileToPath'] as $hookReference) {
192 $hookObject =& t3lib_div::getUserObj($hookReference);
193 if (method_exists($hookObject, 'copyFileToPath')) {
194 $destinationPath = $hookObject->copyFileToPath($params, $destinationPath, $this);
195 }
196 }
197 }
198
199 if (strpos($destinationPath, $fileadminDir . '/FAL_Migration/') === false) {
200 $destinationPath = $fileadminDir . '/FAL_Migration/' . $destinationPath;
201 }
202
203 if (!is_dir($destinationPath)) {
204 t3lib_div::mkdir_deep(PATH_site, str_replace(PATH_site, '', $destinationPath));
205 }
206
207 return $destinationPath;
208 }
209
210 /**
211 * Fetch path from tca for tablename and field
212 *
213 * @param string $tableName DESCRIPTION
214 * @param string $fieldName DESCRIPTION
215 * @return string DESCRIPTION
216 */
217 protected function getSourcePath($tableName, $fieldName) {
218 $pathFromTCA = $GLOBALS['TCA'][$tableName]['columns'][$fieldName]['config']['uploadfolder'];
219 // make sure a trailing slash is there
220 $pathParts = t3lib_div::trimExplode('/', $pathFromTCA);
221 $fixedPath = implode('/', $pathParts) . '/';
222 return PATH_site . $fixedPath;
223 }
224
225 /**
226 * Check if a sys_file is already available with the same sha1 hash
227 *
228 * @param [to be defined] $fileName DESCRIPTION
229 * @return boolean DESCRIPTION
230 */
231 protected function fetchDuplicateRecord($fileName, $filePath, $table, $fieldName) {
232 $GLOBALS['TYPO3_DB']->debugOutput = 1;
233 $result = FALSE;
234 if(isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fal']['tableAndFieldMapping'][$table][$fieldName])) {
235 $fieldName = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fal']['tableAndFieldMapping'][$table][$fieldName];
236 }
237 $fileHash = $this->getFileHash($fileName, $filePath);
238
239 $res = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query(
240 'sys_files.*',
241 'sys_files',
242 'sys_files_usage_mm',
243 $table,
244 'AND sys_files.file_hash = \'' . $fileHash . '\' AND sys_files_usage_mm.tablenames = \''.$table.'\' AND sys_files_usage_mm.ident = \''.$fieldName.'\''
245 );
246 // if files with same filehash are found
247 while ($fileRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
248 if(count($fileRecord) > 1) {
249 $result = $fileRecord;
250 break;
251 }
252 }
253 return $result;
254 }
255
256 /**
257 * Remove filename additions like _01 _02
258 *
259 * @param string $fileName DESCRIPTION
260 * @return string DESCRIPTION
261 */
262 protected function makeFilenameUnique($fileName) {
263 // get extension
264 $fileInfo = pathinfo($fileName);
265 $fileName = str_replace('.' . $fileInfo['extension'], '', $fileName);
266 $fileNameParts = explode('_', $fileName);
267 $void = array_pop($fileNameParts);
268 return implode('_', $fileNameParts) . '.' . $fileInfo['extension'];
269 }
270
271 /**
272 * Fetches the filehash and returns it
273 *
274 * @param string $fileName DESCRIPTION
275 * @param string $filePath DESCRIPTION
276 * @return string DESCRIPTION
277 */
278 protected function getFileHash($fileName, $filePath) {
279 return sha1_file($filePath . '/' . $fileName);
280 }
281
282 /**
283 * Create reference between record and asset
284 *
285 * @param string $tableName DESCRIPTION
286 * @param string $fieldName DESCRIPTION
287 * @param integer $recordUid DESCRIPTION
288 * @param integer $assetUid DESCRIPTION
289 * @param integer $sorting DESCRIPTION
290 * @return void
291 */
292 protected function createReference($tableName, $fieldName, $recordUid, $assetUid, $sorting) {
293 // get real fieldname
294 if(isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fal']['tableAndFieldMapping'][$tableName][$fieldName])) {
295 $fieldName = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['fal']['tableAndFieldMapping'][$tableName][$fieldName];
296 }
297 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
298 '*',
299 'sys_files_usage_mm',
300 'uid_local = ' . $assetUid .
301 ' AND uid_foreign = ' . $recordUid .
302 ' AND tablenames = \'' . $tableName . '\'' .
303 ' AND ident = \'' . $fieldName . '\'' .
304 ' AND sorting = ' . $sorting
305 );
306
307 if (!$count) {
308 $GLOBALS['TYPO3_DB']->exec_INSERTquery(
309 'sys_files_usage_mm',
310 array(
311 'uid_local' => $assetUid,
312 'uid_foreign' => $recordUid,
313 'tablenames' => $tableName,
314 'ident' => $fieldName,
315 'sorting' => $sorting,
316 )
317 );
318 }
319 }
320
321 /**
322 * Count the references for combination of asset, record, tablename, fieldname
323 *
324 * @param string $tableName DESCRIPTION
325 * @param string $fieldName DESCRIPTION
326 * @param integer $recordUid DESCRIPTION
327 * @param integer $assetUid DESCRIPTION
328 * @return integer DESCRIPTION
329 */
330 protected function fetchReferenceCount($tableName, $fieldName, $recordUid) {
331 return $GLOBALS['TYPO3_DB']->exec_SELECTcountRows(
332 '*',
333 'sys_files_usage_mm',
334 'uid_foreign = ' . $recordUid .
335 ' AND tablenames = \'' . $tableName . '\'' .
336 ' AND ident = \'' . $fieldName . '\''
337 );
338 }
339
340 /**
341 * Update the reference count to table
342 *
343 * @param integer $referenceCount DESCRIPTION
344 * @return void
345 */
346 protected function updateReferenceCount($tableName, $fieldName, $recordUid, $referenceCount) {
347 $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
348 $tableName,
349 'uid = ' . $recordUid,
350 array($fieldName . '_rel' => $referenceCount)
351 );
352 }
353 }
354
355 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/fal/classes/controller/class.tx_fal_migrationcontroller.php'])) {
356 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/fal/classes/controller/class.tx_fal_migrationcontroller.php']);
357 }
358 ?>