Expressフォームのデザインカスタマイズ方法

n.yuumi
n.yuumi

concrete5には、フォームを作成用のExpressフォームブロックがあります。
今回はそのExpressフォームブロックのデザインをカスタマイズする方法について説明していきたいと思います。
 

カスタムコントローラー作成

 
カスタムフォームコントローラーを作成します。
このカスタムフォームコントローラーを作成することで、自身でカスタムしたフォームコンテキストをconcrete5が優先的に見るように仕向けることができます。
カスタムフォームはパッケージディレクトリ内に設置してください。
 
まず、今回は例として、/src直下にTestSiteディレクトリを作成し、/scr/TestSiteをPSR-4 オートローダーとして登録してみます。
パッケージのcontroller.phpに下記のように記載してください。
 
protected $pkgAutoloaderRegistries = array(
    'src/TestSite' => '\TestSite',
);
この設定を行うと、パッケージ直下の/src/TestSiteディレクトリがrootディレクトリとして登録されます。
つまり、どんな階層のどんなクラスであってもこの/src/TestSiteディレクトリ以下に存在するものは自動でロードされるようになります。
 
express1.png
 
PSR-4 オートロード設定が完了したら、いよいよカスタムフォームコントローラーを作成していきます。
先ほど、登録した/src/TestSiteの中にカスタムフォームコントローラーを作成してください。
 
express2.png
 
まずは下記の通り記載してください。
coreのExpress FormのStandardControllerクラスを継承します。namespaceは、$pkgAutoloaderRegistriesで登録済なのでTestSiteから指定が可能です。
 
<?php
namespace TestSite\Express\Controller;
use Concrete\Core\Express\Controller\StandardController;

class FormController extends StandardController
{

}
次に、​​​​on_start()設定を行います。パッケージコントローラーに下記のように記載してください。
setStandardController()にカスタムフォームコントローラーを定義することで、優先的にカスタマイズした方が使用されるようになります。
 
public function on_start()
{
    $this->app->make('Concrete\Core\Express\Controller\Manager')
        ->setStandardController('TestSite\Express\Controller\FormController');
}

コンテキストレジスタの実装

それでは、コンテキストを作成していきます。
 
expressform4.png
 
まずは処理は書かず、下記のようにクラスだけ定義してください。その際、コアのConcrete\Core\Express\Form\Context\FrontendFormContextクラスを継承してください。
 
<?php
namespace TestSite\Express\Form\Context;

use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;

class FrontendFormContext extends CoreFrontendFormContext
{

}
 
それでは、先ほど作成したコンテキストをカステムフォームコントローラーに登録していきましょう。
コードは下記を参照してください。
 
<?php
namespace TestSite\Express\Controller;
use Concrete\Core\Express\Controller\StandardController;
use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;
use TestSite\Express\Form\Context\FrontendFormContext;
use Concrete\Core\Form\Context\Registry\ContextRegistry;

class FormController extends StandardController
{

    public function getContextRegistry()
    {
        return new ContextRegistry([
            CoreFrontendFormContext::class => new FrontendFormContext()
        ]);
    }
}

コンテキストをカスタマイズ

カスタムフォームコントローラーでカスタムコンテキストの登録が完了したので、コンテキストで設定を行なっていきたいと思います。
このコンテキストは、探索パスをの優先順位をコアではなく自身で追加した/packages/theme_testに設定する役割を持っています。設定は、prependLocation()でディレクトリの設定をしたあと最後に'theme_test'と記載するだけです。
 
<?php
namespace TestSite\Express\Form\Context;

use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;
use Concrete\Core\Filesystem\TemplateLocator;

class FrontendFormContext extends CoreFrontendFormContext
{
    public function setLocation(TemplateLocator $locator)
    {
        $locator = parent::setLocation($locator);
        $locator->prependLocation([DIRNAME_ELEMENTS .
            DIRECTORY_SEPARATOR .
            DIRNAME_EXPRESS .
            DIRECTORY_SEPARATOR .
            DIRNAME_EXPRESS_FORM_CONTROLS .
            DIRECTORY_SEPARATOR .
            DIRNAME_EXPRESS_FORM_CONTROLS // not a typo
            , 'theme_test']);
        return $locator;
    }
}

カスタムコントロールテンプレート作成

次に、カスタムコントロールテンプレートを作成しますが、コアからコピペで大丈夫です。
このform.phpファイルを
concrete/elements/express/form/form/form.php
自分のパッケージディレクトリにコピーしてください。
packages/theme_test/elements/express/form/form/form.php
 
 

expressc.png

expressp.png

<?php

use Concrete\Core\Page\Page;

defined('C5_EXECUTE') or die("Access Denied.");
/**
 * @var Concrete\Core\Express\Form\Context\FrontendFormContext $context
 * @var Concrete\Core\Entity\Express\Form $form
 * @var Concrete\Core\Validation\CSRF\Token $token
 */

$page = Page::getCurrentPage();
if (!$page || $page->isError() || !$page->isEditMode()) {
    $token->output('express_form');
}
?>
<input type="hidden" name="express_form_id" value="<?=$form->getID()?>">
<div class="ccm-dashboard-express-form">
    <?php
    foreach ($form->getFieldSets() as $fieldSet) { ?>

        <fieldset>
            <?php if ($fieldSet->getTitle()) { ?>
                <legend><?= h($fieldSet->getTitle()) ?></legend>
            <?php } ?>

            <?php

            foreach($fieldSet->getControls() as $setControl) {
                $controlView = $setControl->getControlView($context);

                if (is_object($controlView)) {
                    $renderer = $controlView->getControlRenderer();
                    print $renderer->render();
                }
            }

            ?>
        </fieldset>
    <?php } ?>
</div>

属性をカスタマイズ

Expressフォームには、テキストやテキストエリア、メール、チェックボックスなどさまざまな属性が存在します。
フォームのコンテキストファイルを作成したように、属性用のコンテキストファイルもカスタマイズが必要です。
ひとまずコアのConcrete\Core\Attribute\Context\FrontendFormContextクラスを継承したコンテキストクラスを定義してください。
 
attribute.png
 
<?php
namespace TestSite\Attribute\Context;

use Concrete\Core\Attribute\Context\FrontendFormContext as BaseFrontendFormContext;

class FrontendFormContext extends BaseFrontendFormContext
{

}
それでは、ExpressフォームのコンテキストのgetAttributeContext()で先ほど追加した属性のコンテキストを定義します。
 
<?php
namespace TestSite\Express\Form\Context;

use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;
use Concrete\Core\Filesystem\TemplateLocator;

class FrontendFormContext extends CoreFrontendFormContext
{
    // Set Attribute Context
    public function getAttributeContext()
    {
        return new \TestSite\Attribute\Context\FrontendFormContext();
    }

    public function setLocation(TemplateLocator $locator)
    {

        $locator = parent::setLocation($locator);
        $locator->prependLocation([DIRNAME_ELEMENTS .
            DIRECTORY_SEPARATOR .
            DIRNAME_EXPRESS .
            DIRECTORY_SEPARATOR .
            DIRNAME_EXPRESS_FORM_CONTROLS .
            DIRECTORY_SEPARATOR .
            DIRNAME_EXPRESS_FORM_CONTROLS // not a typo
            , 'theme_test']);
        return $locator;
    }
}

属性コンテキストをカスタマイズ

それでは、属性のコンテキストの処理を記載していきます。
 
まずはコンストラクタの設定です。
preferTemplateIfAvailable()にテンプレートとパッケージハンドル名を定義してください。
 
テンプレート名は自由に決められますが、今回は例としてテンプレートをtestと設定しました。
 
例)テキスト属性をカスタマイズ
 
concrete5はtest.phpファイルを探しにいきます。
packages/theme_test/attributes/text/test.php
 
もし存在しない場合、コアの属性ファイルを読みにいくような仕様になります。
concrete/attributes/text/form.php
 
public function __construct()
{
    parent::__construct();
    $this->preferTemplateIfAvailable('test', 'theme_test');
}
コンストラクタの設定が完了したら、次はsetLocation()の設定です。
ここでは、各属性のラッパーとなるHTML部分を定義したファイルの設定を行います。
 
こちらも任意の名前で定義可能ですが、例としてtestという名前でテンプレート設定したので、ファイルもtest.phpとします。
 
packages/theme_test/elements/form/test.php
 
public function setLocation(TemplateLocator $locator)
{
    $locator->setTemplate(['test', 'theme_test']);
    return $locator;
}

属性フォームテンプレート作成

ここまで設定が完了したら、あとは自由に属性のカスタマイズが可能になります。
コアからコピー&属性のコンテキストファイルで定義したテンプレート名にファイル名を変えてあげるだけです。
 
例)
属性のラッパーとなるHTMLが記載されたファイル
concrete/elements/form/bootstrap3.php
packages/theme_test/elements/form/test.php
 
属性が定義されたファイル
concrete/attributes/text/form.phpconcrete/attributes/email/form.php....
packages/theme_test/attributes/text/test.phppackages/theme_test/attributes/email/test.php...
 

expressbefore.png

                      ↓

expressafter.png

このようにExpressフォームはデザインを自由にカスタマイズすることが可能です。
色々とファイルの設定はありますが、一度設定してしまえば自由にデザインを更新することできるので、是非お試しください。
 
また、英語での記載になりますが、こちらにも詳しいカスタマイズ方法が載っていますので参考にしてみてください。