Skip to content

Instantly share code, notes, and snippets.

@atsu666
Created January 19, 2022 10:13
Show Gist options
  • Save atsu666/119c1644588725573a7dc8ce06f73e79 to your computer and use it in GitHub Desktop.
Save atsu666/119c1644588725573a7dc8ce06f73e79 to your computer and use it in GitHub Desktop.
php/Services/StaticExport/Engine.php
<?php
namespace Acms\Services\StaticExport;
use App;
use DB;
use SQL;
use ACMS_Filter;
use Acms\Services\Facades\Storage;
use Acms\Services\StaticExport\Generator\TopGenerator;
use Acms\Services\StaticExport\Generator\ThemeGenerator;
use Acms\Services\StaticExport\Generator\RequireThemeGenerator;
use Acms\Services\StaticExport\Generator\CategoryGenerator;
use Acms\Services\StaticExport\Generator\CategoryPageGenerator;
use Acms\Services\StaticExport\Generator\CategoryArchivesGenerator;
use Acms\Services\StaticExport\Generator\EntryGenerator;
use Acms\Services\StaticExport\Generator\PageGenerator;
use Symfony\Component\Finder\Finder;
class Engine
{
/**
* @var \Acms\Services\StaticExport\Compiler
*/
protected $compiler;
/**
* @var \Acms\Services\StaticExport\Destination
*/
protected $destination;
/**
* @var \Acms\Services\StaticExport\TerminateCheck
*/
protected $terminateFlag;
/**
* @var \Acms\Services\StaticExport\Logger
*/
protected $logger;
/**
* @var \Symfony\Component\Finder\Finder
*/
protected $finder;
/**
* @var int
*/
protected $maxPublish;
/**
* @var \stdClass
*/
protected $config;
/**
* Engine constructor.
*/
public function __construct()
{
$this->finder = new Finder();
}
/**
* 初期設定
*
* @param \Acms\Services\StaticExport\Logger $logger
* @param \Acms\Services\StaticExport\Destination $destination
* @param int $maxPublish
* @param \Field $config
* @throws \Exception
*/
public function init($logger, $destination, $maxPublish, $config)
{
$this->logger = $logger;
$this->destination = $destination;
$this->maxPublish = $maxPublish;
$this->config = $config;
try {
if ( !is_writable($this->destination->getDestinationPath()) ) {
$this->logger->error('データの書き込みに失敗しました。', $this->destination->getDestinationPath());
}
$this->compiler = App::make('static-export.compiler');
$this->compiler->setDestination($this->destination);
} catch ( \Exception $e ) {
throw $e;
}
}
/**
* Run
*/
public function run()
{
$themes = $this->extractTheme($this->config->theme);
// アセットの書き出し
$this->processExportArchives();
// テーマのアセット書き出し
$this->processExportAssets($themes);
// css の url属性のパス解決
$this->processResolvCssPath($themes);
// テーマのテンプレート書き出し
$this->processExportTheme($themes);
// トップページの書き出し
DB::reconnect(dsn());
$this->processExportTop();
// ページの書き出し
DB::reconnect(dsn());
$this->processExportPagenation();
// カテゴリートップページの書き出し
DB::reconnect(dsn());
$this->processExportCategoryTop();
// エントリーの書き出し
DB::reconnect(dsn());
$this->processExportEntry();
// カテゴリーページの書き出し
DB::reconnect(dsn());
$this->processExportCategoryPagenation($this->config->static_page_cid);
// アーカイブページの書き出し
DB::reconnect(dsn());
$this->processExportArchivePage($this->config->static_archive_cid);
// 古いファイルの削除
$this->deleteOldFiles();
$this->logger->start('書き出し完了');
$this->logger->processing();
sleep(1);
$this->logger->destroy();
}
/**
* アーカイブの書き出し
*/
protected function processExportArchives()
{
$this->logger->start('アーカイブの書き出し');
$this->logger->processing();
$this->copyArchives();
}
/**
* テーマのアセット書き出し
*
* @param array $themes
*/
protected function processExportAssets($themes)
{
$this->copyThemeItems(THEMES_DIR . 'system/');
$this->copyThemeRequireItems(THEMES_DIR . 'system/');
foreach ( $themes as $theme ) {
$path = THEMES_DIR . $theme . '/';
$this->copyThemeItems($path);
$this->copyThemeRequireItems($path);
}
}
/**
* css の url属性のパス解決
*
* @param array $themes
*/
protected function processResolvCssPath($themes)
{
$this->resolvePathInCss(THEMES_DIR . 'system/');
foreach ( $themes as $theme ) {
$path = THEMES_DIR . $theme . '/';
$this->resolvePathInCss($path);
}
}
/**
* テーマのテンプレート書き出し
*
* @param array $themes
*/
protected function processExportTheme($themes)
{
foreach ( $themes as $theme ) {
$path = THEMES_DIR . $theme . '/';
$themeGenerator = new ThemeGenerator($this->compiler, $this->destination, $this->logger, $this->maxPublish);
$themeGenerator->setSourceTheme($path);
$themeGenerator->setExclusionList($this->config->exclusion_list);
$themeGenerator->run();
$themeGenerator = new RequireThemeGenerator($this->compiler, $this->destination, $this->logger, $this->maxPublish);
$themeGenerator->setSourceTheme($path);
$themeGenerator->setIncludeList($this->config->include_list);
$themeGenerator->run();
}
}
/**
* トップページの書き出し
*/
protected function processExportTop()
{
$generator = new TopGenerator($this->compiler, $this->destination, $this->logger, $this->maxPublish);
$generator->setExclusionList($this->config->exclusion_list);
$generator->run();
}
/**
* カテゴリートップの書き出し
*/
protected function processExportCategoryTop()
{
$SQL = SQL::newSelect('category');
$SQL->setSelect('category_id');
$SQL->addLeftJoin('blog', 'blog_id', 'category_blog_id');
ACMS_Filter::blogTree($SQL, BID, 'ancestor-or-self');
ACMS_Filter::categoryStatus($SQL);
$Where = SQL::newWhere();
$Where->addWhereOpr('category_blog_id', BID, '=', 'OR');
$Where->addWhereOpr('category_scope', 'global', '=', 'OR');
$SQL->addWhere($Where);
$target = DB::query($SQL->get(dsn()), 'list');
$generator = new CategoryGenerator($this->compiler, $this->destination, $this->logger, $this->maxPublish);
$generator->setTargetCategories($target);
$generator->run();
}
/**
* エントリーの書き出し
*/
protected function processExportEntry()
{
$SQL = SQL::newSelect('entry');
$SQL->setSelect('entry_id');
$SQL->addLeftJoin('blog', 'blog_id', 'entry_blog_id');
$SQL->addWhereOpr('entry_blog_id', BID);
$SQL->addWhereOpr('entry_status', 'open');
$target = DB::query($SQL->get(dsn()), 'list');
$generator = new EntryGenerator($this->compiler, $this->destination, $this->logger, $this->maxPublish);
$generator->setTargetEntries($target);
$generator->run();
}
/**
* ページの書き出し
*/
protected function processExportPagenation()
{
$this->logger->start('2ページ以降を生成');
if (!empty($this->config->static_export_dafault_max_page)) {
$this->logger->processing();
$generator = new PageGenerator($this->compiler, $this->destination, null, $this->maxPublish);
$generator->setMaxPage($this->config->static_export_dafault_max_page);
$generator->run(true);
}
}
/**
* カテゴリーページの書き出し
*
* @param array $categories
*/
protected function processExportCategoryPagenation($categories)
{
if (is_array($categories) && count($categories) > 0) {
$this->logger->start('カテゴリーの2ページ以降を生成', count($categories));
foreach ($categories as $i => $cid) {
// カテゴリーのページを書き出し
$this->logger->processing();
$generator = new CategoryPageGenerator($this->compiler, $this->destination, null, $this->maxPublish);
$generator->setCategoryId($cid);
$generator->setMaxPage($this->getConfig('static_page_max', 5, $i));
$generator->run(true);
}
}
}
/**
* アーカイブページの書き出し
*
* @param array $categories
*/
protected function processExportArchivePage($categories)
{
if (is_array($categories) && count($categories) > 0) {
foreach ($categories as $i => $cid) {
try {
$generator = new CategoryArchivesGenerator($this->compiler, $this->destination, $this->logger, $this->maxPublish);
$generator->setCategoryId($cid);
$generator->setMonthRange($this->getConfig('static_archive_start', date('Y-m-d', REQUEST_TIME), $i));
$generator->setMaxPage($this->getConfig('static_archive_max', 5, $i));
$generator->run();
} catch (\Exception $e) {
$this->logger->error($e->getMessage(), $e->getFile() . ':' . $e->getLine());
}
}
}
}
/**
* copy archives
*
* @return void
*/
protected function copyArchives()
{
$blog_archives_dir = sprintf('%03d', BID);
$src_archives_dir = ARCHIVES_DIR . $blog_archives_dir;
$dest_archives_dir = $this->destination->getDestinationPath() . ARCHIVES_DIR . $blog_archives_dir;
Storage::copyDirectory($src_archives_dir, $dest_archives_dir);
$src_media_dir = MEDIA_LIBRARY_DIR;
$dest_media_dir = $this->destination->getDestinationPath() . MEDIA_LIBRARY_DIR;
Storage::copyDirectory($src_media_dir, $dest_media_dir);
$src_storage_dir = MEDIA_STORAGE_DIR;
$dest_storage_dir = $this->destination->getDestinationPath() . MEDIA_STORAGE_DIR;
Storage::copyDirectory($src_storage_dir, $dest_storage_dir);
Storage::remove($this->destination->getDestinationPath() . MEDIA_STORAGE_DIR . '.htaccess');
Storage::copyDirectory(JS_DIR, $this->destination->getDestinationPath() . JS_DIR);
Storage::copy('acms.js', $this->destination->getDestinationPath() . 'acms.js');
}
/**
* copy theme items
*
* @param string $theme
* @return void
*/
protected function copyThemeItems($theme)
{
if (empty($theme)) {
return;
}
$finder = new Finder();
$iterator = $finder
->in($theme)
->name('/\.(js|json|css|ttf|img|png|gif|jpeg|jpg|svg|txt|pdf|ppt|xls|csv|docx|pptx|xlsx|zip)$/')
->exclude('acms-code')
->exclude('admin');
if (property_exists($this->config, 'exclusion_list')) {
foreach ($this->config->exclusion_list as $path) {
if (!empty($path)) {
$iterator->notPath(trim($path, '/'));
}
}
}
$iterator->files();
$this->logger->start('テーマのリソース書き出し ( ' . $theme . ' )', iterator_count($iterator));
foreach ($iterator as $file) {
try {
$relative_dir_path = $file->getRelativePath();
$relative_file_path = $file->getRelativePathname();
$this->logger->processing();
Storage::makeDirectory($this->destination->getDestinationPath() . $this->destination->getBlogCode() . $relative_dir_path);
Storage::copy($theme . $relative_file_path, $this->destination->getDestinationPath() . $this->destination->getBlogCode() . $relative_file_path);
} catch ( \Exception $e ) {
$this->logger->error($e->getMessage(), $file->getRelativePathname());
}
}
}
/**
* copy theme require items
*
* @param string $theme
* @return void
*/
protected function copyThemeRequireItems($theme)
{
if (empty($theme)) {
return;
}
if (property_exists($this->config, 'include_list')) {
$includeList = array();
foreach ($this->config->include_list as $path) {
if (!empty($path)) {
$includeList[] = trim($path, '/');
}
}
if (count($includeList) > 0) {
$finder = new Finder();
$iterator = $finder->in($theme);
foreach ($includeList as $path) {
$iterator->path($path);
}
$iterator->files();
$this->logger->start('テーマの必須リソース書き出し ( ' . $theme . ' )', iterator_count($iterator));
foreach ($iterator as $file) {
try {
$relative_dir_path = $file->getRelativePath();
$relative_file_path = $file->getRelativePathname();
$this->logger->processing();
Storage::makeDirectory($this->destination->getDestinationPath() . $this->destination->getBlogCode() . $relative_dir_path);
Storage::copy($theme . $relative_file_path, $this->destination->getDestinationPath() . $this->destination->getBlogCode() . $relative_file_path);
} catch ( \Exception $e ) {
$this->logger->error($e->getMessage(), $file->getRelativePathname());
}
}
}
}
}
/**
* css の url属性のパス解決
*
* @param string $theme
* @return void
*/
protected function resolvePathInCss($theme)
{
$finder = new Finder();
$iterator = $finder
->in($theme)
->name('/\.css$/')
->exclude('acms-code')
->exclude('admin');
if (property_exists($this->config, 'exclusion_list')) {
foreach ($this->config->exclusion_list as $path) {
if (!empty($path)) {
$iterator->notPath(trim($path, '/'));
}
}
}
$iterator->files();
$this->logger->start('CSSのURL属性を解決 ( ' . $theme . ' )', iterator_count($iterator));
foreach ( $iterator as $file ) {
$relative_file_path = $file->getRelativePathname();
$this->logger->processing($relative_file_path);
if ( $file->isReadable() ) {
$data = Storage::get($theme . $relative_file_path);
if ( $data = $this->compiler->compile($data) ) {
Storage::put($this->destination->getDestinationPath() . $this->destination->getBlogCode() . $relative_file_path, $data);
}
}
}
}
/**
* delete files
*
* @return void
*/
protected function deleteOldFiles()
{
$finder = new Finder();
$iterator = $finder
->in($this->destination->getDestinationPath() . $this->destination->getBlogCode())
->notPath(ARCHIVES_DIR)
->date('< ' . date('Y-m-d H:i:s', REQUEST_TIME));
$SQL = SQL::newSelect('blog');
$SQL->addSelect('blog_code');
$SQL->addWhereOpr('blog_parent', BID);
$all = DB::query($SQL->get(dsn()), 'all');
foreach ($all as $blog) {
if ($bcd = $blog['blog_code']) {
$iterator->notPath($bcd);
}
}
if (property_exists($this->config, 'delete_exclusion_list')) {
foreach ($this->config->delete_exclusion_list as $path) {
if (!empty($path)) {
$iterator->notPath($path);
}
}
}
$iterator->files();
$this->logger->start('古いファイルを削除', iterator_count($iterator));
foreach ( $iterator as $file ) {
$this->logger->processing();
$path = $this->destination->getDestinationPath() . $file->getRelativePathname();
Storage::remove($path);
}
}
/**
* get themes
*
* @param string $theme
* @return array
*/
protected function extractTheme($theme)
{
$theme = trim($theme, '@');
$themes[] = $theme;
while ( $pos = strpos($theme, '@') ) {
$theme = substr($theme, $pos + 1);
$themes[] = $theme;
}
return array_reverse(array_unique($themes));
}
protected function getConfig($key, $default, $i)
{
if (property_exists($this->config, $key)) {
$array = $this->config->$key;
if (isset($array[$i])) {
return $array[$i];
}
}
return $default;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment