こんにちは。たかぴーです。
EC-CUBEで動的にブロック配置をする
EC-CUBEには、ブロックレイアウトの管理機能があって、メインコンテンツを真ん中に据えて、周りにブロックと呼ばれる小さなパーツを並べられる。
もちろんブロック自体が独立して動いていて、どこにでも配置できるような形で。
ちなみにblocなのかblockなのかアヤシイ。
Silexベースで実装してみた
View
まず、Viewの設計から。
できれば大元ではワンライナーで呼び出してるっぽくしたいと思い、以下のような呼び出しを想定。
{{ render(path('bloc', {'position': 'HEAD'})) }}
こうすることで、site_main.twigの見通しがダンチ。
次にbefore()ミドルウェアを使って、DIコンテナに突っ込む。
こうすることでサブリクエスト時には動作せず、何回もクエリが投げられずに済む。
$app->before( function(Request $request, Application $app) {
$qb = $app['orm.em']->createQueryBuilder()
->select('p, bp, b')
->from('Eccube\Entity\PageLayout', 'p')
->leftJoin('p.BlocPositions', 'bp', \Doctrine\ORM\Query\Expr\Join::WITH, 'p.page_id = bp.page_id OR bp.anywhere = 1')
->innerJoin('bp.Bloc', 'b')
->andWhere('p.device_type_id = :device_type_id AND p.url = :url')
->addOrderBy('bp.target_id', 'ASC')
->addOrderBy('bp.bloc_row', 'ASC');
$result = null;
try {
$result = $qb->getQuery()
->setParameters(array(
'device_type_id' => 10,
'url' => $url,
))
->getSingleResult();
} catch (\Doctrine\ORM\NoResultException $e) {
}
$app['eccube.layout'] = $result;
});
続いて、
site_main.twigから呼び出されるControllerはこちら。
ただtargetIdに合致する配列だけを引っ張って$blocに突っ込んでるだけです。
namespace Eccube\Controller;
class BlocController
{
public function index(Application $app)
{
$position = $app['request']->get('position');
$blocs = array();
if ($app['eccube.layout']) {
foreach ($app['eccube.layout']->getBlocPositions() as $blocPositions) {
if ($blocPositions->getTargetId() == constant("Eccube\Entity\BlocPosition::" . $position)) {
$blocs[] = $blocPositions->getBloc();
}
}
}
return $app['twig']->render('bloc.twig', array(
'blocs' => $blocs,
));
}
}
View側は、ループ回してそれぞれのblocのcontroller呼びに行ってるだけなので割愛。
サブリクエストにすることで、before()は1回しか通らないし、リクエストも無駄に投げられないしで、作りながら「もし◯◯だったらどうしよ...」っていうのをことごとく回避してくれてました。
symofnyって本当によく考えられたフレームワークですよね。
というわけでまた次回〜!