質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

Q&A

解決済

2回答

1846閲覧

[Cakephp3] アソシエーションごと保存するときのフォームについて

jagatarou

総合スコア13

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

0グッド

0クリップ

投稿2019/08/23 13:01

初めまして。
現在会員登録システムの開発を進めておりますが、タイトルの件について分からないことがあります。

下記のテーブル構造・フォーム・コントローラーで、アソシエーションごとデータを新規保存しようと思っています。

table

1users - statuses を hasOne 2  └statuses - users へ belongsTo 3    ├basics - statuses へ belongsTo 4    └userdatas - statuses へ belongsTo

php

1# Users/form.ctp 2 3<?= $this->Form->create($entity); ?> 4 5<!-- Users 項目 --> 6 <?= $this->Form->control('username'); ?> 7 <?= $this->Form->control('password'); ?> 8 9<!-- Status 項目 --> 10 <?= $this->Form->hidden('Statuses.flg', ['value' => 1]); ?> 11 12<!-- Basics 項目 --> 13 <?= $this->Form->control('Statuses.Basics.address_first'); ?> 14 <?= $this->Form->control('Statuses.Basics.address_second'); ?> 15 16<!-- Userdatas 項目 --> 17 <?= $this->Form->hidden('Statuses.Userdatas.date_entry', ['value' => '2019-08-23'); ?> 18 19<?= $this->Form->submit('送信'); ?> 20<?= $this->Form->end(); ?> 21

php

1#UsersController.php - function form() 2 3$entity = $this->Users->newEntity(); 4 5 // POSTされたときの処理 6 if ($this->request->is('post')) 7 { 8 $entity = $this->Users->patchEntity( 9 $entity, 10 $this->request->getData(), 11 ['associated' => ['Statuses', 'Statuses.Basics', 'Statuses.Userdatas']] 12 ); 13 14 // データの中身を見るためにデバッグ 15 debug($entity); 16 17 $this->Users->save($entity); 18 } 19 20$this->set(compact(['entity']));

しかしながら、上記の形でフォームを送信しますと Statuses 以下のアソシエーションデータが patchEntity で反映されません。
途中に用意したデバッグ箇所で出力されるのは、

php

1# debug($entity) 2 3object(App\Model\Entity\User) { 4 5 'username' => 'hoge', 6 'password' => 'fuga', 7 '[new]' => true, 8 '[accessible]' => [ 9 'username' => true, 10 'password' => true, 11 ], 12 '[dirty]' => [ 13 'username' => true, 14 'password' => true, 15 'Statuses' => true // フィールドとして認識されている? 16 ], 17 '[original]' => [], 18 '[virtual]' => [], 19 '[errors]' => [], 20 '[invalid]' => [], 21 '[repository]' => 'Users' 22 23}

このような中身になっており、アソシエーション部分のデータはまるごと反映されておらず、不可解な部分も見受けられます。
原因にはどういったことが考えられますか?
また、この形でのフォームですとsave後のエンティティーからアソシエーション先のバリデートエラーも反映・表示されますでしょうか?
お力添えをお願いします。

なお、冗長になるかと思い Model/Table アソシエーションの記載や、POSTデータの中身は割愛いたしました。
そちらに原因が考えられそうな場合は追記・編集いたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

Entity にて $_accessible の設定をしている場合、アソシエーション先のクラス名を明記しておかなければ保護フィールドとして扱われてしまい、エンティティー生成時等でアソシエーション先のデータは反映されません。

以下のように $_accessible へアソシエーション先のクラス名を true で指定することで解決いたしました。

php

1# Model\Entity\User.php 2 3class User extends AppEntity{ 4 5 protected $_accessible = [ 6 'username' => true, 7 'email' => true, 8 9 // アソシエーション先のモデル名を明記 10 'Statuses' => true, 11 ]; 12 13 protected $_hidden = [ 14 'password', 15 ]; 16} 17

または、以下のように $_accessible を指定しない場合であれば '*' => true として扱われ、同様に解決いたしました。

php

1# Model\Entity\Status.php 2 3class Status extends AppEntity{ 4 5 /** そもそも $_accessible の指定をしない ** 6 7 protected $_accessible = [ 8 '*' => true, 9 ]; 10 11 *****************************************/ 12 13 protected $_hidden = [ 14 'flg', 15 ]; 16} 17

投稿2019/08/27 16:39

jagatarou

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

0

ベストアンサー

フォームで指定しているアソシエーション部分のプロパティ名が間違っています。

belongsTo, hasOneでアソシエーションされた、テーブルのプロパティ名はデフォルトで単数系となります。
hasMany, belongsToManyでアソシエーションされた、テーブルのプロパティ名はデフォルトで複数系となります。
(正確にはアソシエーション名を単数系/複数形にした後、underscore化したもの

質問文から読み取るに、

Users hasOne Statuses Statuses hasOne Basics Statuses hasOne Userdatas

の関係かと思います。

であれば、エンティティのプロパティは

php

1$user->status->basic; 2$user->status->userdata;

として取得できます。

そして、フォームヘルパーの指定はエンティティに対して行うので、

php

1<?= $this->Form->hidden('status.flg', ['value' => 1]); ?> 2<?= $this->Form->control('status.basic.address_first'); ?>

となるはずです。

なお、アソシエーション設定時に propertyName や、 setProperty() で、関連付けのエンティティにおけるプロパティ名を指定できますので利用しましょう。

参考: アソシエーション - モデル同士を繋ぐ - 3.8

投稿2019/08/27 11:07

編集2019/08/27 11:09
nojimage

総合スコア957

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jagatarou

2019/09/01 17:33 編集

ご返答ありがとうございます。 つい先刻自己解決してしまったのですが、原因は Model\Entity\User での $_accessible への記載漏れでした。 パスワード等のセキュリティ面を考慮して $_accessible の指定をしていましたが、アソシエーション先を明記しておかなければ保護フィールドとして扱われ、今回のように patchEntity してもアソシエーションデータが反映されない現象が引き起こされてしまったようです。 なお status アソシエーションに関しては 'setProperty' => 'Statuses' の設定をしていました。 私が Model\Table\UsersTable の記載を割愛してしまったためですが、nojimage様のおっしゃった点も本来修正すべき点でしたのでベストアンサーにさせていただきました。 ご回答ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問