Symfony

EC-CUBEがSymfonyを使っていて、やっぱりHTMLテンプレートを使っているので、見ておいた。長くなってきたので以下から移動した。
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/HTML/CSS/PHP%a4%ce%ce%fd%bd%ac%20%bc%c2%c1%a9%20%bb%a8%c2%bf%a4%ca%b5%ad%cf%bf
途中からEC-CUBEをLaravel化してみる事となり、以下の続きとなった。
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/EC%2dCUBE%20%bb%c8%a4%a4%ca%fd

SymfonyとLaravelの関係は?
SymfonyとLaravelは、どちらもPHPで構築された人気のあるフレームワークですが、それぞれに異なる特徴があります。ただし、両者の間には深い関係があり、特にLaravelがSymfonyの多くのコンポーネントを利用している点で結びついています。(ChatGPT)
### 関係の詳細:
\- **Symfonyのコンポーネント使用**: Laravelは、Symfonyのいくつかのコンポーネント(HTTPリクエスト、ルーティング、セッション管理、フォームハンドリングなど)を内部的に使用しています。これにより、Laravelはモジュール化された、信頼性の高い基盤を持っています。
\- **アーキテクチャの違い**: Symfonyは、「フルスタック」フレームワークとして設計されており、非常にカスタマイズ性が高く、再利用可能なコンポーネントを提供します。一方、Laravelは使いやすさと開発者の生産性向上に焦点を当てており、よりシンプルなセットアップで迅速にプロジェクトを開始できます。
\- **学習曲線**: Laravelはそのシンプルさと豊富なドキュメントにより、初心者に優しい設計です。一方、Symfonyは強力ですが、より深い理解と構成のカスタマイズを要求することが多いため、学習曲線がやや急です。
### 結論として:
LaravelはSymfonyのコンポーネントに依存しており、これがLaravelの基盤を支えていますが、Laravel独自の特徴(簡単なルーティング、Eloquent ORM、Bladeテンプレートなど)により、異なるユーザー層に向けたフレームワークとして位置づけられています。
$ ls -l 60-nouen3/vendor/symfony/ | wc -l
28
$ ls -l ec-cube/vendor/symfony/ | wc -l
73
確かにLaravelは(28/73)でSymfonyに依存してる。

Laravelにて、ecommerce-app/resources/views/shop/list.blade.php にて商品一覧を作成したが、Symfonyの https://github.com/EC-CUBE/ec-cube/tree/4.3 のどのファイルがこれに相当するか?
Laravelの`resources/views/shop/list.blade.php`は、商品一覧を表示するビューに相当します。SymfonyベースのEC-CUBEでは、同様の商品一覧ビューがテンプレートファイル内にあります。EC-CUBEのファイル構造を基にすると、商品一覧ページは主に次のファイルに相当します。
\**EC-CUBEの商品一覧に該当するファイル:**
\- `src/Eccube/Resource/template/default/Product/list.twig`
このファイルが、商品一覧ページのテンプレートに相当します。Twigテンプレートエンジンが使用されており、LaravelのBladeテンプレートに相当する構造で、商品データの表示に使用されます。
また、商品一覧に関連するコントローラ部分は以下にあります:
\- `src/Eccube/Controller/ProductController.php`
このコントローラが、商品一覧を取得し、ビューに渡す役割を果たします。

Laravelの ecommerce-app/routes/web.php は、Symfonyのどのファイルがこれに相当するか?
Laravelの`routes/web.php`は、アプリケーションのルーティングを定義するファイルです。SymfonyやEC-CUBEでは、ルーティングの定義はYAMLファイルやアノテーションを使って行われます。Symfony (EC-CUBEも同様) の場合、Laravelの`routes/web.php`に相当するのは、以下のファイルや設定です。
\**Symfony (EC-CUBE) のルーティングに該当するファイル:**
1. **`config/routes.yaml`**
\ – SymfonyではYAML形式でルーティングを定義するのが一般的です。このファイルにルートを定義します。
2. **`src/Eccube/Controller` ディレクトリ内のコントローラ**
\ – EC-CUBEでは、各コントローラ内でPHPのアノテーションを使ってルートを定義することもあります。例えば、`@Route(“/shop”)`などで、コントローラにルートを直接バインドする方法です。
具体例として、商品一覧ページに関するルートは、以下のように`ProductController.php`内で定義されるか、`routes.yaml`に書かれます。
\**例 (routes.yaml):**
\product_list:
\ path: /products
\ controller: Eccube\Controller\ProductController::index
このように、`routes.yaml`にルートのパスと対応するコントローラメソッドを定義することで、Laravelの`routes/web.php`と同様の役割を果たします。

\/**
\ * 商品一覧画面.
\ *
\ * @Route(“/products/list”, name=”product_list”, methods={“GET”})
\ * @Template(“Product/list.twig”)
\ */
というのはコメントではなく、コード生成に使用されているのか?
はい、`@Route(“/products/list”, name=”product_list”, methods={“GET”})` や `@Template(“Product/list.twig”)` は単なるコメントではなく、**Symfonyのアノテーションルーティング**で使用される**実際のコード**です。これらはSymfonyによって解釈され、ルーティングやビューの設定に使われています。
### 詳細説明:
#### 1. **`@Route` アノテーション**
\- `@Route(“/products/list”, name=”product_list”, methods={“GET”})` は、Symfonyのアノテーションルーティングの一部です。
\- これは、**実際にコードとして機能しており**、Symfonyのルーティングシステムがこのアノテーションを読み取って、`/products/list` というURLにアクセスしたときに `ProductController` の `index()` メソッドを呼び出すようにします。
\- また、`name=”product_list”` は、このルートに名前をつけて、テンプレートや他のコントローラから簡単に参照できるようにしています。
#### 2. **`@Template` アノテーション**
\- `@Template(“Product/list.twig”)` も、Symfonyが提供するアノテーションの一つです。これは、対応するビューとして`Product/list.twig`テンプレートを指定しています。
\- このアノテーションを使うと、`index()` メソッドから直接テンプレートをレンダリングするコードを書く必要がなく、アノテーションによって自動的にビューがレンダリングされます。
### 結論:
これらのアノテーションはSymfonyのアノテーション機能によって**実際のコードとして機能**し、ルーティングやテンプレートのレンダリングなど、アプリケーションの動作に直接関わっています。単なるコメントとは異なり、コードの生成や動作に重要な役割を果たしています。

/*************************************************************************************/
EC-CUBEのUIをLaravel化することで、デザインを学ぶ(パクる)。
https://www.ec-cube.net/manual/ec-cube4/front/front_top.php
https://ec-cube.com/admin/content/page
全部で41画面ある。とりあえず、Laravel+Lunarに移植して表示させてみる。

以下のSymfonyのindex.twigをLaravelのindex.blade.phpへ変換せよ。(コードのメモは省略)
このコードでは、Twig構文をBlade構文へ置き換えています。また、Twigの{% block %}はBladeの@sectionに相当し、{% extends %}は@extendsで、{% set %}はBladeでは必要がないため、直接@sectionで定義しています。
このBladeテンプレートはTwigテンプレートからの変換において、Twig構文をBlade構文へ置き換え、{{ }}や{% %}などをLaravel用のBlade構文に適用しています。また、Twigのincludeやtransといった関数もBladeに置き換えました。
$ sudo cp -i -a ec-cube/html ecommerce-app/public/
$ emacs ecommerce-app/resources/views/ec_cube/index.blade.php &
asset(‘assets/img/top/img_hero_pc01.jpg’) -> asset(‘html/template/default/assets/img/top/img_hero_pc01.jpg’) 変更。

以下のSymfonyのBaseInfo.phpをLaravelでのBaseInfo.phpへ変換せよ。(コードのメモは省略)
LaravelでのBaseInfo.phpモデルに変換した例です。EC-CUBEのDoctrine ORMアノテーションをEloquent ORMの形式に置き換え、Laravelの標準的な構文にしています。
$ emacs ecommerce-app/app/Models/BaseInfo.php &
主な変更点の説明:
1.ORMアノテーションからEloquent ORMへ: Doctrineの@ORMアノテーションは不要となり、$fillableと$castsプロパティでLaravelの設定を行いました。
2.関係メソッド: country()とpref()メソッドを定義し、リレーションを設定しています。
3.アクセサ/ミューテータ: getCompanyNameAttributeやsetCompanyNameAttributeなどのアクセサ・ミューテータを利用し、データへのアクセスや設定をカスタマイズ可能にしています。
4.日付フォーマット: Carbonで日付型に変換し、LaravelのEloquent標準に合わせました。
主な変更点の説明2:
SymfonyベースのBaseInfo.phpコードをDoctrine ORMからLaravelのEloquent ORMへ変換する方法は以下の通りです。この変換では、各getterおよびsetterメソッドをLaravelのEloquentアクセサおよびミューテータ規約に従って再現し、不必要なDoctrineアノテーションを削除し、Laravelモデルの一般的な属性でクラスを設定します。
・Fillable属性: mass-assignment可能な属性を定義するために、fillable配列を設定します。
・データキャスト: casts配列を使用して属性のデータ型を定義し、日付や小数フィールドの処理を容易にします。
・アクセサ/ミューテータの命名: Laravelのアクセサとミューテータは、getAttributeおよびsetAttributeの命名規則に従い簡略化されています。
主な変更点の説明3:
1.Fillable属性: fillableに定義された属性は、Doctrineのsetterメソッドを使用するのと同様に、マスアサインメント(複数のプロパティを一括で設定する方法)に対応しています。これにより、指定したプロパティが一括設定可能となり、データベースへの保存時の安全性が高まります。
2.型キャスト(Casting): Laravelのcastsプロパティを使用して、特定の属性を特定のデータ型に変換しています。例えば、フラグとして使用される属性はboolean型としてキャストされ、取り扱いやすくしています。
3.リレーションシップ: CountryやPrefの外部キー設定を、Symfonyの方法からLaravel EloquentのbelongsToメソッドに置き換え、リレーションシップを定義しています。これにより、他のテーブルとの関連付けを明確にしています。
4.アクセサとミューテータ: 各ゲッターとセッターをLaravelのアクセサ/ミューテータのパターンに変更しました。これにより、属性の値を取得・設定する際に、モデル内でカスタム処理が容易になります。

DB(eccube_001)のテーブル(dtb_base_info)を別のDB(laravel_001)へコピーして追加した。
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/MySQL%28MariaDB%29

上の resources/views/Layout/default_frame.blade.php にて発生したエラー
Undefined variable $BaseInfo
のために、app/Models/BaseInfo.php を作成したが、どうやってこれを読みこ込ませるか?
app/Models/BaseInfo.php のモデルを default_frame.blade.php ビューに読み込ませるには、以下の2つの方法があります。
方法1: コントローラーから読み込む
1.コントローラー内で BaseInfo モデルのデータを取得します。
2.compact() 関数や連想配列でビューに渡します。
\ use App\Models\BaseInfo;
\
\ public function someControllerMethod()
\ {
\ $baseInfo = BaseInfo::first(); // 例として1つのレコードを取得
\ return view(‘Layout.default_frame’, compact(‘baseInfo’));
\ }
3.こうすることで、 default_frame.blade.php 内で $baseInfo が利用可能になります。
方法2: ビューコンポーザーを使用する
複数のビューで BaseInfo データを使用したい場合は、ビューコンポーザーを使うと便利です。これにより、特定のビューに毎回コントローラー経由で渡す手間が省けます。
1.サービスプロバイダー(例: App\Providers\AppServiceProvider)内でビューコンポーザーを定義します。
\ use App\Models\BaseInfo;
\ use Illuminate\Support\Facades\View;
\
\ public function boot()
\ {
\ View::composer(‘Layout.default_frame’, function ($view) {
\ $view->with(‘baseInfo’, BaseInfo::first());
\ });
\ }
2.これで、default_frame.blade.php ビュー内で自動的に $baseInfo が使用できるようになります。
いずれかの方法で実装後、 default_frame.blade.php 内で $baseInfo が利用可能になり、エラーが解消されるはずです。

meta.blade.php で使用している $Page は、https://github.com/EC-CUBE/ec-cube/tree/4.3 のどのファイルを Larabel に変換して渡すか?
EC-CUBE 4.3のmeta.twigファイルで使用されている$Page変数は、通常、src/Eccube/Entity/Page.phpファイル内に定義されているPageエンティティクラスに由来します。このPage.phpファイルをLaravelのモデルに変換することで、meta.blade.phpファイルから同様のデータにアクセスできるようになります。
Laravel用にPage.phpを適用するには、app/ModelsディレクトリにモデルファイルPage.phpを作成し、対応するデータベースのフィールドを属性として定義します。LaravelのEloquent ORMを使用すれば、リレーションやアクセサが処理され、Bladeテンプレート内で$Pageのデータに直接アクセスすることが可能になります。

ec-cube/src/Eccube/Entity を以下に移植。他のファイルも同様。BaseInfo.phpもこの下に置いた。
$ mkdir app/Models/{Entity,他}
ec-cube/src/Eccube/Resource/template/default/Product を以下に移植。他のファイルも同様。
$ mkdir resources/views/{Block,Cart,Contact,Entry,Forgot,Form,Help,Mail,Mypage,Product,Shopping}

以下のSymfonyのPage.phpをLaravelのPage.phpへ変換せよ。(コードのメモは省略)
主な変更点
1.Eloquent ORM: Doctrineのアノテーションは不要です。代わりに、テーブル名やプライマリキーをプロパティで指定。
2.リレーション設定: hasManyやbelongsToを使用して、PageLayoutやMasterPageとの関係を定義。
3.メソッドの修正: getLayouts()とgetSortNo()メソッドもLaravelのコレクションメソッドを使用して簡潔に実装。

DB(eccube_001)のテーブル(dtb_page他)を別のDB(laravel_001)へコピーして追加した。
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/MySQL%28MariaDB%29

以下のSymfonyのLayout.phpをLaravelのLayout.phpへ変換せよ。(コードのメモは省略)
Laravelへの変換では、以下の点に注目します:
・エンティティのアノテーションの違い:SymfonyはDoctrineのアノテーション(@ORM)を用いてエンティティのプロパティやリレーションを定義しますが、LaravelではEloquent ORMを使用するため、モデルのプロパティやリレーションはメソッドベースで定義されます。
・リレーションの変換:Symfonyでの@OneToManyや@ManyToOneなどのアノテーションは、LaravelではhasManyやbelongsToといったメソッドで指定します。
・型指定の違い:Doctrineのアノテーションによる型指定やカラムの詳細(例:@ORM\Column(type=”integer”, options={“unsigned”:true}))は、Laravelのマイグレーションファイル内で対応するカラムタイプや制約を定義して設定します。
・定数やメソッド:Symfonyと同様に、Laravelでもクラス内でconstで定数を定義可能です。メソッドは変換の際に基本的には同様に定義できますが、Eloquentのメソッドと互換性のあるように注意が必要です。

名前空間とエンティティ宣言:名前空間の宣言やuse文は、SymfonyとLaravelの間で類似していますが、DoctrineのアノテーションはEloquentのリレーションや属性に置き換える必要があります。
1.クラス定義:Laravelのモデルは通常、Illuminate\Database\Eloquent\Modelを拡張し、AbstractEntityは使用しません。また、Doctrineのような継承はEloquentではサポートされていないため、継承に関する部分は簡略化します。
2.定数とリレーション:クラス内で直接定数を定義し、BlockPositionsやPageLayoutsのようなコレクションの処理には、Eloquentリレーション(hasManyなど)を使用します。
3.メソッド:getPages、getBlocks、getColumnNumなどのカスタムメソッドは保持できますが、Eloquentリレーションの構文はDoctrineと若干異なるため注意が必要です。
重要な違いと考慮点
・Doctrineアノテーション:protected $tableやprotected $fillable、およびhasManyなどのリレーションメソッドを使い、Doctrineのアノテーションを置き換えます。
・コレクションとソート:LaravelのCollectionには、sortByのようなソートヘルパーがあり、Doctrineのソート機能に代わります。
・日付:Laravelはデフォルトでcreated_atおよびupdated_atを使用しますが、元のコードがcreate_dateやupdate_dateを使用しているため、$fillableでこれらのフィールドを明示的に宣言します。

以下のSymfonyのlang.twigをLaravelのlang.blade.phpへ変換せよ。(コードのメモは省略)
・Laravelでは、Symfonyの|transフィルターの代わりに__()ヘルパー関数を使用して翻訳文字列を取得します。
・Bladeの構文では、変数の出力には{{ }}を使用し、Twigと同じ書き方が可能です。
このLaravel版コードは、アプリケーションで設定されている現在のロケールに基づいて、適切な言語の文字列を取得します。resources/lang/en/common.phpやresources/lang/en/front.phpなどに、common.delete_confirmやfront.product.out_of_stockが定義されている必要があります。

以下のSymfonyのblock.twigをLaravelのblock.blade.phpへ変換せよ。(2024.11)
変換のポイント
1.{% for %} と {% endfor %}:
・Twigのforループは、Bladeの@foreachと@endforeachに変換されています。
2.{% if %} と {% else %}:
・条件分岐の構文は、Bladeの@ifと@elseに変更されています。
3.render(path(…)):
・render(path(…))は、Bladeでの{!! route(…) !!}に変更されました。
・route関数はURLを生成し、Bladeでは通常の変数やHTMLをレンダリングするために {!! … !!} を使用します。
4.include_dispatch:
・include_dispatchの代わりに、Bladeの@includeを使用しています。Bladeの@includeは、ファイルパスがresources/viewsからの相対パスである必要があるため、ファイルパスにBlock/を付加しています。

{!! $Page->meta_tags !!} と {{ $Page->meta_tags }} の違いは、Laravel の Blade テンプレートにおけるエスケープ処理の有無です。
1. {{ $Page->meta_tags }}
・エスケープ処理あり。
・出力される値が自動的にエスケープされます。
・HTMLやJavaScriptの特殊文字がサニタイズされ、クロスサイトスクリプティング(XSS)攻撃を防ぎます。
2. {!! $Page->meta_tags !!}
・エスケープ処理なし。
・値がそのまま出力されます。
・例えば、$Page->meta_tags に HTML タグが含まれている場合、そのままブラウザにレンダリングされます。
・注意: この方法は信頼できるデータソースからの値にのみ使用してください。信頼できないデータをそのまま出力すると、XSS の脆弱性を引き起こす可能性があります。
どちらを使うべきか?
・安全性が重要な場合(デフォルトで推奨):{{ $Page->meta_tags }}
・HTMLタグをそのまま出力したい場合(注意が必要):{!! $Page->meta_tags !!}
もし $Page->meta_tags にメタタグやHTMLコンテンツを含むことが想定されているなら、{!! $Page->meta_tags !!} が適していますが、安全性を考慮してデータを検証してから出力してください。

ec-layoutRole__headerが非表示。AIが生成した、default_frame.blade.phpにて、$Layout->Header
は存在しない。$Layout->getHeader() にした。
@dd($layout->Header) が null を返している理由は、Header プロパティが BlockPosition クラスでリレーションとして設定されていないためです。と言われてイロイロ試したが、やっぱり$Layout->Headerは無かった。

CartServiceExtensionは、Laravelでは通常サービスプロバイダとして配置し、app/Providers/ディレクトリに配置することが推奨されます。また、BladeテンプレートではTwig関数の代わりにBladeディレクティブを使います。
1. CartServiceProviderの作成
まず、SymfonyのCartServiceExtensionをLaravelのサービスプロバイダに変換します。ファイルはapp/Providers/CartServiceProvider.phpに配置します。
(ファイル名は変えたくないので、しばらくそのままにしよう)

Twigテンプレートエンジンを使わず、TwigFunctionも使わない。(2024.12)
Laravel Bladeで、カスタム関数を直接呼び出せるようにするために、Laravelで、BladeテンプレートやPHPスクリプト全体で利用可能なグローバル関数を作成した。
app/Models/Extension/CartServiceExtension.php
composer.jsonにautoload設定を追加。
\”autoload”: {
\ “psr-4”: {
\ “App\\”: “app/”,
\ “Database\\Factories\\”: “database/factories/”,
\ “Database\\Seeders\\”: “database/seeders/”
\ },
\ “files”: [
\ “app/Models/Extension/CartServiceExtension.php”
\ ]
\},
$ PATH=$PATH:/usr/local/laravel-composer/:~/.config/composer/vendor/bin/ composer dump-autoload

SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘dtb_cart.deleted_at’ in ‘where clause’
エラーの原因は、dtb_cartテーブルに存在しない列 deleted_at が自動的にクエリに追加されていることです。これは、Laravelの Soft Deletes 機能が関係しています。
・LaravelのEloquentモデルでSoftDeletesトレイトが使われている場合、Eloquentはクエリにdeleted_at IS NULLという条件を自動的に追加します。
・CartモデルでSoftDeletesが有効になっているが、dtb_cartテーブルにdeleted_at列が存在しない場合、このエラーが発生します。
EC-CUBEではSoftDeletesは無いので、Cart.phpからコメントアウトする事にした。

Symfonyでの、cart.twig
<div class=”ec-cartNavi__price”>{{ totalPrice|price }}</div>
が、Laravelでは以下(cart.blade.php)に変換されたが、どういう意味か?
<div class=”ec-cartNavi__price”>{{ price($totalPrice) }}</div>
以下の変換には、SymfonyとLaravelにおけるテンプレートエンジンやカスタムフィルタ・関数の違いが反映されています。
\—
### **Symfonyの`cart.twig`**
twig
<div class=”ec-cartNavi__price”>{{ totalPrice|price }}</div>
#### 意味
\- **`totalPrice`**: 変数で、カート内の商品の合計金額。
\- **`price`フィルタ**: SymfonyのTwigテンプレートエンジンで定義されたカスタムフィルタ。数値を通貨形式に整形します。
\ – 例えば、「`1234|price`」が「`1,234円`」などの形式に変換される。
\—
### **Laravelの`cart.blade.php`**
php
<div class=”ec-cartNavi__price”>{{ price($totalPrice) }}</div>
#### 意味
\- **`price($totalPrice)`**: Laravelでは、`price`という関数をBladeテンプレート内で直接呼び出しています。
\- **Bladeテンプレート**: PHPコードを埋め込める構文(`{{ … }}`)を提供し、直接PHP関数を使用可能。
\—
### **なぜ変換が必要なのか?**
#### 1. **テンプレートエンジンの違い**
\- **Symfony (Twig)**: フィルタ(`|price`のような形式)を使って値を加工します。
\- **Laravel (Blade)**: 関数を直接呼び出すことが多い。
#### 2. **`price`の実装場所の違い**
\- Symfonyでは、`price`はTwigのカスタムフィルタとして実装されています。
\ – フィルタはTwig拡張クラス(例: `AbstractExtension`を継承)を通じて登録されます。
\- Laravelでは、`price`は通常、PHPのグローバル関数やサービスプロバイダで実装されます。
\ – BladeではPHPのネイティブ関数を直接利用できるため、関数呼び出しの形式に変換されています。
#### 3. **パフォーマンスとメンテナンス性**
Laravelでは関数を直接呼び出す形式のほうがシンプルで、パフォーマンス的に効率が良いことがあります。
\—
### **まとめ**
#### Symfony版
\- `totalPrice|price`: Twigフィルタを用いて値を加工。
#### Laravel版
\- `price($totalPrice)`: PHP関数を直接呼び出して値を加工。
この変換により、SymfonyのTwigフィルタをLaravelのBladeテンプレートで適切に置き換えています。`price`関数自体の実装がプロジェクト内のどこかに存在している(または作成されている)はずですので、そのコードを確認してください。
\
無名関数(Closure)を使うことで、特定のスコープ内に限定して関数を使用できます。
vendor/lunarphp/lunar/src/helpers.php lunarのがあったが、ローカル関数でごまかした。
$price = function($yen){ return $yen . ‘円’;} //とりあえずごまかす.

src/Eccube/Entity/Category.php を Laravel へ変換せよ。依存は、 https://github.com/EC-CUBE/ec-cube/tree/4.3/src を参照せよ。
主な変換ポイント
1.プロパティの定義:
・$fillableを使用してデータベースフィールドのマスアサインメントを許可。
・$datesに日時フィールドを設定。
2.リレーションシップ:
・hasManyとbelongsToを使用して親子関係を設定。
・ProductCategoryやCreatorとのリレーションも追加。
3.メソッド:
・DoctrineのメソッドをEloquentに合わせて変換。
4.再帰処理:
・countBranchesやcalcChildrenSortNoなど、再帰的な処理はそのまま保持。

src/Eccube/Repository/CategoryRepository.php を Laravel へ変換せよ。依存は、 https://github.com/EC-CUBE/ec-cube/tree/4.3/src を参照せよ。
変更点および説明
1.リポジトリ層の設計:
・SymfonyのリポジトリはDoctrine依存の設計ですが、LaravelではEloquentモデルとクエリビルダーを組み合わせる形にしました。
2.階層構造の取得:
・with([‘children.children.children.children’])を用いて最大5階層の子カテゴリをロードしています。これにより、N+1問題を回避します。
3.ソート番号の管理:
・ソート番号を保存・削除時に計算し、他のカテゴリのソート番号を調整する処理をEloquentのクエリビルダーで実装。
4.トランザクション管理:
・DB::transactionを使用してデータの整合性を保つようにしました。
5.getSelfAndDescendantsメソッド:
・モデルに定義されたこのメソッドを利用してカテゴリの階層化データを平坦化する処理を実装。
必要なモデル
上記リポジトリを使用するには、Categoryモデルが適切に階層構造 (parent と children) を管理している必要があります。この点は前述のCategoryモデルに適用済みです。

app/Models/Repository/NewsRepository.php を生成する前に app/Models/Entity/News.php を生成させてしまった。
が、それでよかった。正しかった。
NewsRepository は News モデルに依存しています。具体的には、News モデルを通じてデータベースの操作を行います。

Call to undefined method App\Models\Entity\News::getList()
エラーの原因は、News クラス (App\Models\Entity\News) に getList() メソッドが定義されていないことです。
Laravelでは、モデル (News) 自体にはリポジトリパターンで記述されたメソッド (getList()) を持つことはありません。リポジトリパターンはモデルとは独立してデータ操作を管理します。そのため、getList() は NewsRepository に定義されており、モデルから直接呼び出すことはできません。
リポジトリを直接使用するには、コントローラーまたは Blade ファイルで NewsRepository をインスタンス化して使用します。
Blade ファイル内で直接リポジトリを呼び出すのは推奨されません。代わりに、コントローラーで処理を行い、Blade ファイルには必要なデータのみを渡すのがベストプラクティスです。
がしかし、そもそもECCUBEで
\{% set NewsList = repository(‘Eccube\\Entity\\News’).getList() %}
とやっているし、return view(‘index’, [ の引数に全部入れるのもイマイチなので、Bladeの方に持たせる事にした。
route()で一旦ControllerをCallするやり方は、全部終わって整理してから考えよう。

ここまでできている分をBackUpとして残し、コピーして改めてLaravel用を作る。(2024.12,2025.01)
$ sudo cp -i -a ecommerce-app ec-cube_43la
とやろうとしたが、Inst(プロジェクト作成)時点であちこちにecommerce-appが入っていて、ec-cube_43la
でInstし直さないとダメだ。Laravelプロジェクトをec-cube_43laで作成し直し(忘れかけたので丁度よいか。
Lunarがv11のLaravel使えないの忘れてて、v10を入れ直した。後でLunarを使いたくなるかもしれないから)
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/Laravel
$ PATH=$PATH:/usr/local/laravel-composer/:~/.config/composer/vendor/bin/ composer create-project –prefer-dist laravel/laravel:^10.0 ec-cube_43la
て、app,config,public,resources,routesをecommerce-appから移植し、appとその他のpermを変更し、
$ cd ec-cube_43la; ln -sf /myproj/ec-cube_43la/storage/app/public storage
あと、LunarとそのDBは削除した。
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/MySQL%28MariaDB%29
\
Symfony(EC-CUBE)とLaravelのViewのファイル構成に対する認識を間違えて、EC-CUBEの、
ec-cube/src/Eccube/Resource/template
\ ├── admin/{Content,Customer,…}
\ ├── common/
\ ├── default/{Block,Cart,…}
\ ├── install/
\ ├── smartphone/
\ └── toolbar/
に対してLarabelで、
ecommerce-app/resources/views
\ └── {Block,Cart,…}
とやってしまった。とりあえず以下に修正。足りなくなったら後から追加するか。
ecommerce-app/resources/views
\ ├── admin/{Content,Customer,…}
\ └── default/{Block,Cart,…}
\
composer.json のautoloadに”app/Models/Extension/CartServiceExtension.php”を設定して以下実行。
$ PATH=$PATH:/usr/local/laravel-composer/:~/.config/composer/vendor/bin/ composer dump-autoload
Generating optimized autoload files
Class App\Models\Service\Session\Session located in ./app/Models/Session/Session.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Repositories\BaseInfoRepository located in ./app/Models/Repository/BaseInfoRepository.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Repository\ProductClassRepository located in ./app/Models/Repository/ProductClassRepository.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Repositories\OrderRepository located in ./app/Models/Repository/OrderRepository.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Utils\StringUtil located in ./app/Models/Util/StringUtil.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Services\CartService located in ./app/Models/Service/CartService2.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Services\Calculator\OrderItemCollection located in ./app/Models/Service/Calculator/OrderItemCollection.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Services\CartService located in ./app/Models/Service/CartService5.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Services\Cart\CartItemComparator located in ./app/Models/Service/Cart/CartItemComparator.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Services\PurchaseFlow\ItemCollection located in ./app/Models/Service/PurchaseFlow/ItemCollection.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Shipping located in ./app/Models/Entity/Shipping.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Shipping located in ./app/Models/Entity/Shipping.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Order located in ./app/Models/Entity/Order.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Master\TaxType located in ./app/Models/Entity/Master/TaxType.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Master\RoundingType located in ./app/Models/Entity/Master/RoundingType.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Models\Entity\Customer located in ./app/Models/Entity/Customer.old.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Services\CartService located in ./app/Models/Extension/CartServiceExtension3.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Services\CartService located in ./app/Models/Extension/CartServiceExtension2.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Providers\AppServiceProvider located in ./app/Models/Extension/CartServiceExtension2.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Providers\BladeServiceProvider located in ./app/Models/Extension/CartServiceExtension2.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
Class App\Http\Controllers\ShopController located in ./app/Http/Controllers/ShopController2.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
\> Illuminate\Foundation\ComposerScripts::postAutoloadDump
\> @php artisan package:discover –ansi
INFO Discovering packages.
laravel/sail ……………………………………………………………………………………………………………….. DONE
laravel/sanctum …………………………………………………………………………………………………………….. DONE
laravel/tinker ……………………………………………………………………………………………………………… DONE
nesbot/carbon ………………………………………………………………………………………………………………. DONE
nunomaduro/collision ………………………………………………………………………………………………………… DONE
nunomaduro/termwind …………………………………………………………………………………………………………. DONE
spatie/laravel-ignition ……………………………………………………………………………………………………… DONE
Generated optimized autoload files containing 6132 classes
(前回はメモ省略していたので、今回はメモ)
\
package.jsonも記述量が全然足りない。そのうち必要な分は合わせよう。
以下でpackage.jsonはほぼ書いた。
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/EC%2dCUBE%20CSS%a4%c8JS

/*************************************************************************************/
上まででTOPページだけ表示できたと思ったが、よく見るとHTMLが足りてない。やはりChatGPTだけ
(丸投げ)ではムリか。Debugを始めた。(2025.01)

block.twigにて、{{ render(path(‘block_’ ~ Block.file_name)) }} となっている。
Twigの render() と同じように、Laravel Bladeでも即座にルートを実行して結果を埋め込みたい場合は、以下のいずれかの方法を使用します:
方法1: Route::dispatch() を使用する
<?php
$response = Route::dispatch(Request::create(route(‘block_’ . $Block->file_name)));
echo $response->getContent();
?>
方法2: コントローラ内で事前に実行して結果を渡す
コントローラでルートを実行し、その結果をビューに渡します:
$response = app()->handle(Request::create(route(‘block_’ . $Block->file_name)));
$data = $response->getContent();
return view(‘your-view’, compact(‘data’));
ビュー内では次のように出力します:
{!! $data !!}
このようにすることで、BladeでもTwigの render() に近い挙動が再現可能です。

SymfonyのCalendarController.phpは、CalendarRepository.phpに依存しているが、CalendarController.phpをLaravelに変換する場合に、CalendarRepository.phpのLaravelへの変換と依存が必要か?
Symfonyの `CalendarController.php` を Laravel に変換する際、 `CalendarRepository.php` をどう扱うかは以下の要因に依存します:
### 1. **Symfonyの`CalendarRepository.php`の役割を理解する**
Symfonyでは、リポジトリ(Repository)はエンティティとデータベース操作を抽象化する層として使われることが一般的です。
Laravelでも同様の役割を果たす仕組みは次のいずれかで実現されます:
\- **Eloquentモデル**(Laravelのデフォルトで使用されるORM)
\- **クエリビルダ**(柔軟なデータベース操作のための構文)
\- **リポジトリパターンの実装**(必要であれば自前で作成可能)
### 2. **Laravelでリポジトリが必要かどうかの判断**
Symfonyのリポジトリと同じ形態をLaravelで再現する必要があるかどうかは、以下を基準に判断できます:
#### (1) 既存のロジックが単純で、Eloquentモデルで十分
もしリポジトリに単純なクエリロジックのみが含まれている場合、Eloquentモデルやクエリビルダを直接使うことで十分です。この場合、リポジトリの移植は不要です。
\“`php
// Eloquentでの例
\$events = Calendar::where(‘start_date’, ‘>=’, now())->get();
#### (2) 既存のリポジトリが複雑で再利用性が高い
もしリポジトリが複雑なクエリロジックやカスタム処理を含み、複数のコントローラやサービスで再利用されている場合、Laravelでもリポジトリパターンを導入することを検討すべきです。
\“`php
\namespace App\Repositories;
\class CalendarRepository
\{
\ public function getUpcomingEvents()
\ {
\ return Calendar::where(‘start_date’, ‘>=’, now())->get();
\ }
\}
コントローラでリポジトリを依存注入して使用できます。
\“`php
\use App\Repositories\CalendarRepository;
\class CalendarController extends Controller
\{
\ protected $calendarRepository;
\ public function __construct(CalendarRepository $calendarRepository)
\ {
\ $this->calendarRepository = $calendarRepository;
\ }
\ public function index()
\ {
\ $events = $this->calendarRepository->getUpcomingEvents();
\ return view(‘calendar.index’, compact(‘events’));
\ }
\}
#### (3) リポジトリを必要としない場合
場合によっては、Symfonyでリポジトリを使っている理由が特に重要でない場合があります。この場合、リポジトリを省略してコントローラに直接クエリを記述することも可能です(ただし再利用性は低下します)。
### 3. **依存関係をどう扱うか**
Symfonyの `CalendarController.php` が `CalendarRepository.php` に依存している場合、以下の対応が必要です:
#### **(1) リポジトリをLaravelで再現**
`CalendarRepository.php` を Laravel でクラスとして再作成し、必要なメソッドを実装します。Laravelのサービスプロバイダを使って依存注入を設定します。
#### **(2) 依存をEloquentモデルに置き換える**
リポジトリで行っている操作をEloquentモデルのメソッドに置き換えられる場合、リポジトリそのものを省略できます。
### 4. **変換の進め方の例**
#### Symfonyのコード例:
\**`CalendarController.php`**
\“`php
\public function index(CalendarRepository $calendarRepository)
\{
\ $events = $calendarRepository->findUpcomingEvents();
\ return $this->render(‘calendar/index.html.twig’, [‘events’ => $events]);
\}
\**`CalendarRepository.php`**
\“`php
\public function findUpcomingEvents()
\{
\ return $this->createQueryBuilder(‘c’)
\ ->where(‘c.startDate >= :now’)
\ ->setParameter(‘now’, new \DateTime())
\ ->getQuery()
\ ->getResult();
\}
#### Laravelへの変換例:
\**`CalendarRepository.php`**
\“`php
\namespace App\Repositories;
\use App\Models\Calendar;
\class CalendarRepository
\{
\ public function findUpcomingEvents()
\ {
\ return Calendar::where(‘start_date’, ‘>=’, now())->get();
\ }
\}
\**`CalendarController.php`**
\“`php
\use App\Repositories\CalendarRepository;
\class CalendarController extends Controller
\{
\ protected $calendarRepository;
\ public function __construct(CalendarRepository $calendarRepository)
\ {
\ $this->calendarRepository = $calendarRepository;
\ }
\ public function index()
\ {
\ $events = $this->calendarRepository->findUpcomingEvents();
\ return view(‘calendar.index’, compact(‘events’));
\ }
\}
### 結論
1. **単純なロジックの場合**: Eloquentやクエリビルダに直接置き換え、リポジトリを省略可能。
2. **複雑で再利用性が重要な場合**: リポジトリをLaravelに移植し、依存注入を活用。
3. **リポジトリを移植しない場合**: コントローラに直接ロジックを記述する(推奨されない)。
どのアプローチを採用するかは、アプリケーション全体の設計方針に依存します。

以下は、Symfonyの Eccube\Repository\Master\ProductListOrderByRepository をLaravelのリポジトリに変換した例です。Laravelではリポジトリパターンを直接使用しなくても、Eloquent ORMを用いることで多くの操作が可能です。しかし、リポジトリパターンを維持したい場合は以下のように実装できます。
(コードはメモ省略)

Eccube/Resource/template/default/Block/search_product.twigの form_widget()というのはSymfony特有の関数か?
はい、`form_widget()` は **Symfony特有の関数** です。これは、Symfonyの **Twigテンプレートエンジン** が提供するフォームのビルディングブロックの1つです。
### **`form_widget()` の役割**
`form_widget()` は、Symfonyのフォームコンポーネントで作成されたフォームフィールドをレンダリングするために使用されます。この関数は以下のような特徴を持っています:
1. **フォームフィールドのレンダリング**
\ – フォームフィールドのHTML(例:`<input>` や `<select>` タグなど)を自動生成します。
\ – 必要な属性や値を含めて出力します。
2. **Twigを通じた柔軟なカスタマイズ**
\ – Symfonyでは、Twigテンプレートでフォームの表示を簡単にカスタマイズできます。
\ – `form_widget()` を使用すると、個別のフィールドに特定の属性やクラスを簡単に追加できます。
3. **テーマ適用**
\ – `form_widget()` は、設定されたフォームテーマ(例:`form_div_layout.html.twig`)に従って出力を生成します。
### **`form_widget()` の具体例**
以下の例は、Symfonyのフォームで `form_widget()` を使用する方法です。
#### **コントローラー**
\“`php
\public function searchForm(Request $request)
\{
\ $form = $this->createFormBuilder()
\ ->add(‘name’, TextType::class, [‘required’ => false, ‘attr’ => [‘class’ => ‘search-name’]])
\ ->add(‘category_id’, ChoiceType::class, [
\ ‘choices’ => [‘Category 1’ => 1, ‘Category 2’ => 2],
\ ‘required’ => false
\ ])
\ ->getForm();
\ return $this->render(‘search_product.twig’, [
\ ‘form’ => $form->createView(),
\ ]);
\}
#### **Twigテンプレート**
\“`twig
\<form method=”GET” action=”{{ path(‘product_list’) }}”>
\ <div>
\ {{ form_widget(form.category_id, {‘attr’: {‘class’: ‘category_id’}}) }}
\ </div>
\ <div>
\ {{ form_widget(form.name, {‘attr’: {‘placeholder’: ‘Enter keyword’}}) }}
\ </div>
\ <button type=”submit”>Search</button>
\</form>
### **Laravelへの変換**
Laravelでは、Symfonyのような `form_widget()` 関数は提供されていません。ただし、以下の代替手段があります。
1. **`laravelcollective/html` パッケージの利用**
\ – Laravelでは、このパッケージを使用することで、フォームフィールドを簡単に生成できます。
\ – 例:
\ “`php
\ {!! Form::text(‘name’, null, [‘class’ => ‘search-name’, ‘placeholder’ => ‘Enter keyword’]) !!}
\ {!! Form::select(‘category_id’, [1 => ‘Category 1’, 2 => ‘Category 2’], null, [‘class’ => ‘category_id’]) !!}
2. **Bladeテンプレートで直接HTMLを記述**
\ – `form_widget()` の機能を手動で再現する場合、Bladeテンプレートで直接HTMLを記述します。
\ – 例:
\ “`blade
\ <input type=”text” name=”name” class=”search-name” placeholder=”Enter keyword”>
\ <select name=”category_id” class=”category_id”>
\ <option value=”1″>Category 1</option>
\ <option value=”2″>Category 2</option>
\ </select>
3. **コンポーネントを利用**
\ – LaravelのBladeコンポーネントを作成し、`form_widget()` に相当する汎用的なテンプレートを定義します。
\ – 例:
\ “`blade
\ {{– components/form-field.blade.php –}}
\ @props([‘name’, ‘type’ => ‘text’, ‘attributes’ => []])
\ <input type=”{{ $type }}” name=”{{ $name }}” {{ $attributes->merge([‘class’ => ‘form-control’]) }}>
使用例:
\ “`blade
\ <x-form-field name=”name” type=”text” :attributes=”[‘placeholder’ => ‘Enter keyword’, ‘class’ => ‘search-name’]” />
### **まとめ**
\- `form_widget()` は Symfony/Twig に特有の機能です。
\- Laravelでは、`laravelcollective/html` パッケージ、Bladeテンプレート、またはBladeコンポーネントを利用して同様の機能を実現できます。
\- SymfonyからLaravelに移行する場合、`form_widget()` の機能をこれらの手法に置き換える必要があります。

Symfonyの {{ form_widget(form.category_id, {‘id’: null, ‘attr’: {‘class’: ‘category_id’}}) }} が、Laravelにおいての、{!! Form::select(‘category_id’, $form->category_id->choices, null, [‘class’ => ‘category_id’]) !!} となるのは何故か?特になぜselectと分かるのか?
Symfonyでの form_widget() は、フォームのタイプ(例:ChoiceType、TextType など)に基づいて適切なHTMLを自動生成する機能を持っています。そのため、Symfony側でフォームフィールドが ChoiceType として定義されている場合、form_widget() を呼び出すと <select> 要素としてレンダリングされます。
一方、Laravelでは Form::select() を明示的に呼び出して <select> を生成しています。この挙動を比較しながら解説します。(以降はメモ省略)

search_product.blade.php にて、エラーとなった。Class “Form” not found
エラー `Class “Form” not found` が発生する原因は、Laravelで `Form` ヘルパーが利用できない状態になっているためです。Laravelでは、`Form` ヘルパーはデフォルトでは含まれていないため、利用するには追加のセットアップが必要です。
以下は、問題を解決するための手順です。
### **1. Laravel Collective のインストール**
`Form` ヘルパーは Laravel Collective の一部として提供されています。これをインストールする必要があります。
#### インストール手順
以下のコマンドを実行して、`laravelcollective/html` パッケージをインストールします。
$ composer require laravelcollective/html (Inst関係はこっちにメモ。https://seesaawiki.jp/lifewithslackzaurus_15_0/d/Laravel )
### **2. サービスプロバイダーとエイリアスの設定**
Laravel Collective をインストールしたら、`App\Providers\AppServiceProvider` に以下を追加します。
(サービスプロバイダーとは、https://seesaawiki.jp/lifewithslackzaurus_15_0/d/Laravel%a4%ce%a5%c7%a5%b6%a5%a4%a5%f3%a5%d1%a5%bf%a1%bc%a5%f3 )
#### サービスプロバイダーの登録
`App\Providers\AppServiceProvider` ファイルの `boot` メソッドに以下を追加します。
\“`php
\use Collective\Html\HtmlServiceProvider;
\public function register()
\{
\ $this->app->register(HtmlServiceProvider::class);
\}
#### エイリアスの追加
また、同じ `AppServiceProvider` の `boot` メソッドで以下を設定します。
\“`php
\use Collective\Html\FormFacade;
\use Collective\Html\HtmlFacade;
\class_alias(FormFacade::class, ‘Form’);
\class_alias(HtmlFacade::class, ‘Html’);
### **3. ビューで `Form` を使用可能にする**
`Form` ヘルパーが使用可能になるので、`views/default/Block/search_product.blade.php` のコードはそのまま動作するはずです。
### **4. 使用例**
修正後の `search_product.blade.php` は以下のようになります。
(メモ省略)
### **5. エラーチェックとデバッグ**
\- `Form` が正常に動作しない場合、キャッシュが問題となる場合があります。以下のコマンドでキャッシュをクリアしてください:
$ php artisan config:clear
$ php artisan cache:clear
$ php artisan view:clear
\- また、必要に応じて Laravel サーバーを再起動してください:
$ php artisan serve
これで `Class “Form” not found` エラーが解消され、`Form::select` を正しく利用できるようになります。

上で、FormFacadeやHtmlFacade等のFacadeがあるので、LaravelのデザインパターンをAIに聞いてみた。
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/Laravel%a4%ce%a5%c7%a5%b6%a5%a4%a5%f3%a5%d1%a5%bf%a1%bc%a5%f3
サービスプロバイダはこれまでも出てきていたが、動いてるので気にしてなかったが書籍で確認した。
\
ec-cube_43la/config/app.php
\ ‘providers’ => ServiceProvider::defaultProviders()->merge([
\ …
\ App\Providers\CartServiceProvider::class,
\ ])->toArray(),

CartServiceProviderではBlade::directive()を使用しているが、View::composer()とは、どう違うか? (->ChatGPT)
`Blade::directive()` と `View::composer()` は、どちらも Laravel のビュー関連の機能ですが、用途が異なります。
\## **3. `Blade::directive()` と `View::composer()` の違い**
\| 機能 | `Blade::directive()` | `View::composer()` |
\|———————-|————————————————|——————————————-|
\| 目的 | カスタム Blade ディレクティブを作成する | ビューにデータをバインドする |
\| 使用場所 | Blade テンプレート内 (`@customDirective`) | `View::composer()` を設定したビュー |
\| データの取得 | 直接 PHP コードを Blade で埋め込む | 指定したビューに `$view->with()` で渡す |
\| 適用範囲 | Blade の構文で指定した場所 | 指定したビューがレンダリングされるとき |
\| 主な用途 | Blade 内のショートカットを作成 | ビューのデータを動的に渡す |

app/Models/の下に、Service,Entity,Repository,Session,Util,Extension を置いていたがapp/下に
持ってきた。ec-cubeに少し近づけた。ec-cubeはsrc/Eccube/下に全部フラットにあるが。
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/Laravel%a4%ce%b5%a1%c7%bd%ca%cc%a5%c7%a5%a3%a5%ec%a5%af%a5%c8%a5%ea%b9%bd%c0%ae

よく見たら、composer require laravelcollective/html とか、composer dump-autoload をすると、
https://seesaawiki.jp/lifewithslackzaurus_15_0/d/Laravel
Class App\Models\Service\Session\Session located in ./app/Models/Session/Session.php does not comply with psr-4 autoloading standard (rule: App\ => ./app). Skipping.
とか、大量にエラー出てるではないか。気づいてなかった。修正。

以下のSymfonyの ec-cube/src/Eccube/Form/Type/SearchProductBlockType.php を Laravelへ変換せよ。また、Laravelでは何処におくべきか?(コード省略) (->ChatGPT)
Laravel版 SearchProductBlockType.php
Symfonyの AbstractType を使用したフォームクラスは、Laravelでは FormRequest や フォームビルダーを使ったカスタムクラス に置き換えることが多いです。
以下のコードは、 フォームデータのバリデーションとカテゴリー選択肢の取得 を担う Laravel の FormRequest クラスです。(コード省略)
\
Symfonyの FormType は Laravel では FormRequest に変換
EntityType::class の代わりに Eloquentの pluck() を使用
SearchProductBlockRequest は app/Http/Requests/ に配置
コントローラーでリクエストを注入し、ビューに選択肢を渡す
$ mkdir app/Http/Requests
$ emacs app/Http/Requests/SearchProductBlockRequest.php

resources/views/default/Form/form_div_layout.blade.php を使うため、以下をbladeへ変換。
ec-cube/vendor/symfony/twig-bridge/Resources/views/Form/form_div_layout.html.twig
\
form_div_layout.twig が使用しているブロック?、関数?のform_widget_simple は、先のform_div_layout.html.twig の中で定義されているが、{{ parent() }} については見つからない。parent()とは何か?また、Laravelではどう表現すべきか? (->ChatGPT)
## `parent()` とは?
`{{ parent() }}` は、Twig テンプレートの **ブロック継承** に関連する関数です。
Twig では、子テンプレートが `block` をオーバーライドしている場合でも、元の親テンプレートの `block` の内容を呼び出すことができます。
## Laravel での対応方法
Laravel の Blade テンプレートでは `{{ parent() }}` のような直接的な機能はありません。
しかし、**`@extends` と `@section` / `@yield` を使って類似の機能を実現** できます。
\- **Twig の `{{ parent() }}` は、親の `block` を呼び出すためのもの**
\- **Laravel の Blade では `@parent` を使う**
\- **より柔軟にするなら、Blade コンポーネント (`x-component`) を活用**
この方法を使えば、Laravel でも Twig の `parent()` のような継承を再現できます!
\
form_div_layout.twig を @extends @section @yield @parent を使って、form_div_layout.blade.php へ変換せよ。 (->ChatGPT)
以下のように、`form_div_layout.twig` を `form_div_layout.blade.php` へ変換しました。
Blade の `@extends`、`@section`、`@yield`、`@parent` を活用し、Twig の構造を Laravel に適合させています。(コード省略)
## **変換ポイント**
1. **Twig の `{% extends ‘form_div_layout.html.twig’ %}` を `@extends(‘form_div_layout’)` に変更**
\ – これにより、`form_div_layout.blade.php` は `form_div_layout.blade.php` を基に拡張する。
2. **`{% block … %}` を `@section … @endsection` に変更**
\ – 例えば、`{% block form_errors %}` を `@section(‘form_errors’)` に変換。
3. **`{{ parent() }}` を `@parent` に変更**
\ – 例えば、`{% block form_label %}` 内の `{{ parent() }}` を `@parent` にすることで、親テンプレートの処理を呼び出せる。
4. **`{{ block(‘form_widget_simple’) }}` を `@yield(‘form_widget_simple’)` に変更**
\ – `@yield` は Blade で他のテンプレートが提供するコンテンツを差し込むために使用。
5. **Twig のフィルタや関数を Blade に対応**
\ – `{{ error.message|trans({}, translation_domain) }}` → `{{ __($error->message, [], $translation_domain ?? null) }}`
\ – `{{ label is not same as(false) ? (translation_domain is same as(false) ? label : label|trans({}, translation_domain)) }}`
\ → `{{ !empty($translation_domain) && $translation_domain !== false ? __($label, [], $translation_domain) : $label }}`
### **この Blade テンプレートの使い方**
親テンプレート `form_div_layout.blade.php` では、`@yield(‘form_errors’)` や `@yield(‘form_label’)` などを定義しておき、
この `form_div_layout.blade.php` でそれらを `@section` で上書き・拡張する形になります。
\
同じファイル内で @yield と @section を使えるか? (->DeepSeek)
基本的には使えません。(Symfonyのブロック関数(?){% block .. %}は使えている)
@yield は親テンプレートで定義され、@section は子テンプレートで定義されるため、同じファイル内で両方を使うことは通常ありません。
ただし、@section で定義した内容を同じファイル内で @yield に渡すことは可能ですが、これは一般的な使い方ではありません。
例: 同じファイル内での使用(非推奨)
\<!– 同じファイル内で @section と @yield を使う例 –>
\@section(‘content’)
\ <p>これはコンテンツです。</p>
\@endsection
\@yield(‘content’)
この場合、@section で定義した内容が @yield に渡されますが、このような使い方は稀です。
(Symfonyでは再帰的なブロック呼び出しは有効であり、これをLaravel変換すると同一ファイル内で@section
/@yieldを使う処理を生成する)
\
Symfonyのtwigにて、以下のform_widget関数?がある場合、
confirm.twig
{{ form_widget(form.name.name02, { type : ‘hidden’ }) }}
form_div_layout.html.twig
(依存のみ記入。メモは省略)
これらをLaravelの@sectionや@yieldを使って変換せよ。form_widgetはどのように変換されるか説明せよ。
(やっぱり複数ファイルで作ってくる)
@section の場合は {{ form_widget(form.name.name02, { type : ‘hidden’ }) }} の様に name,value,type を渡せないと言う事か?(->ChatGPT)
結論
✅ @section では変数を渡せないので、代わりに @push + @stack または @component を使う。
✅ @push は複数回追加できるため、複数の form_widget を動的に埋め込むのに便利。
✅ @component なら変数を渡しつつ、Twig の form_widget() のように再利用できる。
(@componentも関数毎にファイルを作らなければならないのは、@includeと同じだった)
\
推奨されてはいないが、@section を使うと1つのファイルに複数の関数(ブロック)を宣言できる。このため、@section を使うが、変数を渡せない代わりに、*.blade.phpファイル間で namespace を使ってスコープ内で変数を渡すとしたら、どのように書けるか? (->ChatGPT)
Blade には namespace はないが、以下の方法でスコープ内で変数を渡せる:
(コードのメモは省略)
結論
1. View::share()(全 Blade テンプレートで共有)
2. view()->composer()(特定のテンプレートだけに渡す)
3. session()(一時的なデータの共有)
4. config()(設定ファイルを使う。設定値として保持)
\
sessionで変数を持つより普通にグローバルで変数を持った方が、パフォーマンスもセキュリティリも
良いので(ChatGPT,DeepSeek)、グローバル変数で渡す事にした。最初は再現性重視で構文を似た感じに。
confirm.twig
{{ form_widget(form.name.name01, { type : ‘hidden’ }) }}
confirm.blade.php (->DeepSeek)
{{– {!! Form::hidden(‘name[name01]’, $form[‘name’][‘name01’]->vars[‘data’]) !!} –}}
@php $form_widget_data = [‘name’ => ‘name.name01’, ‘type’ => ‘hidden’, ‘value’ => old(‘name.name01’)]; @endphp
@yield(‘form_widget’, [‘form_widget_data’ => $form_widget_data])
\
{% form_theme form ‘Form/form_div_layout.twig’ %} は、どういう意味か? (->DeepSeek)
この一文は、フォームのテーマ(見た目やレイアウト)を指定するためのものです。具体的には、以下のようなことを行います。
・form: フォームオブジェクトを指します。このフォームのレンダリング方法をカスタマイズします。
・’Form/form_div_layout.twig’: フォームのレンダリングに使用するテンプレートファイルを指定します。
このディレクティブを使うことで、指定したテンプレートファイル(form_div_layout.twig)に基づいてフォームがレンダリングされます。
form_div_layout.twig は、Symfonyが提供するデフォルトのフォームレイアウトテンプレートです。このテンプレートは、フォームの各要素(ラベル、入力フィールド、エラーメッセージなど)をどのようにHTMLとしてレンダリングするかを定義しています。
例えば、以下のようなフォーム要素をレンダリングするためのテンプレートが含まれています。
・form_label: フォームのラベルをレンダリングする。
・form_widget: フォームの入力フィールドをレンダリングする。
・form_errors: フォームのエラーメッセージをレンダリングする。
{% form_theme form ‘Form/form_div_layout.twig’ %} を指定すると、以下のような動作が行われます。
1.フォームのレンダリング方法を変更:
・form オブジェクトのレンダリングに、Form/form_div_layout.twig で定義されたテンプレートが使用されます。
・これにより、フォームの見た目やレイアウトがデフォルトのものに変更されます。
2.テンプレートの適用範囲:
・このディレクティブが記述されたテンプレート内でのみ有効です。
・他のテンプレートや部分テンプレートには影響しません。
LaravelにはSymfonyのような form_theme ディレクティブはありませんが、Bladeテンプレートを使って同様の機能を実現できます。
(Bladeでの対応例はメモ省略。Blade化する場合はform_themeという名称は不要になる)

/*************************************************************************************/

参考書籍、関連情報:
PHPフレームワーク Laravel入門 第2版 2019.12
https://www.shuwasystem.co.jp/book/9784798060996.html
(@parentの事が書いてあった。{% extends %}や@extendsは、Twig(Symfony)やBlade(Laravel)の
ディレクティブという。書いてあったか?、見てみる)
\
EC-CUBE研修資料(Symfony入門ハンズオン)
https://qiita.com/chihiro-adachi/items/ccb00206c7288c1804b0

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です