/**
* Recursively duplicate files and folders
*
* @param string $source
* @param string $destination
*
* @throws AccessDeniedException
* @throws InternalServerErrorException
*/
public function copy($source = null, $destination = null)
{
if ($GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable']) {
throw new InternalServerErrorException('Table "' . $this->strTable . '" is not copyable.');
}
$strFolder = \Input::get('pid', true);
$blnDoNotRedirect = $source !== null;
if ($source === null) {
$source = $this->intId;
}
if ($destination === null) {
$destination = str_replace(dirname($source), $strFolder, $source);
}
$this->isValid($source);
$this->isValid($destination);
if (!file_exists(TL_ROOT . '/' . $source) || !$this->isMounted($source)) {
throw new AccessDeniedException('File or folder "' . $source . '" is not mounted or cannot be found.');
}
if (!file_exists(TL_ROOT . '/' . $strFolder) || !$this->isMounted($strFolder)) {
throw new AccessDeniedException('Parent folder "' . $strFolder . '" is not mounted or is not a directory.');
}
// Avoid a circular reference
if (preg_match('/^' . preg_quote($source, '/') . '/i', $strFolder)) {
throw new InternalServerErrorException('Attempt to copy the folder "' . $source . '" to "' . $strFolder . '" (circular reference).');
}
/** @var SessionInterface $objSession */
$objSession = \System::getContainer()->get('session');
// Empty clipboard
$arrClipboard = $objSession->get('CLIPBOARD');
$arrClipboard[$this->strTable] = array();
$objSession->set('CLIPBOARD', $arrClipboard);
$this->import('Files');
// Copy folders
if (is_dir(TL_ROOT . '/' . $source)) {
$count = 1;
$new = $destination;
// Add a suffix if the folder exists
while (is_dir(TL_ROOT . '/' . $new) && $count < 12) {
$new = $destination . '_' . $count++;
}
$destination = $new;
$this->Files->rcopy($source, $destination);
} else {
$count = 1;
$new = $destination;
// Add a suffix if the file exists
while (file_exists(TL_ROOT . '/' . $new) && $count < 12) {
$ext = pathinfo($destination, PATHINFO_EXTENSION);
$new = str_replace('.' . $ext, '_' . $count++ . '.' . $ext, $destination);
}
$destination = $new;
$this->Files->copy($source, $destination);
}
// Update the database AFTER the file has been copied
if ($this->blnIsDbAssisted) {
$syncSource = \Dbafs::shouldBeSynchronized($source);
$syncTarget = \Dbafs::shouldBeSynchronized($destination);
if ($syncSource && $syncTarget) {
\Dbafs::copyResource($source, $destination);
} elseif ($syncTarget) {
\Dbafs::addResource($destination);
}
}
// Call the oncopy_callback
if (is_array($GLOBALS['TL_DCA'][$this->strTable]['config']['oncopy_callback'])) {
foreach ($GLOBALS['TL_DCA'][$this->strTable]['config']['oncopy_callback'] as $callback) {
if (is_array($callback)) {
$this->import($callback[0]);
$this->{$callback[0]}->{$callback[1]}($source, $destination, $this);
} elseif (is_callable($callback)) {
$callback($source, $destination, $this);
}
}
}
// Add a log entry
$this->log('File or folder "' . $source . '" has been duplicated', __METHOD__, TL_FILES);
// Redirect
if (!$blnDoNotRedirect) {
$this->redirect($this->getReferer());
}
}