<?php
namespace AppBundle\Controller\Admin\Base;
use AppBundle\Component\PageBuilder\Event\OnCommitEvent;
use AppBundle\Component\Util\ButtonSection;
use AppBundle\Entity\Approval\ApprovalRequest;
use AppBundle\Entity\Master\Language;
use AppBundle\Event\Approval\RequestCreatedEvent;
use AppBundle\Event\PageBuilderInitializedEvent;
use AppBundle\Repository\ApprovalRequestRepository;
use Doctrine\ORM\Query\FilterCollection;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\DependencyInjection\Container;
use AppBundle\Controller\Admin\Base\BaseController;
use AppBundle\Component\PageBuilder\PageBuilder;
class MasterBaseController extends BaseController
{
public function before(FilterControllerEvent $event)
{
parent::before($event);
}
public function indexAction(Request $request)
{
$settings = $this->entity_settings;
if ($settings->get('single')) {
$entity = $this->findOneEntity($this->models['item'], ['post_type']);
$langParent = ($entity && method_exists($entity, 'getLanguageParent')) ? $entity->getLanguageParent() : null;
if($entity && !empty($langParent)){
$entity = $this->findOneEntity($this->models['item'], ['id' => $langParent]);
}
if ($entity) {
return $this->redirectToRoute($this->routes['edit'], array_merge($this->base_route_params, ['id' => $entity->getId()]));
} else {
return $this->redirectToRoute($this->routes['new'], $this->base_route_params);
}
}
$data_table_options = $this->getListDataTableOptions();
$criteria = $request->query->get('criteria', []);
if (isset($data_table_options['ajax']['url']) && !empty($criteria)) {
$data_table_options['ajax']['url'] = $this->appendParamsToUrl($data_table_options['ajax']['url'],
['criteria' => $criteria]);
}
return $this->render($this->views['index'], [
'meta' => $this->meta('INDEX'),
'data_table_options' => $data_table_options,
'button_sections' => isset($this->button_sections['index']) ? $this->button_sections['index'] : [],
'search_form' => $this->buildSearchForm([], [
'criteria' => $criteria
])->createView(),
]);
}
public function jsonAction(Request $request)
{
$data = [];
$doctrine = $this->getDoctrine();
$em = $doctrine->getManager();
$filters = $em->getFilters();
// 下書きの表示を許可
if($filters->isEnabled('post_type')){
$postTypeFilter = $filters->getFilter('post_type');
$postTypeFilter->setAllowedTypes(['master', 'master:draft', 'master:unapproved', 'master:rejected']);
} else {
$postTypeFilter = null;
}
$repository = $em->getRepository($this->models['item']);
$criteria = $this->base_criteria + $request->query->get('criteria', []);
if ($this->entity_settings->isMultilingual()) {
// 言語フィルタ設定
if (!empty($criteria['language'])) {
$langAlias = $criteria['language'];
}
else {
$langAlias = $this->container->getParameter('language.default', 'jp');
}
$em = $this->getDoctrine()->getManager();
$filter = $em->getFilters()->enable('language');
$filter->setParameter('language', $langAlias);
unset($criteria['language']);
}
// 空の検索条件を除外
$criteria = array_filter($criteria, function ($value) {
return $value !== '';
});
$columns = $request->query->get('columns');
$order = $request->query->get('order');
if (!empty($order)) {
$orderBy = [];
foreach ($order as $value) {
$column = $columns[$value['column']];
// スネークケースに変換
$field = Container::underscore($column['data']);
$orderBy[$field] = $value['dir'];
}
} else {
$orderBy = $this->getDefaultOrderBy();
}
$limit = $request->get("length", 10);
$offset = $request->get("start", 0);
if (-1 == $limit) {
$limit = $offset = null;
}
$entities = $repository->searchBy($criteria, $orderBy, $limit, $offset);
foreach ($entities as $entity) {
$data[] = $entity->toArray();
}
$recordsFiltered = $repository->countBy($criteria);
$recordsTotal = $repository->countBy($this->base_criteria);
//レスポンス(JSONで返す)
return new JsonResponse([
'data' => $data,
'recordsFiltered' => $recordsFiltered,
'recordsTotal' => $recordsTotal,
]);
}
public function newAction(Request $request)
{
$settings = $this->entity_settings;
if ($settings->isMultilingual()) {
return $this->multiLingualNewAction($request);
}
if ($settings->get('single')) {
$entity = $this->findOneEntity($this->models['item']);
$langParent = ($entity && method_exists($entity, 'getLanguageParent')) ? $entity->getLanguageParent() : null;
if($entity && !empty($langParent)){
$entity = $this->findOneEntity($this->models['item'], ['id' => $langParent]);
}
if ($entity) {
return $this->redirectToRoute(
$this->entity_settings->get('base_route') . "_edit",
['id' => $entity->getId()]
);
}
}
if($this->isGranted('approval_request_edit')){
$approval_required = false;
} else {
$approval_required = $settings->get('approval_required', false);
}
$preview_url = null;
$em = $this->getDoctrine()->getManager();
$entity = new $this->models['item']();
$builder = $this->createPageBuilder($this->form_class, null, 'new');
$this->pageBuilderOnLoad($builder);
$buttonAction = $request->request->get('_button_action', 'default');
if ($request->isMethod('post')) {
$referer = $request->headers->get('referer');
$violations = $builder->handleRequest($request);
$builder->initMediaUsageTracker();
// エラーがないとき
if (empty($violations)) {
$repo = $em->getRepository($this->models['item']);
$max = (method_exists($entity, 'getSortNum')) ? $repo->getMaxSortNum() : 0;
if ($buttonAction === 'preview') {
// プレビューの作成
$preview = $this->duplicateEntity($entity);
$preview->setRevisionParent($entity->getId());
$preview->setPostType('preview');
$blocks2 = array_map(function($block){
return clone $block;
}, $builder->getBlocks());
$builder->setBlocks($blocks2);
$builder->commit(OnCommitEvent::MODE_PREVIEW);
$formData = $builder->getData();
$formData = $this->filterFormData($formData, 'new');
$preview->bindFormData($formData);
$token = $this->generateAccessToken();
$preview->setAccessToken($token);
$this->save($em, $preview, $formData, self::SAVE_MODE_PREVIEW);
if($this->entity_settings->isRevisable()) {
$previewParams = [
'id' => $preview->getId()
];
$preview_url = $this->generateUrl($this->routes['preview'], array_merge($this->base_route_params, $previewParams));
} else {
$previewParams = [
'preview_id' => $preview->getId(),
'cms_token' => $token,
'cms_mode' => 'tmp_preview'
];
$preview_url = $this->getPreviewPageUrl($preview->getId(), $previewParams);
}
} else {
$builder->commit();
$formData = $builder->getData();
$formData = $this->filterFormData($formData, 'new');
$entity->bindFormData($formData);
$post_type = ('draft' === $buttonAction) ? 'master:draft' : 'master';
if(method_exists($entity, 'setPostType')){
if($approval_required && 'master' === $post_type){
$post_type = 'master:unapproved';
}
$entity->setPostType($post_type);
}
if (method_exists($entity, 'setSortNum')) {
$entity->setSortNum($max + 1);
}
if (method_exists($entity, 'setLanguageAlias')) {
$default_lang = ($this->container->hasParameter('language.default')) ? $this->container->getParameter('language.default') : 'jp';
$entity->setLanguageAlias($default_lang);
}
if (method_exists($entity, 'setLanguageActive')) {
$entity->setLanguageActive(true);
}
$this->save($em, $entity, $formData, self::SAVE_MODE_NEW, [
'flash_message' => $this->title . MSG_NEW_END
]);
$this->saveMediaUsages($entity);
if ($this->entity_settings->isRevisable()) {
$revision = $this->generateRevision($entity);
$revision->setPostType(('draft' === $buttonAction) ? 'draft' : 'revision');
$em->persist($revision);
$em->flush();
if($approval_required && $revision){
$approval_request = $this->createApprovalRequest($revision, ApprovalRequest::REQUEST_TYPE_CREATE, $this->getUser());
$em->persist($approval_request);
$em->flush();
$this->dispatcher->dispatch(RequestCreatedEvent::NAME, new RequestCreatedEvent($approval_request));
}
$this->saveMediaUsages($revision);
}
if($settings->get('single', false)){
return $this->redirectToRoute($this->routes['edit'], [
'id' => $entity->getId(),
'disable_redirect_suggestion' => true
]);
} else {
return $this->redirect($this->base_path);
}
}
}
}
return $this->render($this->views['edit'], [
'meta' => $this->meta('NEW'),
'builder' => $builder,
'preview_url' => $preview_url,
'redirect_url' => null,
'redirect_message' => null,
'entity' => null,
'master_entity' => null,
'post_type' => null,
'approval_required' => $approval_required,
'revisions' => [],
'revision_history' => [],
'approval_history' => [],
'button_sections' => isset($this->button_sections['new']) ? $this->button_sections['new'] : [],
'_pageBuilderParams' => $builder->getSharedParams(),
'_routes' => $this->routes,
'_base_route_params' => $this->base_route_params,
]);
}
public function multiLingualNewAction(Request $request)
{
$facility = 'master';
$translator = $this->container->get('translator');
$this->get('app.helper.script_loader')
->register('language-edit', CMS__ADMIN_PATH . 'js/pages/language-edit.js');
$settings = $this->entity_settings;
if($this->isGranted('approval_request_edit')){
$approval_required = false;
} else {
$approval_required = $settings->get('approval_required', false);
}
$languages = $this->getMasterLanguages();
$em = $this->getDoctrine()->getManager();
$default_lang = $this->container->getParameter('language.default', 'jp');
$selected_languages = $request->request->get('select_lang', []);
$active_language = $request->request->get('_active-language', null);
$violations = [];
$languageHeading = $this->getLanguagesHeading($languages);
// 言語ごとのbuilderを設定
$builders = $this->createPageBuilderLanguages($languages);
$preview_url = null;
$buttonAction = $request->request->get('_button_action', 'default');
$_pageBuilderParams = [];
foreach ($builders as $builder) {
$_pageBuilderParams += $builder->getSharedParams();
}
if ($request->isMethod('post')) {
$violations = $this->validateLanguages($request, $builders, $selected_languages, $buttonAction);
// エラーなし
if (empty($violations)) {
$parentEntity = null;
$revisionParentEntity = null;
/** @var Language $language */
foreach ($languages as $language) {
$alias = $language->getAlias();
$isParent = $language->isParent();
$prefix = $language->getTranslateKey() . '_';
$entity = new $this->models['item']();
$builder = $builders[$alias];
$repo = $em->getRepository($this->models['item']);
if($buttonAction === 'preview'){
if ($alias !== $active_language) {
continue;
}
$defaults = [
'language' => $language,
'parentEntity' => $parentEntity,
'alias' => $alias,
];
// プレビューの作成
$preview = $this->duplicateEntity($entity);
$preview->setRevisionParent(null);
$preview->setPostType('preview');
$this->setLanguageEntityDefault($preview, $defaults);
$blocks2 = array_map(function($block){
return clone $block;
}, $builder->getBlocks());
$builder->setBlocks($blocks2);
$builder->commit(OnCommitEvent::MODE_PREVIEW);
$formData = $builder->getData();
$formData = $this->filterFormDataLanguage($formData, 'new', $prefix);
$preview->bindFormData($formData);
$token = $this->generateAccessToken();
$preview->setAccessToken($token);
$this->save($em, $preview, $formData, self::SAVE_MODE_PREVIEW);
if($this->entity_settings->isRevisable()){
$previewParams = [
'id' => $preview->getId()
];
$preview_url = $this->generateUrl($this->routes['preview'], array_merge($this->base_route_params, $previewParams));
} else {
$previewParams = [
'preview_id' => $preview->getId(),
'cms_token' => $token,
'cms_mode' => 'tmp_preview',
'_locale' => $preview->getLanguageAlias()
];
$preview_url = $this->getPreviewPageUrl($facility, $preview->getId(), $previewParams);
}
} else {
$builder->commit();
$formData = $builder->getData();
$formData = $this->filterFormDataLanguage($formData, 'new', $prefix);
// 項目がない場合は日本語の入力値をセットする
if ($parentEntity) {
$this->setEntityParentLanguage($entity, $parentEntity, $this->form_class);
}
$entity->bindFormData($formData);
$post_type = ('draft' === $buttonAction) ? 'master:draft' : 'master';
$max = (method_exists($entity, 'getSortNum')) ? $repo->getMaxSortNumForLanguage($language, $isParent) : 0;
$defaults = [
'max' => $max,
'buttonAction' => $buttonAction,
'language' => $language,
'parentEntity' => $parentEntity,
'alias' => $alias,
'selected_languages' => $selected_languages
];
$this->setLanguageEntityDefault($entity, $defaults);
if(method_exists($entity, 'setPostType')){
if($approval_required && 'master' === $post_type){
$post_type = 'master:unapproved';
}
$entity->setPostType($post_type);
}
$this->save($em, $entity, $formData, self::SAVE_MODE_NEW, [
'builder' => $builder,
'language' => $language
]);
$this->saveMediaUsages($entity);
if ($isParent) {
$parentEntity = $entity;
}
if ($this->entity_settings->isRevisable()) {
$revision = $this->generateRevision($entity);
$revision->setPostType('revision');
if (is_null($revisionParentEntity)) {
$revision->setLanguageParent(null);
$revisionParentEntity = $revision;
}
else {
$revision->setLanguageParent($revisionParentEntity->getId());
}
$em->persist($revision);
$em->flush();
if($approval_required && $revision && $language->getAlias() === $default_lang){
$approval_request = $this->createApprovalRequest($revision, ApprovalRequest::REQUEST_TYPE_CREATE, $this->getUser());
$em->persist($approval_request);
$em->flush();
$this->dispatcher->dispatch(RequestCreatedEvent::NAME, new RequestCreatedEvent($approval_request));
}
}
}
}
if('preview' !== $buttonAction) {
$flash_message = $translator->trans('message.entry_saved', [], 'admin');
$this->addFlash('success', $flash_message);
if ($settings->get('single', false)) {
return $this->redirectToRoute($this->routes['edit'], [
'facility' => $facility,
'id' => ($parentEntity) ? $parentEntity->getId() : $entity->getId(),
'disable_redirect_suggestion' => true
]);
} else {
return $this->redirect($this->base_path);
}
}
}
}
return $this->render($this->views['multilingual_edit'], [
'meta' => $this->meta('NEW'),
'_languages' => $languages,
'selected_languages' => $selected_languages,
'active_language' => $active_language,
'violations' => $violations,
'builders' => $builders,
'preview_url' => $preview_url,
'redirect_url' => null,
'redirect_message' => null,
'entity' => null,
'master_entity' => null,
'post_type' => null,
'approval_required' => $approval_required,
'revisions' => [],
'revision_history' => [],
'approval_history' => [],
'button_sections' => isset($this->button_sections['new']) ? $this->button_sections['new'] : [],
'_pageBuilderParams' => $_pageBuilderParams,
'_routes' => $this->routes,
'_base_route_params' => $this->base_route_params,
'languages_heading' => $languageHeading
]);
}
public function editAction(Request $request, $id)
{
$translator = $this->container->get('translator');
$settings = $this->entity_settings;
if ($this->entity_settings->isMultilingual()) {
return $this->multiLingualEditAction($request, $id);
}
$em = $this->getDoctrine()->getManager();
$repo = $this->getDoctrine()->getRepository($this->models['item']);
// new でも見えるようにフィルターを外す
$filters = $em->getFilters();
if($filters->isEnabled('post_type')){
$filters->disable('post_type');
$entity = $this->findEntity($id);
$filters->enable('post_type');
} else {
$entity = $this->findEntity($id);
}
if (!$entity) {
throw new NotFoundHttpException();
}
$master_entity = $entity;
if($this->isGranted('approval_request_edit')){
$approval_required = false;
} else {
$approval_required = $settings->get('approval_required', false);
}
$preview_url = null;
$redirect_url = null;
$redirect_message = null;
$post_type = method_exists($entity, 'getPostType') ? $entity->getPostType() : 'master';
$suggestion_disabled = $request->query->getBoolean('disable_redirect_suggestion', false);
if($settings->isRevisable()){
$master_entity = $repo->findMasterEntity($entity);
$revisions = $this->getRevisions($entity);
$revision_history = $this->getRevisionHistory($entity);
if($settings->get('approval_required', false)) {
$approval_history = $this->getApprovalHistory($master_entity);
} else {
$approval_history = [];
}
if(!$suggestion_disabled) {
// 新しい下書きがあるか調べる
foreach ($revisions as $revision) {
if ('draft' === $revision->getPostType() && $revision->getRevisionVersion() > $entity->getRevisionVersion() && $entity->getId() !== $revision->getId()) {
$redirect_url = $this->get('router')->generate($this->routes['edit'], [
'id' => $revision->getId(),
'disable_redirect_suggestion' => true
]);
$redirect_message = '編集中の下書きがあります。表示を切り替えますか?';
break;
}
}
// 新しいリビジョンがあるか調べる
foreach ($revision_history as $value) {
if ($value['version'] > $master_entity->getRevisionVersion() && $entity->getId() !== $revision->getId()) {
$redirect_url = $this->get('router')->generate($this->routes['edit'], [
'id' => $revision->getId(),
'disable_redirect_suggestion' => true
]);
$redirect_message = '新しい項目があります。表示を切り替えますか?';
break;
}
}
}
/** @var ButtonSection $topRightButtons */
$topRightButtons = $this->button_sections['edit']['top_right'];
if($this->entity_settings->get('revisable', false)) {
$topRightButtons->addButton('revision_history', '<i class="fa fa-history" aria-hidden="true"></i> 変更履歴', [
'id' => 'btn-revision-select',
'class' => 'btn btn-default',
'href' => '#btn-revision-select',
'data-toggle' => 'modal',
'data-target' => '#revision-history-modal'
], 1000);
}
if($this->entity_settings->get('approval_required', false)) {
$topRightButtons->addButton('approval_history', '<i class="fa fa-check-circle" aria-hidden="true"></i> 承認履歴', [
'id' => '',
'class' => 'btn btn-default',
'href' => 'javascript:void(0)',
'data-toggle' => 'modal',
'data-target' => '#approval-history-modal'
]);
}
} else {
$revisions = [];
$revision_history = [];
$approval_history = [];
}
$buttonAction = $request->request->get('_button_action', 'default');
$builder = $this->createPageBuilder($this->form_class, $entity, 'edit');
$this->pageBuilderOnLoad($builder);
if ($request->isMethod('post')) {
$referer = $request->headers->get('referer');
$builder->initMediaUsageTracker();
$violations = $builder->handleRequest($request);
// エラーがないとき
if (empty($violations)) {
if ($buttonAction === 'preview') {
$previews = $repo->findChildRevisions($entity, ['preview']);
if ($previews) {
$preview = $previews[0];
} else {
// プレビューの作成
$preview = $this->duplicateEntity($entity);
$preview->setRevisionParent($entity->getId());
$preview->setPostType('preview');
}
$token = $this->generateAccessToken();
$blocks2 = array_map(function($block){
return clone $block;
}, $builder->getBlocks());
$builder->setBlocks($blocks2);
$builder->commit(OnCommitEvent::MODE_PREVIEW);
$formData = $builder->getData();
$formData = $this->filterFormData($formData, 'edit');
$preview->bindFormData($formData);
$preview->setAccessToken($token);
$this->save($em, $preview, $formData, self::SAVE_MODE_PREVIEW);
if($this->entity_settings->isRevisable()) {
$previewParams = [
'id' => $preview->getId()
];
$preview_url = $this->generateUrl($this->routes['preview'], array_merge($this->base_route_params, $previewParams));
} else {
$previewParams = [
'preview_id' => $preview->getId(),
'cms_token' => $token,
'cms_mode' => 'tmp_preview'
];
$preview_url = $this->getPreviewPageUrl($preview->getId(), $previewParams);
}
} else {
$revisionParent = null;
$revision = null;
$targetEntity = $entity;
if ($this->entity_settings->isRevisable()) {
$blocks2 = array_map(function($block){
return clone $block;
}, $builder->getBlocks());
$builder->setBlocks($blocks2);
$builder->commit(OnCommitEvent::MODE_REVISION);
$formData = $builder->getData();
$formData = $this->filterFormData($formData, 'edit');
// 一度もリビジョンが作られていない場合
if(0 === $repo->countRevisions($entity) && 'draft' !== $entity->getPostType()){
$firstRevision = $this->generateRevision($entity);
$firstRevision->setPostType('revision');
$em->persist($firstRevision);
}
// 更新
$revision = $this->generateRevision($entity);
$revision->setPostType(('draft' === $buttonAction) ? 'draft' : 'revision');
$maxVersion = (int)$repo->getMaxRevisionVersion($entity);
$revision->setRevisionVersion($maxVersion + 1);
$em->persist($revision);
$targetEntity = $revision;
// 不要になった下書きを削除
$drafts = ($master_entity) ? $this->getRelatedDrafts($master_entity) : [];
foreach ($drafts as $draft) {
if($targetEntity->getId() === $draft->getId()){
continue;
}
$em->remove($draft);
}
} else {
$builder->commit();
$formData = $builder->getData();
$formData = $this->filterFormData($formData, 'edit');
}
$targetEntity->bindFormData($formData);
$flash_message = $translator->trans('message.entry_saved', [], 'admin');
$this->save($em, $targetEntity, $formData, self::SAVE_MODE_EDIT);
if ($this->entity_settings->isRevisable() && $revision) {
$approval_request = null;
if('draft' === $buttonAction){
// 下書きの再編集
if('master:draft' === $master_entity->getPostType()){
$this->applyRevision($master_entity, $revision);
}
} else {
if($approval_required){
if('master:draft' === $master_entity->getPostType()){
$approval_request = $this->createApprovalRequest($revision, ApprovalRequest::REQUEST_TYPE_CREATE, $this->getUser());
} else {
$approval_request = $this->createApprovalRequest($revision, ApprovalRequest::REQUEST_TYPE_UPDATE, $this->getUser());
}
$em->persist($approval_request);
// 下書き、または承認前なら即時反映
if(in_array($master_entity->getPostType(), ['master:draft', 'master:unapproved', 'master:rejected'])){
$this->applyRevision($master_entity, $revision);
$master_entity->setPostType('master:unapproved');
}
} else {
if ('master:draft' === $master_entity->getPostType()) {
$master_entity->setPostType('master');
}
$this->applyRevision($master_entity, $revision);
$this->cancelRelatedApprovalRequests($master_entity);
}
}
if($approval_request){
$this->dispatcher->dispatch(RequestCreatedEvent::NAME, new RequestCreatedEvent($approval_request));
}
$em->flush();
$this->saveMediaUsages($revision);
}
$this->saveMediaUsages($master_entity);
$this->addFlash('success', $flash_message);
if($settings->get('single', false)){
return $this->redirectToRoute($this->routes['edit'], [
'id' => $targetEntity->getId(),
'disable_redirect_suggestion' => true
]);
} else {
return $this->redirect($this->base_path);
}
}
}
}
if('' !== (string)$preview_url){
$redirect_url = null;
$redirect_message = null;
}
return $this->render($this->views['edit'], [
'meta' => $this->meta('EDIT'),
'builder' => $builder,
'preview_url' => $preview_url,
'redirect_url' => $redirect_url,
'redirect_message' => $redirect_message,
'entity' => $entity,
'master_entity' => $master_entity,
'post_type' => $post_type,
'approval_required' => $approval_required,
'revisions' => $revisions,
'revision_history' => $revision_history,
'approval_history' => $approval_history,
'drafts' => [],
'button_sections' => isset($this->button_sections['edit']) ? $this->button_sections['edit'] : [],
'_pageBuilderParams' => $builder->getSharedParams(),
'_routes' => $this->routes,
'_base_route_params' => $this->base_route_params,
]);
}
public function multiLingualEditAction(Request $request, $id)
{
$facility = 'master';
$this->get('app.helper.script_loader')
->register('language_edit', CMS__ADMIN_PATH . 'js/pages/language-edit.js');
$translator = $this->container->get('translator');
$settings = $this->entity_settings;
$languages = $this->getMasterLanguages();
$em = $this->getDoctrine()->getManager();
$repo = $this->getDoctrine()->getRepository($this->models['item']);
$default_lang = $this->container->getParameter('language.default', 'jp');
$languageHeading = $this->getLanguagesHeading($languages);
$revision_parent = $request->query->get('revision_parent', null);
if (empty($revision_parent)) {
$revision_parent = $id;
}
$revision_lang = $request->query->get('revision_lang', null);
$active_language = $request->request->get('_active-language', null);
if (!empty($revision_lang)) {
$active_language = $revision_lang;
}
// new でも見えるようにフィルターを外す
/** @var FilterCollection $filters */
$filters = $em->getFilters();
if($filters->isEnabled('post_type')){
$postTypeFilter = $filters->getFilter('post_type');
$postTypeFilter->saveState();
$postTypeFilter->deactivate();
} else {
$postTypeFilter = null;
}
$entities = $repo->getEntitiesForLanguage($id, $revision_parent, $revision_lang);
$trunk = $repo->findTrunkLanguageEntry($id, $default_lang);
if($postTypeFilter){
$postTypeFilter->restoreState();
}
$defaultSelected = [];
foreach ($entities as $k => $entity) {
if ($entity->isLanguageActive()) {
$defaultSelected[] = $k;
}
}
$selected_languages = $request->request->get('select_lang', $defaultSelected);
if (!is_null($active_language) && !in_array($active_language, $selected_languages)) {
$selected_languages[] = $active_language;
}
$master_entity = $trunk;
if($this->isGranted('approval_request_edit')){
$approval_required = false;
} else {
$approval_required = $settings->get('approval_required', false);
}
$violations = [];
// 言語ごとのbuilderを設定
$builders = $this->createPageBuilderLanguages($languages, $entities, 'edit');
$preview_url = null;
$redirect_url = null;
$redirect_message = null;
$post_type = null;
$suggestion_disabled = $request->query->getBoolean('disable_redirect_suggestion', false);
$revisions = [];
$first_entity = isset($entities[$active_language]) ? $entities[$active_language] : reset($entities);
if($settings->isRevisable()) {
$master_entity = ($trunk) ? $repo->findMasterEntity($trunk) : null;
$revision_history = $this->getRevisionHistory($trunk);
if($settings->get('approval_required', false)) {
$approval_history = $this->getApprovalHistory($trunk);
} else {
$approval_history = [];
}
if(!$suggestion_disabled) {
// 新しい下書きがあるか調べる
foreach ($revisions as $revision) {
if ('draft' === $revision->getPostType() && $revision->getRevisionVersion() > $entity->getRevisionVersion() && $entity->getId() !== $revision->getId()) {
$redirect_url = $this->get('router')->generate($this->routes['edit'], [
'facility' => $facility, 'id' => $revision->getId(),
'disable_redirect_suggestion' => 1
]);
$redirect_message = '編集中の下書きがあります。表示を切り替えますか?';
break;
}
}
// 新しいリビジョンがあるか調べる
foreach ($revision_history as $value) {
if ($value['version'] > $master_entity->getRevisionVersion() && $entity->getId() !== $value['id']) {
$redirect_url = $value['edit_url'];
$redirect_message = '新しい項目があります。表示を切り替えますか?';
break;
}
}
}
/** @var ButtonSection $topRightButtons */
$topRightButtons = $this->button_sections['edit']['top_right'];
if($this->entity_settings->get('revisable', false)) {
$topRightButtons->addButton('revision_history', '<i class="fa fa-history" aria-hidden="true"></i> 変更履歴', [
'id' => 'btn-revision-history',
'class' => 'btn btn-default',
'href' => '#revision-history-modal',
'data-toggle' => 'modal',
'data-target' => '#revision-history-modal'
], 1000);
}
if($this->entity_settings->get('approval_required', false)) {
$topRightButtons->addButton('approval_history', '<i class="fa fa-check-circle" aria-hidden="true"></i> 承認履歴', [
'id' => 'btn-approval-history',
'class' => 'btn btn-default',
'href' => '#approval-history-modal',
'data-toggle' => 'modal',
'data-target' => '#approval-history-modal'
]);
}
} else {
$revisions = [];
$revision_history = [];
$approval_history = [];
}
$buttonAction = $request->request->get('_button_action', 'default');
$_pageBuilderParams = [];
foreach ($builders as $builder) {
$_pageBuilderParams += $builder->getSharedParams();
}
if ($request->isMethod('post')) {
$violations = $this->validateLanguages($request, $builders, $selected_languages, $buttonAction);
if (empty($violations)) {
// 不足言語分のEntityを先に作成
foreach ($languages as $language) {
$formData = [];
$alias = $language->getAlias();
if (!isset($entities[$alias])) {
$entity = new $this->models['item']();
$max = (method_exists($entity, 'getSortNum')) ? $repo->getMaxSortNumForLanguage($language, $language->isParent()) : 0;
$defaults = [
'max' => $max,
'buttonAction' => $buttonAction,
'language' => $language,
'parentEntity' => $entities[$default_lang],
'alias' => $alias,
'selected_languages' => []
];
$this->setLanguageEntityDefault($entity, $defaults);
$entity->bindFormData($formData);
$em->persist($entity);
$em->flush();
$entities[$alias] = $entity;
}
}
$parentEntity = null;
$parentMasterEntity = null;
$parentFirstRevisionEntity = null;
/** @var Language $language */
foreach ($languages as $language) {
$alias = $language->getAlias();
$isParent = $language->isParent();
$prefix = $language->getTranslateKey() . '_';
$builder = $builders[$alias];
$builder->initMediaUsageTracker();
$entity = $entities[$alias];
if ($buttonAction === 'preview') {
if ($alias !== $active_language) {
continue;
}
$previews = $repo->findChildRevisions($entity, ['preview']);
if($previews){
$preview = $previews[0];
} else {
// プレビューの作成
$preview = $this->duplicateEntity($entity);
$preview->setPostType('preview');
}
$preview->setRevisionParent($entity->getId());
$token = $this->generateAccessToken();
$defaults = [
'language' => $language,
'parentEntity' => $parentEntity,
'alias' => $alias,
];
$this->setLanguageEntityDefault($preview, $defaults);
$blocks2 = array_map(function($block){
return clone $block;
}, $builder->getBlocks());
$builder->setBlocks($blocks2);
$builder->commit(OnCommitEvent::MODE_PREVIEW);
$formData = $builder->getData();
$formData = $this->filterFormDataLanguage($formData, 'edit', $prefix);
$formData = $this->filterFormData($formData, 'edit');
$preview->bindFormData($formData);
$preview->setAccessToken($token);
$this->save($em, $preview, $formData, self::SAVE_MODE_PREVIEW);
if($this->entity_settings->isRevisable()) {
$previewParams = [
'id' => $preview->getId()
];
$preview_url = $this->generateUrl($this->routes['preview'], array_merge($this->base_route_params, $previewParams));
} else {
$previewParams = [
'preview_id' => $preview->getId(),
'cms_token' => $token,
'cms_mode' => 'tmp_preview',
'_locale' => $preview->getLanguageAlias()
];
$preview_url = $this->getPreviewPageUrl($facility, $preview->getId(), $previewParams);
}
} else {
$revisionParent = null;
$revision = null;
$targetEntity = $entity;
if ($this->entity_settings->isRevisable()) {
$blocks2 = array_map(function($block){
return clone $block;
}, $builder->getBlocks());
$builder->setBlocks($blocks2);
$builder->commit(OnCommitEvent::MODE_REVISION);
$formData = $builder->getData();
$formData = $this->filterFormDataLanguage($formData, 'edit', $prefix);
$languageMaster = $repo->findMasterEntity($entity);
$parentId = $entity->getRevisionParent();
$revisionParent = ($parentId) ? $repo->findRevision($parentId) : null;
if ('draft' === $entity->getPostType()) {
$targetEntity = $entity;
if($revisionParent){
// 既存下書き
$revision = $entity;
$revision->setPostType(('draft' === $buttonAction) ? 'draft' : 'revision');
} else {
// 新規下書き
$targetEntity->setPostType(('draft' === $buttonAction) ? 'draft' : 'master');
}
} else {
// 一度もリビジョンが作られていない場合
if(0 === $repo->countRevisions($entity) && 'draft' !== $entity->getPostType()){
$firstRevision = $this->generateRevision($entity);
$firstRevision->setPostType('revision');
if (is_null($parentFirstRevisionEntity)) {
$firstRevision->setLanguageParent(null);
$parentFirstRevisionEntity = $firstRevision;
}
else {
$firstRevision->setLanguageParent($parentFirstRevisionEntity->getId());
}
$em->persist($firstRevision);
}
// 更新
$revision = $this->generateRevision($entity);
$revision->setPostType(('draft' === $buttonAction) ? 'draft' : 'revision');
$maxVersion = (int)$repo->getMaxRevisionVersion($entity);
$revision->setRevisionVersion($maxVersion + 1);
$em->persist($revision);
$targetEntity = $revision;
}
// 不要になった下書きを削除
$drafts = ($languageMaster) ? $this->getRelatedDrafts($languageMaster) : [];
foreach ($drafts as $draft) {
if($targetEntity->getId() === $draft->getId()){
continue;
}
$em->remove($draft);
}
} else {
$languageMaster = $entity;
$builder->commit();
$formData = $builder->getData();
$formData = $this->filterFormDataLanguage($formData, 'edit', $prefix);
}
if ($parentEntity) {
$this->setEntityParentLanguage($targetEntity, $parentEntity, $this->form_class);
}
$targetEntity->bindFormData($formData);
$defaults = [
'language' => $language,
'alias' => $alias,
'selected_languages' => $selected_languages,
'parentEntity' => $parentEntity,
];
$this->setLanguageEntityDefault($targetEntity, $defaults);
$this->save($em, $targetEntity, $formData, self::SAVE_MODE_EDIT, [
'builder' => $builder,
'language' => $language
]);
if ($isParent) {
$parentEntity = $targetEntity;
}
if ($this->entity_settings->isRevisable() && $revision) {
$approval_request = null;
if('draft' === $buttonAction){
// 下書きの再編集
if('master:draft' === $languageMaster->getPostType()){
$this->applyRevision($languageMaster, $revision);
}
} else {
if($approval_required){
if($language->getAlias() !== $default_lang){
$approval_request = null;
} elseif('master:draft' === $master_entity->getPostType()){
$approval_request = $this->createApprovalRequest($revision, ApprovalRequest::REQUEST_TYPE_CREATE, $this->getUser());
} else {
$approval_request = $this->createApprovalRequest($revision, ApprovalRequest::REQUEST_TYPE_UPDATE, $this->getUser());
}
if($approval_request) {
$em->persist($approval_request);
}
// 下書き、または承認前なら即時反映
if(in_array($languageMaster->getPostType(), ['master:draft', 'master:unapproved', 'master:rejected'])){
$this->applyRevision($languageMaster, $revision);
$master_entity->setPostType('master:unapproved');
}
} else {
if (in_array($languageMaster->getPostType(), ['master:draft', 'master:unapproved', 'master:rejected'])) {
$languageMaster->setPostType('master');
}
$this->applyRevision($languageMaster, $revision);
$this->cancelRelatedApprovalRequests($languageMaster);
}
}
$em->flush();
if($approval_request){
$this->dispatcher->dispatch(RequestCreatedEvent::NAME, new RequestCreatedEvent($approval_request));
}
$this->saveMediaUsages($revision);
}
}
}
if ($buttonAction !== 'preview') {
$this->saveMediaUsages($master_entity);
$flash_message = $translator->trans('message.entry_saved', [], 'admin');
$this->addFlash('success', $flash_message);
if ($settings->get('single', false)) {
return $this->redirectToRoute($this->routes['edit'], [
'facility' => $facility,
'id' => $trunk->getId(),
'disable_redirect_suggestion' => true
]);
} else {
return $this->redirect($this->base_path);
}
}
}
}
if('' !== (string)$preview_url){
$redirect_url = null;
$redirect_message = null;
}
return $this->render($this->views['multilingual_edit'], [
'meta' => $this->meta('EDIT'),
'builders' => $builders,
'preview_url' => $preview_url,
'redirect_url' => $redirect_url,
'redirect_message' => $redirect_message,
'_languages' => $languages,
'selected_languages' => $selected_languages,
'active_language' => $active_language,
'violations' => $violations,
'entity' => $first_entity,
'master_entity' => $master_entity,
'post_type' => $post_type,
'approval_required' => $approval_required,
'revisions' => $revisions,
'revision_history' => $revision_history,
'approval_history' => $approval_history,
'button_sections' => isset($this->button_sections['edit']) ? $this->button_sections['edit'] : [],
'_pageBuilderParams' => $_pageBuilderParams,
'_routes' => $this->routes,
'_base_route_params' => $this->base_route_params,
'revision_parent' => $revision_parent,
'languages_heading' => $languageHeading
]);
}
/**
* @param Request $request
* @param $id
* @return Response
*/
public function detailAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
/** @var FilterCollection $filters */
$filters = $em->getFilters();
if($filters->isEnabled('post_type')){
$filter = $filters->getFilter('post_type');
$filterState = $filter->isActive();
$filter->deactivate();
} else {
$filter = null;
$filterState = false;
}
$item = $this->findOneEntity($this->models['item'], ['id' => $id]);
if(!$item){
throw $this->createNotFoundException();
}
if($filterState){
$filter->activate();
}
$builder = $this->createPageBuilder($this->form_class, $item);
$builder->setTheme('browse');
return $this->render($this->views['detail'], [
'item' => $item,
'builder' => $builder,
'page_title' => $this->title
]);
}
public function deleteAction(Request $request)
{
$translator = $this->get('translator');
$id = $request->get('id', -1);
$em = $this->getDoctrine()->getManager();
$repo = $this->getDoctrine()->getRepository($this->models['item']);
$filters = $em->getFilters();
if($filters->isEnabled('post_type')){
$filters->disable('post_type');
}
$item = $repo->find($id);
if($filters->isEnabled('post_type')){
$filters->enable('post_type');
}
if(!$item) throw $this->createNotFoundException();
if(method_exists($item, 'getPostType')){
$post_type = $item->getPostType();
} else {
$post_type = 'master';
}
if($this->isGranted('approval_request_edit')){
$approval_required = false;
} else {
$approval_required = $this->entity_settings->get('approval_required', false);
}
if('master' === $post_type && $approval_required) {
$approval_request = $this->createApprovalRequest($item, ApprovalRequest::REQUEST_TYPE_DELETE, $this->getUser());
$em->persist($approval_request);
$em->flush();
// フラッシュメッセージ
$this->addFlash('success', $translator->trans('approval.message.entry_delete_requested', [], 'admin'));
$this->dispatcher->dispatch(RequestCreatedEvent::NAME, new RequestCreatedEvent($approval_request));
} else {
$em->remove($item);
$em->flush();
// フラッシュメッセージ
$this->addFlash('success', $translator->trans('message.entry_deleted', [], 'admin'));
}
return $this->redirect($this->base_path);
}
public function sortAction(Request $request)
{
$meta = $this->meta('INDEX');
if ($request->isMethod('post')) {
$order = $request->get('order', '');
$idList = preg_split('/,/', $order, -1, \PREG_SPLIT_NO_EMPTY);
$sortOrder = array_flip($idList);
$doctrine = $this->getDoctrine();
$em = $doctrine->getManager();
$repository = $em->getRepository($this->models['item']);
$entities = $repository->createQueryBuilder('i')
->select('i')
->where('i.id IN(:ids)')
->setParameter('ids', array_values($idList))
->getQuery()
->getResult();
foreach ($entities as $entity) {
$entity->setSortNum($sortOrder[$entity->getId()] + 1);
$em->persist($entity);
}
$em->flush();
// フラッシュメッセージ
$this->addFlash('success', $this->title . MSG_SORT_END);
return $this->redirectToRoute($this->entity_settings->get('base_route') . '_sort');
}
$data_table_options = $this->getSortDataTableOptions();
return $this->render($this->views['sort'], [
'meta' => $meta,
'data_table_options' => $data_table_options,
'button_sections' => isset($this->button_sections['sort']) ? $this->button_sections['sort'] : [],
]);
}
// ID からエンティティを取得
protected function findEntity($id)
{
$repo = $this->getDoctrine()->getRepository($this->models['item']);
$entity = $repo->find($id);
return $entity;
}
public function importAction(Request $request)
{
$meta = $this->meta('IMPORT');
$builder = $this->createPageBuilder(AdminImportForm::class, null);
if ($request->isMethod('post')) {
// ファイル取得
$file = $request->files->get("__block_file")["file"];
$import = $this->get("app.helper.import_helper");
$formatData = $import->getFormatData($request->request->all(), $file);
if (!empty($formatData) && method_exists($this, "importExecuting")) {
$this->importExecuting($formatData);
return $this->redirectToRoute($meta["redirect"]);
}
}
return $this->render(rtrim($this->template_directory) . '/' . 'import.html.php', [
'meta' => $meta,
'builder' => $builder
]);
}
protected function meta($mode, $id = null)
{
$meta = array();
$meta["base"]["title"] = $this->title;
$meta["base"]["path"] = $this->base_path;
$meta["base"]['route'] = $this->entity_settings->getBaseRoute();
$meta["redirect"] = $this->entity_settings->getBaseRoute();
return $this->baseMeta($mode, $meta, $id);
}
protected function baseMeta($mode, $meta = [], $id = null)
{
switch ($mode) {
case "INDEX":
$meta["page"]["title"] = $meta["base"]["title"] . " | 一覧";
$meta["page"]["path"] = $meta["base"]["path"];
$meta["breadcrumbs"]["current"]["title"] = $meta["base"]["title"];
$meta["breadcrumbs"]["parent"]["title"] = "TOP";
$meta["breadcrumbs"]["parent"]["path"] = "/admin/";
break;
case "NEW":
$meta["page"]["title"] = $meta["base"]["title"] . " | 新規作成";
$meta["page"]["path"] = $meta["base"]["path"] . "new/";
$meta["breadcrumbs"]["current"]["title"] = "新規作成";
$meta["breadcrumbs"]["parent"]["title"] = $meta["base"]["title"];
$meta["breadcrumbs"]["parent"]["path"] = $meta["base"]["path"];
break;
case "DETAIL":
$meta["page"]["title"] = $meta["base"]["title"] . " | 詳細";
$meta["page"]["path"] = $meta["base"]["path"] . $id . '/';
$meta["breadcrumbs"]["current"]["title"] = "詳細";
$meta["breadcrumbs"]["parent"]["title"] = $meta["base"]["title"];
$meta["breadcrumbs"]["parent"]["path"] = $meta["base"]["path"];
break;
case "EDIT":
$meta["page"]["title"] = $meta["base"]["title"] . " | 編集";
$meta["page"]["path"] = $meta["base"]["path"] . $id . '/edit/';
$meta["breadcrumbs"]["current"]["title"] = "編集";
$meta["breadcrumbs"]["parent"]["title"] = $meta["base"]["title"];
$meta["breadcrumbs"]["parent"]["path"] = $meta["base"]["path"];
break;
case "IMPORT":
$meta["page"]["title"] = $meta["base"]["title"] . " | インポート";
$meta["page"]["path"] = $meta["base"]["path"] . "import/";
$meta["breadcrumbs"]["current"]["title"] = "インポート";
$meta["breadcrumbs"]["parent"]["title"] = $meta["base"]["title"];
$meta["breadcrumbs"]["parent"]["path"] = $meta["base"]["path"];
break;
default:
$meta["page"]["title"] = "[Unknown]";
$meta["page"]["path"] = "/unknown";
$meta["breadcrumbs"]["current"]["title"] = "[Unknown]";
$meta["breadcrumbs"]["parent"]["title"] = "[Unknown]";
$meta["breadcrumbs"]["parent"]["path"] = "/unknown";
}
return $meta;
}
protected function getListDataTableOptions()
{
return parent::getListDataTableOptions();
}
/**
* @param int id
* @param array $params
* @return string|null
*/
protected function getPreviewPageUrl($id, $params = [])
{
if ($this->entity_settings->get('actions.preview')) {
return $this->generateUrl($this->routes['preview'], $params);
} else {
return null;
}
}
/**
* @param Request $request
* @param $id
* @return RedirectResponse
*/
public function duplicateAction(Request $request, $id)
{
if($this->isGranted('approval_request_edit')){
$approval_required = false;
} else {
$approval_required = $this->entity_settings->get('approval_required', false);
}
$repo = $this->getDoctrine()->getRepository($this->models['item']);
$em = $this->getDoctrine()->getManager();
$filters = $em->getFilters();
$filterState = $filters->isEnabled('post_type');
if($filterState){
$filters->disable('post_type');
}
$entity = $repo->find($id);
if(!$entity){
throw $this->createNotFoundException();
}
if($filterState){
$filters->enable('post_type');
}
$clone = $this->duplicateEntityWithForm($entity, $this->form_class);
if(method_exists($clone, 'getTitle') && method_exists($clone, 'setTitle')){
$clone->setTitle('(複製)' . $clone->getTitle());
}
if(method_exists($clone, 'setStatus')){
$clone->setStatus(0);
}
if($approval_required){
$post_type = (method_exists($clone, 'getPostType')) ? $clone->getPostType() : 'master';
if('master' === $post_type){
$clone->setPostType('master:unapproved');
}
}
if(method_exists($clone, 'setLatestApprovalRequest')){
$clone->setLatestApprovalRequest(null);
}
$this->save($em, $clone, [], self::SAVE_MODE_DUPLICATE);
$this->saveMediaUsages($clone);
return $this->redirectToRoute($this->entity_settings->get('base_route'));
}
public function childIndexAction(Request $request, $parent)
{
/** @var ButtonSection $section */
$section = isset($this->button_sections['index']['top_left']) ? $this->button_sections['index']['top_left'] : new ButtonSection();
$section->addButton('back', '<i class="fa fa-arrow-circle-left"></i> 一覧に戻る', [
'href' => '../../',
'class' => 'btn btn-default'
], 10);
return $this->indexAction($request);
}
public function childEditAction(Request $request, $parent, $id)
{
return $this->editAction($request, $id);
}
public function childJsonAction(Request $request, $parent)
{
return $this->jsonAction($request);
}
public function childSortAction(Request $request, $parent)
{
return $this->sortAction($request);
}
public function childDuplicateAction(Request $request, $parent, $id)
{
return $this->duplicateAction($request, $id);
}
public function childDeleteAction(Request $request, $parent)
{
return $this->deleteAction($request);
}
/**
* デフォルトの並び順
*
* @return array
*/
protected function getDefaultOrderBy()
{
return ['sort_num' => 'ASC', 'id' => 'DESC'];
}
/**
* @param $entity_class
* @param $data
* @param string $value_name
* @return mixed
*/
protected function getCategoryIdForImport($entity_class, $data, $value_name = "title")
{
$repository = $this->getDoctrine()->getRepository($entity_class);
$entries = $repository->findBy(["{$value_name}" => $data[$value_name]]);
if (!empty($entries)) {
return $entries[0];
} else {
// 新規登録
$em = $this->getDoctrine()->getManager();
$entity = new $entity_class();
$entity->bindFormData($data);
$em->persist($entity);
$em->flush();
return $entity;
}
}
}