* @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Media\Api\Model; \defined('_JEXEC') or die; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\Exception\ResourceNotFound; use Joomla\CMS\MVC\Controller\Exception\Save; use Joomla\CMS\MVC\Model\BaseModel; use Joomla\Component\Media\Administrator\Exception\FileExistsException; use Joomla\Component\Media\Administrator\Exception\FileNotFoundException; use Joomla\Component\Media\Administrator\Exception\InvalidPathException; use Joomla\Component\Media\Administrator\Model\ApiModel; use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait; /** * Media web service model supporting a single media item. * * @since 4.1.0 */ class MediumModel extends BaseModel { use ProviderManagerHelperTrait; /** * Instance of com_media's ApiModel * * @var ApiModel * @since 4.1.0 */ private $mediaApiModel; public function __construct($config = []) { parent::__construct($config); $this->mediaApiModel = new ApiModel(); } /** * Method to get a single files or folder. * * @return \stdClass A file or folder object. * * @since 4.1.0 * @throws ResourceNotFound */ public function getItem() { $options = [ 'path' => $this->getState('path', ''), 'url' => $this->getState('url', false), 'temp' => $this->getState('temp', false), 'content' => $this->getState('content', false), ]; ['adapter' => $adapterName, 'path' => $path] = $this->resolveAdapterAndPath($this->getState('path', '')); try { return $this->mediaApiModel->getFile($adapterName, $path, $options); } catch (FileNotFoundException $e) { throw new ResourceNotFound( Text::sprintf('WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND', $path), 404 ); } } /** * Method to save a file or folder. * * @param string $path The primary key of the item (if exists) * * @return string The path * * @since 4.1.0 * * @throws Save */ public function save($path = null): string { $path = $this->getState('path', ''); $oldPath = $this->getState('old_path', ''); $content = $this->getState('content', null); $override = $this->getState('override', false); ['adapter' => $adapterName, 'path' => $path] = $this->resolveAdapterAndPath($path); // Trim adapter information from path if ($pos = strpos($path, ':/')) { $path = substr($path, $pos + 1); } // Trim adapter information from old path if ($pos = strpos($oldPath, ':/')) { $oldPath = substr($oldPath, $pos + 1); } $resultPath = ''; /** * If we have a (new) path and an old path, we want to move an existing * file or folder. This must be done before updating the content of a file, * if also requested (see below). */ if ($path && $oldPath) { try { // ApiModel::move() (or actually LocalAdapter::move()) returns a path with leading slash. $resultPath = trim( $this->mediaApiModel->move($adapterName, $oldPath, $path, $override), '/' ); } catch (FileNotFoundException $e) { throw new Save( Text::sprintf( 'WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND', $oldPath ), 404 ); } } // If we have a (new) path but no old path, we want to create a // new file or folder. if ($path && !$oldPath) { // com_media expects separate directory and file name. // If we moved the file before, we must use the new path. $basename = basename($resultPath ?: $path); $dirname = dirname($resultPath ?: $path); try { // If there is content, com_media's assumes the new item is a file. // Otherwise a folder is assumed. $name = $content ? $this->mediaApiModel->createFile( $adapterName, $basename, $dirname, $content, $override ) : $this->mediaApiModel->createFolder( $adapterName, $basename, $dirname, $override ); $resultPath = $dirname . '/' . $name; } catch (FileNotFoundException $e) { throw new Save( Text::sprintf( 'WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND', $dirname . '/' . $basename ), 404 ); } catch (FileExistsException $e) { throw new Save( Text::sprintf( 'WEBSERVICE_COM_MEDIA_FILE_EXISTS', $dirname . '/' . $basename ), 400 ); } catch (InvalidPathException $e) { throw new Save( Text::sprintf( 'WEBSERVICE_COM_MEDIA_BAD_FILE_TYPE', $dirname . '/' . $basename ), 400 ); } } // If we have no (new) path but we do have an old path and we have content, // we want to update the contents of an existing file. if ($oldPath && $content) { // com_media expects separate directory and file name. // If we moved the file before, we must use the new path. $basename = basename($resultPath ?: $oldPath); $dirname = dirname($resultPath ?: $oldPath); try { $this->mediaApiModel->updateFile( $adapterName, $basename, $dirname, $content ); } catch (FileNotFoundException $e) { throw new Save( Text::sprintf( 'WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND', $dirname . '/' . $basename ), 404 ); } catch (InvalidPathException $e) { throw new Save( Text::sprintf( 'WEBSERVICE_COM_MEDIA_BAD_FILE_TYPE', $dirname . '/' . $basename ), 400 ); } $resultPath = $resultPath ?: $oldPath; } // If we still have no result path, something fishy is going on. if (!$resultPath) { throw new Save( Text::_( 'WEBSERVICE_COM_MEDIA_UNSUPPORTED_PARAMETER_COMBINATION' ), 400 ); } return $resultPath; } /** * Method to delete an existing file or folder. * * @return void * * @since 4.1.0 * @throws Save */ public function delete(): void { ['adapter' => $adapterName, 'path' => $path] = $this->resolveAdapterAndPath($this->getState('path', '')); try { $this->mediaApiModel->delete($adapterName, $path); } catch (FileNotFoundException $e) { throw new Save( Text::sprintf('WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND', $path), 404 ); } } }