Memo

メモ > 技術 > CMS: ECCube > カスタマイズ: 新着情報管理をもとに独自の記事管理を作成

■カスタマイズ: 新着情報管理をもとに独自の記事管理を作成
既存機能の「新着情報管理」をもとに、独自の記事管理を作成してみる 独自に作成したテーブルには専用のプレフィックスを付けておく方が管理しやすいか。contactも含めて考える ■調査メモ
@ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255)
EC-CUBE4のDBのそれぞれのテーブルにあるdiscriminator_typeとは何なのか - Qiita https://qiita.com/okazy/items/974d8e07b0dbd50b9c6a Entityを継承して拡張するときに利用されるらしい ECCubeでは以下のアノテーションを指定すると、discriminator_type列にクラス名が小文字になった文字列が入る 現状それ以上は気にしなくていいか
@ORM\InheritanceType("SINGLE_TABLE")
Doctrine2のInheritanceMapping | QUARTETCOM TECH BLOG https://tech.quartetcom.co.jp/2015/08/24/doctorine2-inheritance-mapping/ Single Table Inheritance は、全ての階層構造を一つのテーブルで表現したもの Class Table Inheritance は、複数テーブルで継承関係を表現したもの ECCubeではすべてのテーブルで SINGLE_TABLE が指定されいているみたい
@ORM\HasLifecycleCallbacks()
データーベースと Doctrine | SymDoc - PHP フレームワーク Symfony3 日本語ドキュメント Wiki http://symdoc.kwalk.jp/doc/book/doctrine エンティティが INSERT や UPDATE、DELETE される直前または、直後に、アクションを実行することができる 例えば「データを登録する際に、自動で特定のメソッドが実行されるようにする」のような処理ができる ECCubeではすべてのテーブルに指定されいているみたい ■Entityとテーブルの作成 src\Eccube\Entity\News.php をもとに app\Customize\Entity\Article.php を作成
<?php /* * This file is part of EC-CUBE * * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved. * * http://www.ec-cube.co.jp/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Customize\Entity; use Doctrine\ORM\Mapping as ORM; /** * Article * * @ORM\Table(name="dtb_article") * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255) * @ORM\HasLifecycleCallbacks() * @ORM\Entity(repositoryClass="Customize\Repository\ArticleRepository") * @ORM\Cache(usage="NONSTRICT_READ_WRITE") */ class Article extends \Eccube\Entity\AbstractEntity { /** * @return string */ public function __toString() { return (string) $this->getTitle(); } /** * @var int * * @ORM\Column(name="id", type="integer", options={"unsigned":true}) * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ private $id; /** * @var \DateTime|null * * @ORM\Column(name="publish_date", type="datetimetz", nullable=true) */ private $publish_date; /** * @var string * * @ORM\Column(name="title", type="string", length=255) */ private $title; /** * @var string|null * * @ORM\Column(name="description", type="text", nullable=true) */ private $description; /** * @var string|null * * @ORM\Column(name="url", type="string", length=4000, nullable=true) */ private $url; /** * @var boolean * * @ORM\Column(name="link_method", type="boolean", options={"default":false}) */ private $link_method = false; /** * @var \DateTime * * @ORM\Column(name="create_date", type="datetimetz") */ private $create_date; /** * @var \DateTime * * @ORM\Column(name="update_date", type="datetimetz") */ private $update_date; /** * @var boolean * * @ORM\Column(name="visible", type="boolean", options={"default":true}) */ private $visible; /** * @var \Eccube\Entity\Member * * @ORM\ManyToOne(targetEntity="Eccube\Entity\Member") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="creator_id", referencedColumnName="id") * }) */ private $Creator; /** * Get id. * * @return int */ public function getId() { return $this->id; } /** * Set publishDate. * * @param \DateTime|null $publishDate * * @return Article */ public function setPublishDate($publishDate = null) { $this->publish_date = $publishDate; return $this; } /** * Get publishDate. * * @return \DateTime|null */ public function getPublishDate() { return $this->publish_date; } /** * Set title. * * @param string $title * * @return Article */ public function setTitle($title) { $this->title = $title; return $this; } /** * Get title. * * @return string */ public function getTitle() { return $this->title; } /** * Set description. * * @param string|null $description * * @return Article */ public function setDescription($description = null) { $this->description = $description; return $this; } /** * Get description. * * @return string|null */ public function getDescription() { return $this->description; } /** * Set url. * * @param string|null $url * * @return Article */ public function setUrl($url = null) { $this->url = $url; return $this; } /** * Get url. * * @return string|null */ public function getUrl() { return $this->url; } /** * Set linkMethod. * * @param boolean $linkMethod * * @return Article */ public function setLinkMethod($linkMethod) { $this->link_method = $linkMethod; return $this; } /** * Get linkMethod. * * @return boolean */ public function isLinkMethod() { return $this->link_method; } /** * Set createDate. * * @param \DateTime $createDate * * @return Article */ public function setCreateDate($createDate) { $this->create_date = $createDate; return $this; } /** * Get createDate. * * @return \DateTime */ public function getCreateDate() { return $this->create_date; } /** * Set updateDate. * * @param \DateTime $updateDate * * @return Article */ public function setUpdateDate($updateDate) { $this->update_date = $updateDate; return $this; } /** * Get updateDate. * * @return \DateTime */ public function getUpdateDate() { return $this->update_date; } /** * @return integer */ public function isVisible() { return $this->visible; } /** * @param boolean $visible * * @return Article */ public function setVisible($visible) { $this->visible = $visible; return $this; } /** * Set creator. * * @param \Eccube\Entity\Member|null $creator * * @return Article */ public function setCreator(\Eccube\Entity\Member $creator = null) { $this->Creator = $creator; return $this; } /** * Get creator. * * @return \Eccube\Entity\Member|null */ public function getCreator() { return $this->Creator; } }
以下でマイグレーションファイルを作成
$ cd /var/www/main/html $ php bin/console cache:clear --no-warmup $ php bin/console doctrine:migrations:diff Generated new migration class to "/var/www/main/html/app/DoctrineMigrations/Version20200820110258.php" from schema differences.
app\DoctrineMigrations\Version20200820110258.php を修正(自動作成されたマイグレーションファイル)
<?php declare(strict_types=1); namespace DoctrineMigrations; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ final class Version20200820110258 extends AbstractMigration { public function up(Schema $schema) : void { // this up() migration is auto-generated, please modify it to your needs $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('CREATE TABLE dtb_article (id INT UNSIGNED AUTO_INCREMENT NOT NULL, creator_id INT UNSIGNED DEFAULT NULL, publish_date DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetimetz)\', title VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, url VARCHAR(4000) DEFAULT NULL, link_method TINYINT(1) DEFAULT \'0\' NOT NULL, create_date DATETIME NOT NULL COMMENT \'(DC2Type:datetimetz)\', update_date DATETIME NOT NULL COMMENT \'(DC2Type:datetimetz)\', visible TINYINT(1) DEFAULT \'1\' NOT NULL, discriminator_type VARCHAR(255) NOT NULL, INDEX IDX_23A0E6661220EA6 (creator_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = InnoDB'); $this->addSql('ALTER TABLE dtb_article ADD CONSTRAINT FK_23A0E6661220EA6 FOREIGN KEY (creator_id) REFERENCES dtb_member (id)'); } public function down(Schema $schema) : void { // this down() migration is auto-generated, please modify it to your needs $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.'); $this->addSql('DROP TABLE dtb_article'); } }
以下でマイグレーションを実行
$ php bin/console doctrine:migrations:status == Configuration >> Name: Application Migrations >> Database Driver: pdo_mysql >> Database Name: main >> Configuration Source: manually configured >> Version Table Name: migration_versions >> Version Column Name: version >> Migrations Namespace: DoctrineMigrations >> Migrations Directory: /var/www/main/html/app/DoctrineMigrations >> Previous Version: 2020-08-17 05:51:48 (20200817055148) >> Current Version: 2020-08-20 03:20:03 (20200820032003) >> Next Version: 2020-08-20 11:02:58 (20200820110258) >> Latest Version: 2020-08-20 11:02:58 (20200820110258) >> Executed Migrations: 6 >> Executed Unavailable Migrations: 0 >> Available Migrations: 7 >> New Migrations: 1 $ php bin/console doctrine:migrations:migrate Application Migrations WARNING! You are about to execute a database migration that could result in schema changes and data loss. Are you sure you wish to continue? (y/n)y Migrating up to 20200820110258 from 20200820032003 ++ migrating 20200820110258 -> CREATE TABLE article (id INT UNSIGNED AUTO_INCREMENT NOT NULL, creator_id INT UNSIGNED DEFAULT NULL, publish_date DATETIME DEFAULT NULL COMMENT '(DC2Type:datetimetz)', title VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, url VARCHAR(4000) DEFAULT NULL, link_method TINYINT(1) DEFAULT '0' NOT NULL, create_date DATETIME NOT NULL COMMENT '(DC2Type:datetimetz)', update_date DATETIME NOT NULL COMMENT '(DC2Type:datetimetz)', visible TINYINT(1) DEFAULT '1' NOT NULL, discriminator_type VARCHAR(255) NOT NULL, INDEX IDX_23A0E6661220EA6 (creator_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = InnoDB -> ALTER TABLE article ADD CONSTRAINT FK_23A0E6661220EA6 FOREIGN KEY (creator_id) REFERENCES dtb_member (id) ++ migrated (0.28s) ------------------------ ++ finished in 0.28s ++ 1 migrations executed ++ 2 sql queries
実行できたら、テーブルが作成されていることを確認する ■プログラムの作成 src\Eccube\Repository\NewsRepository.php をもとに app\Customize\Repository\ArticleRepository.php を作成
<?php /* * This file is part of EC-CUBE * * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved. * * http://www.ec-cube.co.jp/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Customize\Repository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; use Doctrine\DBAL\Exception\DriverException; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use Symfony\Bridge\Doctrine\RegistryInterface; use Customize\Entity\Article; /** * ArticleRepository * * This class was generated by the Doctrine ORM. Add your own custom * repository methods below. */ class ArticleRepository extends \Eccube\Repository\AbstractRepository { public function __construct(RegistryInterface $registry) { parent::__construct($registry, Article::class); } /** * 記事を登録します. * * @param $Article */ public function save($Article) { $em = $this->getEntityManager(); $em->persist($Article); $em->flush($Article); } /** * 記事を削除します. * * @param Article $Article * * @throws ForeignKeyConstraintViolationException 外部キー制約違反の場合 * @throws DriverException SQLiteの場合, 外部キー制約違反が発生すると, DriverExceptionをthrowします. */ public function delete($Article) { $em = $this->getEntityManager(); $em->remove($Article); $em->flush($Article); } /** * @return \Doctrine\ORM\QueryBuilder */ public function getQueryBuilderAll() { $qb = $this->createQueryBuilder('n'); $qb->orderBy('n.publish_date', 'DESC') ->addOrderBy('n.id', 'DESC'); return $qb; } /** * @return Article[]|ArrayCollection */ public function getList() { // second level cacheを効かせるためfindByで取得 $Results = $this->findBy(['visible' => true], ['publish_date' => 'DESC', 'id' => 'DESC']); // 公開日時前のArticleをフィルター $criteria = Criteria::create(); $criteria->where(Criteria::expr()->lte('publish_date', new \DateTime())); $Article = new ArrayCollection($Results); return $Article->matching($criteria); } }
src\Eccube\Controller\Admin\Content\NewsController.php をもとに app\Customize\Controller\Admin\Content\ArticleController.php を作成
<?php /* * This file is part of EC-CUBE * * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved. * * http://www.ec-cube.co.jp/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Customize\Controller\Admin\Content; use Eccube\Controller\AbstractController; //use Eccube\Event\EccubeEvents; //use Eccube\Event\EventArgs; use Eccube\Util\CacheUtil; use Knp\Component\Pager\Paginator; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Annotation\Route; use Customize\Entity\Article; use Customize\Form\Type\Admin\ArticleType; use Customize\Repository\ArticleRepository; class ArticleController extends AbstractController { /** * @var ArticleRepository */ protected $articleRepository; /** * ArticleController constructor. * * @param ArticleRepository $articleRepository */ public function __construct(ArticleRepository $articleRepository) { $this->articleRepository = $articleRepository; } /** * 記事一覧を表示する。 * * @Route("/%eccube_admin_route%/content/article", name="admin_content_article") * @Route("/%eccube_admin_route%/content/article/page/{page_no}", requirements={"page_no" = "\d+"}, name="admin_content_article_page") * @Template("@admin/Content/article.twig") * * @param Request $request * @param int $page_no * @param Paginator $paginator * * @return array */ public function index(Request $request, $page_no = 1, Paginator $paginator) { $qb = $this->articleRepository->getQueryBuilderAll(); /* $event = new EventArgs( [ 'qb' => $qb, ], $request ); $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_CONTENT_ARTICLE_INDEX_INITIALIZE, $event); */ $pagination = $paginator->paginate( $qb, $page_no, $this->eccubeConfig->get('eccube_default_page_count') ); return [ 'pagination' => $pagination, ]; } /** * 記事を登録・編集する。 * * @Route("/%eccube_admin_route%/content/article/new", name="admin_content_article_new") * @Route("/%eccube_admin_route%/content/article/{id}/edit", requirements={"id" = "\d+"}, name="admin_content_article_edit") * @Template("@admin/Content/article_edit.twig") * * @param Request $request * @param null $id * * @return array|\Symfony\Component\HttpFoundation\RedirectResponse */ public function edit(Request $request, $id = null, CacheUtil $cacheUtil) { if ($id) { $Article = $this->articleRepository->find($id); if (!$Article) { throw new NotFoundHttpException(); } } else { $Article = new \Customize\Entity\Article(); $Article->setPublishDate(new \DateTime()); } $builder = $this->formFactory ->createBuilder(ArticleType::class, $Article); /* $event = new EventArgs( [ 'builder' => $builder, 'Article' => $Article, ], $request ); $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_CONTENT_ARTICLE_EDIT_INITIALIZE, $event); */ $form = $builder->getForm(); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { if (!$Article->getUrl()) { $Article->setLinkMethod(false); } $this->articleRepository->save($Article); /* $event = new EventArgs( [ 'form' => $form, 'Article' => $Article, ], $request ); $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_CONTENT_ARTICLE_EDIT_COMPLETE, $event); */ $this->addSuccess('admin.common.save_complete', 'admin'); // キャッシュの削除 $cacheUtil->clearDoctrineCache(); return $this->redirectToRoute('admin_content_article_edit', ['id' => $Article->getId()]); } return [ 'form' => $form->createView(), 'Article' => $Article, ]; } /** * 指定した記事を削除する。 * * @Route("/%eccube_admin_route%/content/article/{id}/delete", requirements={"id" = "\d+"}, name="admin_content_article_delete", methods={"DELETE"}) * * @param Request $request * @param Article $Article * * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function delete(Request $request, Article $Article, CacheUtil $cacheUtil) { $this->isTokenValid(); log_info('記事削除開始', [$Article->getId()]); try { $this->articleRepository->delete($Article); /* $event = new EventArgs(['Article' => $Article], $request); $this->eventDispatcher->dispatch(EccubeEvents::ADMIN_CONTENT_ARTICLE_DELETE_COMPLETE, $event); */ $this->addSuccess('admin.common.delete_complete', 'admin'); log_info('記事削除完了', [$Article->getId()]); // キャッシュの削除 $cacheUtil->clearDoctrineCache(); } catch (\Exception $e) { $message = trans('admin.common.delete_error_foreign_key', ['%name%' => $Article->getTitle()]); $this->addError($message, 'admin'); log_error('記事削除エラー', [$Article->getId(), $e]); } return $this->redirectToRoute('admin_content_article'); } }
src\Eccube\Form\Type\Admin\NewsType.php をもとに app\Customize\Form\Type\Admin\ArticleType.php を作成
<?php /* * This file is part of EC-CUBE * * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved. * * http://www.ec-cube.co.jp/ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Customize\Form\Type\Admin; use Eccube\Common\EccubeConfig; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints as Assert; use Customize\Entity\Article; class ArticleType extends AbstractType { /** * @var EccubeConfig */ protected $eccubeConfig; public function __construct(EccubeConfig $eccubeConfig) { $this->eccubeConfig = $eccubeConfig; } /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('publish_date', DateTimeType::class, [ 'date_widget' => 'choice', 'input' => 'datetime', 'format' => 'yyyy-MM-dd hh:mm', 'years' => range($this->eccubeConfig['eccube_article_start_year'], date('Y') + 3), 'constraints' => [ new Assert\NotBlank(), ], ]) ->add('title', TextType::class, [ 'required' => true, 'constraints' => [ new Assert\NotBlank(), new Assert\Length(['max' => $this->eccubeConfig['eccube_mtext_len']]), ], ]) ->add('url', TextType::class, [ 'required' => false, 'constraints' => [ new Assert\Url(), new Assert\Length(['max' => $this->eccubeConfig['eccube_mtext_len']]), ], ]) ->add('link_method', CheckboxType::class, [ 'required' => false, 'label' => 'admin.content.article.new_window', 'value' => '1', ]) ->add('description', TextareaType::class, [ 'required' => false, 'attr' => [ 'rows' => 8, ], 'constraints' => [ new Assert\Length(['max' => $this->eccubeConfig['eccube_ltext_len']]), ], ]) ->add('visible', ChoiceType::class, [ 'label' => false, 'choices' => ['admin.content.article.display_status__show' => true, 'admin.content.article.display_status__hide' => false], 'required' => true, 'expanded' => false, ]); } /** * {@inheritdoc} */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Article::class, ]); } /** * {@inheritdoc} */ public function getBlockPrefix() { return 'admin_article'; } }
■テンプレートの作成 src\Eccube\Resource\template\admin\Content\news.twig をもとに app\template\admin\Content\article.twig を作成
{# This file is part of EC-CUBE Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved. http://www.ec-cube.co.jp/ For the full copyright and license information, please view the LICENSE file that was distributed with this source code. #} {% extends '@admin/default_frame.twig' %} {% set menus = ['content', 'article'] %} {% block title %}{{ 'admin.content.article_management'|trans }}{% endblock %} {% block sub_title %}{{ 'admin.content.contents_management'|trans }}{% endblock %} {% block stylesheet %} <style type="text/css"> li.list-group-item { z-index: inherit !important; } </style> {% endblock %} {% block main %} <div class="c-contentsArea__cols"> <div class="c-contentsArea__primaryCol"> <div class="c-primaryCol"> <div class="d-block mb-3"> <a id="addNew" class="btn btn-ec-regular" href="{{ url('admin_content_article_new') }}">{{ 'admin.common.create__new'|trans }}</a> </div> <div class="card rounded border-0 mb-4"> <div class="card-body p-0"> <ul class="list-group list-group-flush mb-4 sortable-container"> <li class="list-group-item"> <div class="row justify-content-around"> <div class="col-2"><strong>{{ 'admin.content.article.publish_date'|trans }}</strong> </div> <div class="col-1"><strong>{{ 'admin.content.article.display_status'|trans }}</strong> </div> <div class="col"><strong>{{ 'admin.content.article.title'|trans }}</strong></div> </div> </li> {% for Article in pagination %} <li class="list-group-item sortable-item" data-id="{{ Article.id }}"> <div class="row justify-content-around"> <div class="col-2 d-flex align-items-center"> <span>{{ Article.publishDate|date_min }}</span></div> <div class="col-1 d-flex align-items-center">{{ Article.visible ? 'admin.content.article.display_status__show'|trans : 'admin.content.article.display_status__hide'|trans }}</div> <div class="col d-flex align-items-center"><a href="{{ url('admin_content_article_edit', {id: Article.id}) }}">{{ Article.title }}</a> </div> <div class="col-2"> <div class="row"> <div class="col px-0 text-center"> <a class="btn btn-ec-actionIcon" href="{{ url('admin_content_article_edit', {id: Article.id}) }}" data-toggle="tooltip" data-placement="top" title="{{ 'admin.common.edit'|trans }}"> <i class="fa fa-pencil fa-lg text-secondary"></i> </a> </div> <div class="col pl-0 text-center" data-toggle="tooltip" data-placement="top" title="{{ 'admin.common.delete'|trans }}"> <a class="btn btn-ec-actionIcon" data-toggle="modal" data-target="#delete_{{ Article.id }}"> <i class="fa fa-close fa-lg text-secondary" aria-hidden="true"></i> </a> <div class="modal fade" id="delete_{{ Article.id }}" tabindex="-1" role="dialog" aria-labelledby="delete_{{ Article.id }}" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title font-weight-bold">{{ 'admin.common.delete_modal__title'|trans }}</h5> <button class="close" type="button" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span> </button> </div> <div class="modal-body text-left"> <p class="text-left">{{ 'admin.common.delete_modal__message'|trans({'%name%': Article.title}) }}</p> </div> <div class="modal-footer"> <button class="btn btn-ec-sub" type="button" data-dismiss="modal">{{ 'admin.common.cancel'|trans }}</button> <a class="btn btn-ec-delete" href="{{ url('admin_content_article_delete', {id: Article.id}) }}" {{ csrf_token_for_anchor() }} data-method="delete" data-confirm="false">{{ 'admin.common.delete'|trans }}</a> </div> </div> </div> </div> </div> </div> </div> </div> </li> {% endfor %} </ul> {% if pagination.paginationData.pageCount > 1 %} <div class="row justify-content-md-center mb-4"> {% include "@admin/pager.twig" with { 'pages' : pagination.paginationData, 'routes' : 'admin_content_article_page' } %} </div> {% endif %} </div> </div> </div> </div> </div> {% endblock %}
src\Eccube\Resource\template\admin\Content\news_edit.twig をもとに app\template\admin\Content\article_edit.twig を作成
{# This file is part of EC-CUBE Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved. http://www.ec-cube.co.jp/ For the full copyright and license information, please view the LICENSE file that was distributed with this source code. #} {% extends '@admin/default_frame.twig' %} {% set menus = ['content', 'article'] %} {% block title %}{{ 'admin.content.article_management'|trans }}{% endblock %} {% block sub_title %}{{ 'admin.content.contents_management'|trans }}{% endblock %} {% form_theme form '@admin/Form/bootstrap_4_horizontal_layout.html.twig' %} {% block main %} <form role="form" class="form-horizontal" name="form1" id="form1" method="post" action="?"> {{ form_widget(form._token) }} <div class="c-contentsArea__cols"> <div class="c-contentsArea__primaryCol"> <div class="c-primaryCol"> <div class="card rounded border-0 mb-4"> <div class="card-header"> <div class="row"> <div class="col-8"> <span class="card-title">{{ 'admin.content.article.article_registration'|trans }}</span></div> <div class="col-4 text-right"> <a data-toggle="collapse" href="#articleForm" aria-expanded="true" aria-controls="articleForm"><i class="fa fa-lg fa-angle-up"></i></a></div> </div> </div> <div class="ec-cardCollapse collapse show" id="articleForm" style=""> <div class="card-body"> <div class="row"> <div class="col-3"><span>{{ 'admin.content.article.publish_date'|trans }}</span></div> <div class="col mb-2"> {{ form_widget(form.publish_date) }} {{ form_errors(form.publish_date) }} </div> </div> <div class="row"> <div class="col-3"><span>{{ 'admin.content.article.title'|trans }}</span></div> <div class="col mb-2"> {{ form_widget(form.title) }} {{ form_errors(form.title) }} </div> </div> <div class="row"> <div class="col-3"> <div class="d-inline-block" data-tooltip="true" data-placement="top" title="{{ 'tooltip.content.article.url'|trans }}"> <span>{{ 'admin.content.article.url'|trans }}</span><i class="fa fa-question-circle fa-lg ml-1"></i> </div> </div> <div class="col mb-2"> {{ form_widget(form.url) }} {{ form_errors(form.url) }} </div> </div> <div class="row"> <div class="col-3">&nbsp;</div> <div class="col mb-2"> {{ form_widget(form.link_method) }} {{ form_errors(form.link_method) }} </div> </div> <div class="row"> <div class="col-3"> <div class="d-inline-block" data-tooltip="true" data-placement="top" title="{{ 'tooltip.content.article.body'|trans }}"> <span>{{ 'admin.content.article.body'|trans }}</span><i class="fa fa-question-circle fa-lg ml-1"></i> </div> </div> <div class="col mb-2"> {{ form_widget(form.description) }} {{ form_errors(form.description) }} </div> </div> {# エンティティ拡張の自動出力 #} {% for f in form if f.vars.eccube_form_options.auto_render %} {% if f.vars.eccube_form_options.form_theme %} {% form_theme f f.vars.eccube_form_options.form_theme %} {{ form_row(f) }} {% else %} <div class="row mb-2"> <div class="col-3"> <span>{{ f.vars.label|trans }}</span> </div> <div class="col"> {{ form_widget(f) }} {{ form_errors(f) }} </div> </div> {% endif %} {% endfor %} </div> </div> </div> </div> <div class="c-conversionArea"> <div class="c-conversionArea__container"> <div class="row justify-content-between align-items-center"> <div class="col-6"> <div class="c-conversionArea__leftBlockItem"> <a class="c-baseLink" href="{{ url('admin_content_article') }}"> <i class="fa fa-backward" aria-hidden="true"></i> <span>{{ 'admin.content.article_management'|trans }}</span></a> </div> </div> <div class="col-6"> <div id="ex-conversion-action" class="row align-items-center justify-content-end"> <div class="col-auto"> {{ form_widget(form.visible) }} {{ form_errors(form.visible) }} </div> <div class="col-auto"> <button class="btn btn-ec-conversion px-5" type="submit">{{ 'admin.common.registration'|trans }}</button> </div> </div> </div> </div> </div> </div> </div> </div> </form> {% endblock %}
■文字列定義の作成 app\config\eccube\packages\eccube_nav.yaml に追記(news の直下)
article: name: admin.content.article_management url : admin_content_article
src\Eccube\Resource\locale\messages.en.yaml をもとに app\Customize\Resource\locale\messages.en.yaml を作成
front.block.article.title__en: ARTICLE front.block.article.title__ja: Article front.block.article.read_more: More front.block.article.see_details: Read details admin.home.article_title: Article admin.content.article_management: Article admin.content.article.publish_date: Published on admin.content.article.display_status: Display Status admin.content.article.display_status__show: Displayed admin.content.article.display_status__hide: Hidden admin.content.article.title: Title admin.content.article.url: URL admin.content.article.body: Body admin.content.article.article_registration: Create News admin.content.article.new_window: Open in a New Window tooltip.content.article.url: If there is a page which provides the details of this article, enter its URL. You can also enter external URLs. tooltip.content.article.body: You can use HTML tags.
src\Eccube\Resource\locale\messages.ja.yaml をもとに app\Customize\Resource\locale\messages.ja.yaml を作成
front.block.article.title__en: Article front.block.article.title__ja: 記事 front.block.article.read_more: more front.block.article.see_details: 詳しくはこちら admin.home.article_title: 記事 admin.content.article_management: 記事管理 admin.content.article.publish_date: 公開日時 admin.content.article.display_status: 公開状態 admin.content.article.display_status__show: 公開 admin.content.article.display_status__hide: 非公開 admin.content.article.title: タイトル admin.content.article.url: URL admin.content.article.body: 本文 admin.content.article.article_registration: 記事登録 admin.content.article.new_window: 別ウィンドウで開く tooltip.content.article.url: この記事の詳細な内容を記したウェブページある場合、URLを入力します。外部サイトのURLなどを利用することもできます。 tooltip.content.article.body: HTMLタグが利用可能です。
app\config\eccube\packages\eccube.yaml に追記(news の直下)
eccube_article_start_year: 2000
■動作確認 管理画面の「コンテンツ管理 → 記事管理」から、データの登録編集削除を行える 挙動は基本的に「新着情報管理」と同じ

Advertisement