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($this->strRootDir . '/' . $source) || !$this->isMounted($source))
		{
			throw new AccessDeniedException('File or folder "' . $source . '" is not mounted or cannot be found.');
		}

		if (!file_exists($this->strRootDir . '/' . $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 Session $objSession */
		$objSession = System::getContainer()->get('session');

		// Empty clipboard
		$arrClipboard = $objSession->get('CLIPBOARD');
		$arrClipboard[$this->strTable] = array();
		$objSession->set('CLIPBOARD', $arrClipboard);

		$this->import(Files::class, 'Files');

		// Copy folders
		if (is_dir($this->strRootDir . '/' . $source))
		{
			$count = 1;
			$new = $destination;

			// Add a suffix if the folder exists
			while (is_dir($this->strRootDir . '/' . $new) && $count < 12)
			{
				$new = $destination . '_' . $count++;
			}

			$destination = $new;
			$this->Files->rcopy($source, $destination);
		}

		// Copy a file
		else
		{
			$count = 1;
			$new = $destination;
			$ext = strtolower(substr($destination, strrpos($destination, '.') + 1));

			// Add a suffix if the file exists
			while (file_exists($this->strRootDir . '/' . $new) && $count < 12)
			{
				$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 copied to "'.$destination.'"', __METHOD__, TL_FILES);

		// Redirect
		if (!$blnDoNotRedirect)
		{
			// Switch to edit mode
			if (is_file($this->strRootDir . '/' . $destination))
			{
				$this->redirect($this->switchToEdit($destination));
			}

			$this->redirect($this->getReferer());
		}
	}
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($this->strRootDir . '/' . $source) || !$this->isMounted($source))
		{
			throw new AccessDeniedException('File or folder "' . $source . '" is not mounted or cannot be found.');
		}

		if (!file_exists($this->strRootDir . '/' . $strFolder) || !$this->isMounted($strFolder))
		{
			throw new AccessDeniedException('Parent folder "' . $strFolder . '" is not mounted or is not a directory.');
		}

		
		if (preg_match('/^' . preg_quote($source, '/') . '/i', $strFolder))
		{
			throw new InternalServerErrorException('Attempt to copy the folder "' . $source . '" to "' . $strFolder . '" (circular reference).');
		}

		
		$objSession = System::getContainer()->get('session');

		
		$arrClipboard = $objSession->get('CLIPBOARD');
		$arrClipboard[$this->strTable] = array();
		$objSession->set('CLIPBOARD', $arrClipboard);

		$this->import(Files::class, 'Files');

		
		if (is_dir($this->strRootDir . '/' . $source))
		{
			$count = 1;
			$new = $destination;

			
			while (is_dir($this->strRootDir . '/' . $new) && $count < 12)
			{
				$new = $destination . '_' . $count++;
			}

			$destination = $new;
			$this->Files->rcopy($source, $destination);
		}

		
		else
		{
			$count = 1;
			$new = $destination;
			$ext = strtolower(substr($destination, strrpos($destination, '.') + 1));

			
			while (file_exists($this->strRootDir . '/' . $new) && $count < 12)
			{
				$new = str_replace('.' . $ext, '_' . $count++ . '.' . $ext, $destination);
			}

			$destination = $new;
			$this->Files->copy($source, $destination);
		}

		
		if ($this->blnIsDbAssisted)
		{
			$syncSource = Dbafs::shouldBeSynchronized($source);
			$syncTarget = Dbafs::shouldBeSynchronized($destination);

			if ($syncSource && $syncTarget)
			{
				Dbafs::copyResource($source, $destination);
			}
			elseif ($syncTarget)
			{
				Dbafs::addResource($destination);
			}
		}

		
		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);
				}
			}
		}

		
		$this->log('File or folder "'.$source.'" has been copied to "'.$destination.'"', __METHOD__, TL_FILES);

		
		if (!$blnDoNotRedirect)
		{
			
			if (is_file($this->strRootDir . '/' . $destination))
			{
				$this->redirect($this->switchToEdit($destination));
			}

			$this->redirect($this->getReferer());
		}
	}
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 ( $ this -> strRootDir . '/' . $ source ) || ! $ this -> isMounted ( $ source ) ) { throw new AccessDeniedException ( 'File or folder "' . $ source . '" is not mounted or cannot be found.' ) ; } if ( ! file_exists ( $ this -> strRootDir . '/' . $ 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 Session $objSession */ $ objSession = System :: getContainer ( ) -> get ( 'session' ) ; // Empty clipboard $ arrClipboard = $ objSession -> get ( 'CLIPBOARD' ) ; $ arrClipboard [ $ this -> strTable ] = array ( ) ; $ objSession -> set ( 'CLIPBOARD' , $ arrClipboard ) ; $ this -> import ( Files :: class , 'Files' ) ; // Copy folders if ( is_dir ( $ this -> strRootDir . '/' . $ source ) ) { $ count = 1 ; $ new = $ destination ; // Add a suffix if the folder exists while ( is_dir ( $ this -> strRootDir . '/' . $ new ) && $ count < 12 ) { $ new = $ destination . '_' . $ count ++ ; } $ destination = $ new ; $ this -> Files -> rcopy ( $ source , $ destination ) ; } // Copy a file else { $ count = 1 ; $ new = $ destination ; $ ext = strtolower ( substr ( $ destination , strrpos ( $ destination , '.' ) + 1 ) ) ; // Add a suffix if the file exists while ( file_exists ( $ this -> strRootDir . '/' . $ new ) && $ count < 12 ) { $ 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 copied to "' . $ destination . '"' , __METHOD__ , TL_FILES ) ; // Redirect if ( ! $ blnDoNotRedirect ) { // Switch to edit mode if ( is_file ( $ this -> strRootDir . '/' . $ destination ) ) { $ this -> redirect ( $ this -> switchToEdit ( $ destination ) ) ; } $ this -> redirect ( $ this -> getReferer ( ) ) ; } }
Recursively duplicate files and folders

@param string $source
@param string $destination

@throws AccessDeniedException
@throws InternalServerErrorException
Recursively duplicate files and folders