diff --git a/core/lib/Thelia/Config/Resources/export.xml b/core/lib/Thelia/Config/Resources/export.xml index b212b8dbc..9d7bf8949 100644 --- a/core/lib/Thelia/Config/Resources/export.xml +++ b/core/lib/Thelia/Config/Resources/export.xml @@ -13,6 +13,10 @@ Products Produits + + Content + Contenu + @@ -64,5 +68,20 @@ + + + + Contents and folder + + Export your contents and their related folders + + + + Contenus et dossiers + + Exportez vos contenus et les dossiers associƩs + + + diff --git a/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/TarArchiveBuilder.php b/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/TarArchiveBuilder.php index b455a6e0b..99b6dcded 100644 --- a/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/TarArchiveBuilder.php +++ b/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/TarArchiveBuilder.php @@ -72,8 +72,14 @@ class TarArchiveBuilder extends AbstractArchiveBuilder */ public function addFile($filePath, $directoryInArchive = "/", $name = null, $isOnline = false) { + if (!empty($name)) { + $directoryInArchive .= DS . dirname($name); + } + if (empty($name) || !is_scalar($name)) { $name = basename($filePath); + } else { + $name = basename($name); } /** diff --git a/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/TarGzArchiveBuilder.php b/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/TarGzArchiveBuilder.php index b8519c539..bdb95e432 100644 --- a/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/TarGzArchiveBuilder.php +++ b/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/TarGzArchiveBuilder.php @@ -34,14 +34,10 @@ class TarGzArchiveBuilder extends TarArchiveBuilder return "tar.gz"; } - public function setEnvironment($environment) + protected function compressionEntryPoint() { - parent::setEnvironment($environment); - - $this->previousFile = $this->cacheFile; - if ($this->compression != \Phar::GZ) { - $this->tar = $this->tar->compress(\Phar::BZ2, $this->getExtension()); + $this->tar = $this->tar->compress(\Phar::GZ, $this->getExtension()); } $this->compression = \Phar::GZ; diff --git a/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/ZipArchiveBuilder.php b/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/ZipArchiveBuilder.php index ab31d2a51..dcaac183e 100644 --- a/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/ZipArchiveBuilder.php +++ b/core/lib/Thelia/Core/FileFormat/Archive/ArchiveBuilder/ZipArchiveBuilder.php @@ -74,6 +74,10 @@ class ZipArchiveBuilder extends AbstractArchiveBuilder */ public function addFile($filePath, $directoryInArchive = null, $name = null, $isOnline = false) { + if (!empty($name)) { + $directoryInArchive .= DS . dirname($name) ; + } + $directoryInArchive = $this->formatDirectoryPath($directoryInArchive); /** @@ -86,6 +90,8 @@ class ZipArchiveBuilder extends AbstractArchiveBuilder if (empty($name) || !is_scalar($name)) { $name = basename($filePath); + } else { + $name = basename($name); } /** @@ -178,7 +184,10 @@ class ZipArchiveBuilder extends AbstractArchiveBuilder $directoryInArchive = $this->formatDirectoryPath($directoryPath); if (!empty($directoryInArchive)) { - if (!$this->zip->addEmptyDir($directoryInArchive)) { + $this->zip->addEmptyDir($directoryInArchive); + $this->commit(); + + if (!$this->hasDirectory($directoryInArchive)) { throw new \ErrorException( $this->translator->trans( "The directory %dir has not been created in the archive", diff --git a/core/lib/Thelia/Core/FileFormat/Formatting/Formatter/CSVFormatter.php b/core/lib/Thelia/Core/FileFormat/Formatting/Formatter/CSVFormatter.php index b8ef4b69d..af977be57 100644 --- a/core/lib/Thelia/Core/FileFormat/Formatting/Formatter/CSVFormatter.php +++ b/core/lib/Thelia/Core/FileFormat/Formatting/Formatter/CSVFormatter.php @@ -116,7 +116,9 @@ class CSVFormatter extends AbstractFormatter ksort($row); foreach ($keys as $key) { - $string .= $this->formatField($row[$key]); + if (array_key_exists($key, $row)) { + $string .= $this->formatField($row[$key]); + } } $string = substr($string,0, -$delimiterLength) . $this->lineReturn; diff --git a/core/lib/Thelia/ImportExport/Export/Type/ContentExport.php b/core/lib/Thelia/ImportExport/Export/Type/ContentExport.php new file mode 100644 index 000000000..8c6ddcaae --- /dev/null +++ b/core/lib/Thelia/ImportExport/Export/Type/ContentExport.php @@ -0,0 +1,303 @@ + + */ +class ContentExport extends ExportHandler implements + ImagesExportInterface, + DocumentsExportInterface +{ + const DIRECTORY_NAME = "content"; + + /** + * @return string|array + * + * Define all the type of formatters that this can handle + * return a string if it handle a single type ( specific exports ), + * or an array if multiple. + * + * Thelia types are defined in \Thelia\Core\FileFormat\FormatType + * + * example: + * return array( + * FormatType::TABLE, + * FormatType::UNBOUNDED, + * ); + */ + public function getHandledTypes() + { + return array( + FormatType::TABLE, + FormatType::UNBOUNDED, + ); + } + + /** + * @param Lang $lang + * @return ModelCriteria|array|BaseLoop + */ + public function buildDataSet(Lang $lang) + { + $locale = $lang->getLocale(); + + $contentI18nJoin = new Join(ContentTableMap::ID, ContentI18nTableMap::ID, Criteria::LEFT_JOIN); + $folderI18nJoin = new Join(FolderTableMap::ID, FolderI18nTableMap::ID, Criteria::LEFT_JOIN); + $urlJoin = new Join(ContentTableMap::ID, RewritingUrlTableMap::VIEW_ID, Criteria::LEFT_JOIN); + + + $query = ContentQuery::create() + ->_if($this->isImageExport()) + ->useContentImageQuery("content_image_join", Criteria::LEFT_JOIN) + ->addAsColumn("content_IMAGES", "GROUP_CONCAT(DISTINCT `content_image_join`.FILE)") + ->endUse() + ->_endif() + ->_if($this->isDocumentExport()) + ->useContentDocumentQuery() + ->addAsColumn("content_DOCUMENTS", "GROUP_CONCAT(DISTINCT ".ContentDocumentTableMap::FILE.")") + ->endUse() + ->_endif() + ->useContentFolderQuery(null, Criteria::LEFT_JOIN) + ->useFolderQuery(null, Criteria::LEFT_JOIN) + ->_if($this->isDocumentExport()) + ->useFolderDocumentQuery() + ->addAsColumn("folder_DOCUMENTS", "GROUP_CONCAT(DISTINCT ".FolderDocumentTableMap::FILE.")") + ->endUse() + ->_endif() + ->_if($this->isImageExport()) + ->useFolderImageQuery(null, Criteria::LEFT_JOIN) + ->addAsColumn("folder_IMAGES", "GROUP_CONCAT(DISTINCT ".FolderImageTableMap::FILE.")") + ->endUse() + ->_endif() + ->addJoinObject($folderI18nJoin, "folder_i18n_join") + ->addJoinCondition("folder_i18n_join", FolderI18nTableMap::LOCALE . "=" . $this->real_escape($locale)) + ->addAsColumn("folder_TITLE", FolderI18nTableMap::TITLE) + ->addAsColumn("folder_ID", FolderTableMap::ID) + ->endUse() + ->endUse() + ->addJoinObject($contentI18nJoin, "content_i18n_join") + ->addJoinCondition("content_i18n_join", ContentI18nTableMap::LOCALE . "=" . $this->real_escape($locale)) + ->addAsColumn("content_TITLE", ContentI18nTableMap::TITLE) + ->addAsColumn("content_CHAPO", ContentI18nTableMap::CHAPO) + ->addAsColumn("content_DESCRIPTION", ContentI18nTableMap::DESCRIPTION) + ->addAsColumn("content_CONCLUSION", ContentI18nTableMap::POSTSCRIPTUM) + ->addAsColumn("content_seo_TITLE", ContentI18nTableMap::META_TITLE) + ->addAsColumn("content_seo_DESCRIPTION", ContentI18nTableMap::META_DESCRIPTION) + ->addAsColumn("content_seo_KEYWORDS", ContentI18nTableMap::META_KEYWORDS) + ->addJoinObject($urlJoin, "url_rewriting_join") + ->addJoinCondition( + "url_rewriting_join", + RewritingUrlTableMap::VIEW . "=" . + $this->real_escape((new Content())->getRewrittenUrlViewName()) + ) + ->addJoinCondition( + "url_rewriting_join", + RewritingUrlTableMap::VIEW_LOCALE . "=" . $this->real_escape($locale) + ) + ->addAsColumn("url_URL", RewritingUrlTableMap::URL) + ->select([ + ContentTableMap::ID, + ContentTableMap::VISIBLE, + "content_TITLE", + "content_CHAPO", + "content_DESCRIPTION", + "content_CONCLUSION", + "content_seo_TITLE", + "content_seo_DESCRIPTION", + "content_seo_KEYWORDS", + "url_URL", + "folder_TITLE", + "folder_ID", + ]) + ->groupBy(ContentTableMap::ID) + ->groupBy("folder_ID") + ; + + /** + * @var ContentQuery $query + */ + if ($this->isDocumentExport()) { + $query->select($query->getSelect() + [ + "folder_DOCUMENTS", + "content_DOCUMENTS", + ]); + } + + /** + * @var ContentQuery $query + */ + if ($this->isImageExport()) { + $query->select($query->getSelect() + [ + "folder_IMAGES", + "content_IMAGES", + ]); + } + + $dataSet = $query + ->find() + ->toArray() + ; + + $previous = null; + foreach ($dataSet as &$line) { + if ($previous === null || $previous !== $line[ContentTableMap::ID]) { + $previous = $line[ContentTableMap::ID]; + } else { + /** + * Do not repeat content values + */ + $line["content_TITLE"] = ""; + $line["content_VISIBLE"] = ""; + $line["content_CHAPO"] = ""; + $line["content_DESCRIPTION"] = ""; + $line["content_CONCLUSION"] = ""; + $line["content_seo_TITLE"] = ""; + $line["content_seo_DESCRIPTION"] = ""; + $line["content_seo_KEYWORDS"] = ""; + $line["url_URL"] = ""; + $line["content_IMAGES"] = ""; + $line["content_DOCUMENTS"] = ""; + + if (isset($line["content_IMAGES"])) { + $line["content_IMAGES"] = ""; + } + + if (isset($line["content_DOCUMENTS"])) { + $line["content_IMAGES"] = ""; + } + } + } + + return $dataSet; + } + + protected function getDefaultOrder() + { + return [ + "id", + "title", + "chapo", + "description", + "conclusion", + "visible", + "seo_title", + "seo_description", + "seo_keywords", + "url", + "folder_id", + "folder_title", + ]; + } + + protected function getAliases() + { + return [ + ContentTableMap::ID => "id", + ContentTableMap::VISIBLE => "visible", + "content_TITLE" => "title", + "content_CHAPO" => "chapo", + "content_DESCRIPTION" => "description", + "content_CONCLUSION" => "conclusion", + "content_seo_TITLE" => "seo_title", + "content_seo_DESCRIPTION" => "seo_description", + "content_seo_KEYWORDS" => "seo_keywords", + "url_URL" => "url", + "folder_TITLE" => "folder_title", + "folder_ID" => "folder_id", + ]; + } + + + /** + * @return array + * + * return an array with the paths to the documents to include in the archive + */ + public function getDocumentsPaths() + { + $documentPaths = []; + + $folderDocuments = FolderDocumentQuery::create() + ->find(); + /** @var \Thelia\Model\FolderDocument $folderDocument */ + foreach ($folderDocuments as $folderDocument) { + $this->addFileToArray($folderDocument, $documentPaths); + + } + + $contentDocuments = ContentDocumentQuery::create() + ->find(); + + /** @var \Thelia\Model\ContentDocument $contentDocument */ + foreach ($contentDocuments as $contentDocument) { + $this->addFileToArray($contentDocument, $documentPaths); + } + + return $documentPaths; + } + + /** + * @return array + * + * return an array with the paths to the images to include in the archive + */ + public function getImagesPaths() + { + $imagePaths = []; + + $folderImages = FolderImageQuery::create() + ->find(); + + /** @var \Thelia\Model\FolderDocument $folderImage */ + foreach ($folderImages as $folderImage) { + $this->addFileToArray($folderImage, $imagePaths); + } + + $contentImages = ContentImageQuery::create() + ->find(); + + /** @var \Thelia\Model\ContentImage $contentImage */ + foreach ($contentImages as $contentImage) { + $this->addFileToArray($contentImage, $imagePaths); + } + + return $imagePaths; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Tests/ImportExport/Export/ContentExportTest.php b/core/lib/Thelia/Tests/ImportExport/Export/ContentExportTest.php new file mode 100644 index 000000000..827b11408 --- /dev/null +++ b/core/lib/Thelia/Tests/ImportExport/Export/ContentExportTest.php @@ -0,0 +1,138 @@ + + */ +class ContentExportTest extends \PHPUnit_Framework_TestCase +{ + protected $lang; + + /** @var ContentExport */ + protected $handler; + + public function setUp() + { + new Translator(new Container()); + + $this->lang = Lang::getDefaultLanguage(); + $this->handler = new ContentExport(new Container()); + } + + public function testQuery() + { + $data = $this->handler->buildData($this->lang)->getData(); + + $max = count($data); + if ($max > 50) { + $max = 50; + } + + for ($i = 0; $i < $max;) { + $content = ContentQuery::create()->findPk($data[$i]["id"]); + + $this->assertNotNull($content); + + $this->assertEquals($content->getTitle(), $data[$i]["title"]); + $this->assertEquals($content->getDescription(), $data[$i]["description"]); + $this->assertEquals($content->getChapo(), $data[$i]["chapo"]); + $this->assertEquals($content->getPostscriptum(), $data[$i]["conclusion"]); + $this->assertEquals($content->getMetaTitle(), $data[$i]["seo_title"]); + $this->assertEquals($content->getMetaDescription(), $data[$i]["seo_description"]); + $this->assertEquals($content->getMetaKeywords(), $data[$i]["seo_keywords"]); + + + do { + if (null !== $data[$i]["folder_id"]) { + $folder = FolderQuery::create()->findPk($data[$i]["folder_id"]); + + $this->assertNotNull($folder); + + $contentFolder = ContentFolderQuery::create() + ->filterByContent($content) + ->filterByFolder($folder) + ->findOne() + ; + + $this->assertNotNull($contentFolder); + + $this->assertEquals( + $folder->getTitle(), + $data[$i]["folder_title"] + ); + } + } while ( + isset($data[++$i]["id"]) && + $data[$i-1]["id"] === $data[$i]["id"] && + ++$max + ); + } + } + + public function testQueryImages() + { + $data = $this->handler + ->setImageExport(true) + ->buildData($this->lang) + ->getData() + ; + + $max = count($data); + if ($max > 50) { + $max = 50; + } + + for ($i = 0; $i < $max; ++$i) { + $images = ContentImageQuery::create() + ->filterByContentId($data[$i]["id"]) + ->select(ContentImageTableMap::FILE) + ->find() + ->toArray() + ; + + $imagesString = implode(",", $images); + + $this->assertEquals($imagesString, $data[$i]["content_images"]); + + $folderImages = FolderImageQuery::create() + ->useFolderQuery() + ->useContentFolderQuery() + ->filterByContentId($data[$i]["id"]) + ->endUse() + ->endUse() + ->select(FolderImageTableMap::FILE) + ->find() + ->toArray() + ; + + $folderImages = implode(",", $folderImages); + + $this->assertEquals($folderImages, $data[$i]["folder_images"]); + } + } +} \ No newline at end of file