2017-01-12 21 views
0

表は、この問題に進化は、次のとおりCakePHP 3:HABTMの2つのレベルを持つエンティティを保存する方法は?

  • tarifas(contratosに属する)
  • 領域(HABTMのtarifas)も
  • tarifas_areas(HABTM turnos)
  • tarifas_areas_turnos

Tarifas habtm Diasがありますが、この関連付けには問題はありません。これは単純な関連性があるためです。

TarifasTable:

<?php 
namespace App\Model\Table; 

use Cake\ORM\Query; 
use Cake\ORM\RulesChecker; 
use Cake\ORM\Table; 
use Cake\Validation\Validator; 

/** 
* Tarifas Model 
* 
* @property \Cake\ORM\Association\BelongsTo $Contratos 
* @property \Cake\ORM\Association\BelongsToMany $Areas 
* @property \Cake\ORM\Association\BelongsToMany $Dias 
* 
* @method \App\Model\Entity\Tarifa get($primaryKey, $options = []) 
* @method \App\Model\Entity\Tarifa newEntity($data = null, array $options = []) 
* @method \App\Model\Entity\Tarifa[] newEntities(array $data, array $options = []) 
* @method \App\Model\Entity\Tarifa|bool save(\Cake\Datasource\EntityInterface $entity, $options = []) 
* @method \App\Model\Entity\Tarifa patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) 
* @method \App\Model\Entity\Tarifa[] patchEntities($entities, array $data, array $options = []) 
* @method \App\Model\Entity\Tarifa findOrCreate($search, callable $callback = null) 
*/ 
class TarifasTable extends Table 
{ 

    /** 
    * Initialize method 
    * 
    * @param array $config The configuration for the Table. 
    * @return void 
    */ 
    public function initialize(array $config) 
    { 
     parent::initialize($config); 

     $this->table('tarifas'); 
     $this->displayField('id'); 
     $this->primaryKey('id'); 

     $this->belongsTo('Contratos', [ 
      'foreignKey' => 'contrato_id', 
      'joinType' => 'INNER' 
     ]); 
     $this->belongsToMany('Areas', [ 
      'foreignKey' => 'tarifa_id', 
      'targetForeignKey' => 'area_id', 
      'joinTable' => 'tarifas_areas' 
     ]); 
     $this->belongsToMany('Dias', [ 
      'foreignKey' => 'tarifa_id', 
      'targetForeignKey' => 'dia_id', 
      'joinTable' => 'tarifas_dias' 
     ]); 
    } 

    /** 
    * Default validation rules. 
    * 
    * @param \Cake\Validation\Validator $validator Validator instance. 
    * @return \Cake\Validation\Validator 
    */ 
    public function validationDefault(Validator $validator) 
    { 
     $validator 
      ->integer('id') 
      ->allowEmpty('id', 'create'); 

     $validator 
      ->requirePresence('nome', 'create') 
      ->notEmpty('nome'); 

     $validator 
      ->date('dataInicial') 
      ->requirePresence('dataInicial', 'create') 
      ->notEmpty('dataInicial'); 

     $validator 
      ->date('dataFinal') 
      ->requirePresence('dataFinal', 'create') 
      ->notEmpty('dataFinal'); 

     return $validator; 
    } 

    /** 
    * Returns a rules checker object that will be used for validating 
    * application integrity. 
    * 
    * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. 
    * @return \Cake\ORM\RulesChecker 
    */ 
    public function buildRules(RulesChecker $rules) 
    { 
     $rules->add($rules->existsIn(['contrato_id'], 'Contratos')); 

     return $rules; 
    } 

    public function salvaTarifasContrato($idContrato, $dadosTarifas){ 
     $tarifas = $this->newEntities(
      $dadosTarifas, 
      ['associated' => ['TarifasAreas', 'TarifasAreas.TarifasAreasTurnos']] 
     ); 
     debug($tarifas); die(); 
    } 
} 

AreasTable:

<?php 
namespace App\Model\Table; 

use Cake\ORM\Query; 
use Cake\ORM\RulesChecker; 
use Cake\ORM\Table; 
use Cake\Validation\Validator; 

/** 
* Areas Model 
* 
* @property \Cake\ORM\Association\BelongsTo $Clientes 
* @property \Cake\ORM\Association\BelongsToMany $Bairros 
* @property \Cake\ORM\Association\BelongsToMany $Contratos 
* @property \Cake\ORM\Association\BelongsToMany $Tarifas 
* 
* @method \App\Model\Entity\Area get($primaryKey, $options = []) 
* @method \App\Model\Entity\Area newEntity($data = null, array $options = []) 
* @method \App\Model\Entity\Area[] newEntities(array $data, array $options = []) 
* @method \App\Model\Entity\Area|bool save(\Cake\Datasource\EntityInterface $entity, $options = []) 
* @method \App\Model\Entity\Area patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) 
* @method \App\Model\Entity\Area[] patchEntities($entities, array $data, array $options = []) 
* @method \App\Model\Entity\Area findOrCreate($search, callable $callback = null) 
*/ 
class AreasTable extends Table 
{ 

    /** 
    * Initialize method 
    * 
    * @param array $config The configuration for the Table. 
    * @return void 
    */ 
    public function initialize(array $config) 
    { 
     parent::initialize($config); 

     $this->table('areas'); 
     $this->displayField('id'); 
     $this->primaryKey('id'); 

     $this->belongsTo('Clientes', [ 
      'foreignKey' => 'cliente_id', 
      'joinType' => 'INNER' 
     ]); 
     $this->belongsToMany('Bairros', [ 
      'foreignKey' => 'area_id', 
      'targetForeignKey' => 'bairro_id', 
      'joinTable' => 'areas_bairros' 
     ]); 
     $this->belongsToMany('Contratos', [ 
      'foreignKey' => 'area_id', 
      'targetForeignKey' => 'contrato_id', 
      'joinTable' => 'contratos_areas' 
     ]); 
     $this->belongsToMany('Tarifas', [ 
      'foreignKey' => 'area_id', 
      'targetForeignKey' => 'tarifa_id', 
      'joinTable' => 'tarifas_areas' 
     ]); 
    } 

    /** 
    * Default validation rules. 
    * 
    * @param \Cake\Validation\Validator $validator Validator instance. 
    * @return \Cake\Validation\Validator 
    */ 
    public function validationDefault(Validator $validator) 
    { 
     $validator 
      ->integer('id') 
      ->allowEmpty('id', 'create'); 

     $validator 
      ->allowEmpty('descricaoarea'); 

     return $validator; 
    } 

    /** 
    * Returns a rules checker object that will be used for validating 
    * application integrity. 
    * 
    * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. 
    * @return \Cake\ORM\RulesChecker 
    */ 
    public function buildRules(RulesChecker $rules) 
    { 
     $rules->add($rules->existsIn(['cliente_id'], 'Clientes')); 

     return $rules; 
    } 
} 

TarifasAreasTable:

<?php 
namespace App\Model\Table; 

use Cake\ORM\Query; 
use Cake\ORM\RulesChecker; 
use Cake\ORM\Table; 
use Cake\Validation\Validator; 

/** 
* TarifasAreas Model 
* 
* @property \Cake\ORM\Association\BelongsTo $Tarifas 
* @property \Cake\ORM\Association\BelongsTo $Areas 
* @property \Cake\ORM\Association\BelongsToMany $Turnos 
* 
* @method \App\Model\Entity\TarifasArea get($primaryKey, $options = []) 
* @method \App\Model\Entity\TarifasArea newEntity($data = null, array $options = []) 
* @method \App\Model\Entity\TarifasArea[] newEntities(array $data, array $options = []) 
* @method \App\Model\Entity\TarifasArea|bool save(\Cake\Datasource\EntityInterface $entity, $options = []) 
* @method \App\Model\Entity\TarifasArea patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) 
* @method \App\Model\Entity\TarifasArea[] patchEntities($entities, array $data, array $options = []) 
* @method \App\Model\Entity\TarifasArea findOrCreate($search, callable $callback = null) 
*/ 
class TarifasAreasTable extends Table 
{ 

    /** 
    * Initialize method 
    * 
    * @param array $config The configuration for the Table. 
    * @return void 
    */ 
    public function initialize(array $config) 
    { 
     parent::initialize($config); 

     $this->table('tarifas_areas'); 
     $this->displayField('id'); 
     $this->primaryKey('id'); 

     $this->belongsTo('Tarifas', [ 
      'foreignKey' => 'tarifa_id', 
      'joinType' => 'INNER' 
     ]); 
     $this->belongsTo('Areas', [ 
      'foreignKey' => 'area_id', 
      'joinType' => 'INNER' 
     ]); 
     $this->belongsToMany('Turnos', [ 
      'foreignKey' => 'tarifas_area_id', 
      'targetForeignKey' => 'turno_id', 
      'joinTable' => 'tarifas_areas_turnos' 
     ]); 
    } 

    /** 
    * Default validation rules. 
    * 
    * @param \Cake\Validation\Validator $validator Validator instance. 
    * @return \Cake\Validation\Validator 
    */ 
    public function validationDefault(Validator $validator) 
    { 
     $validator 
      ->integer('id') 
      ->allowEmpty('id', 'create'); 

     return $validator; 
    } 

    /** 
    * Returns a rules checker object that will be used for validating 
    * application integrity. 
    * 
    * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. 
    * @return \Cake\ORM\RulesChecker 
    */ 
    public function buildRules(RulesChecker $rules) 
    { 
     $rules->add($rules->existsIn(['tarifa_id'], 'Tarifas')); 
     $rules->add($rules->existsIn(['area_id'], 'Areas')); 

     return $rules; 
    } 
} 

TarifasAreasTurnosTable:

<?php 
namespace App\Model\Table; 

use Cake\ORM\Query; 
use Cake\ORM\RulesChecker; 
use Cake\ORM\Table; 
use Cake\Validation\Validator; 

/** 
* TarifasAreasTurnos Model 
* 
* @property \Cake\ORM\Association\BelongsTo $TarifaAreas 
* @property \Cake\ORM\Association\BelongsTo $Turnos 
* 
* @method \App\Model\Entity\TarifasAreasTurno get($primaryKey, $options = []) 
* @method \App\Model\Entity\TarifasAreasTurno newEntity($data = null, array $options = []) 
* @method \App\Model\Entity\TarifasAreasTurno[] newEntities(array $data, array $options = []) 
* @method \App\Model\Entity\TarifasAreasTurno|bool save(\Cake\Datasource\EntityInterface $entity, $options = []) 
* @method \App\Model\Entity\TarifasAreasTurno patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) 
* @method \App\Model\Entity\TarifasAreasTurno[] patchEntities($entities, array $data, array $options = []) 
* @method \App\Model\Entity\TarifasAreasTurno findOrCreate($search, callable $callback = null) 
*/ 
class TarifasAreasTurnosTable extends Table 
{ 

    /** 
    * Initialize method 
    * 
    * @param array $config The configuration for the Table. 
    * @return void 
    */ 
    public function initialize(array $config) 
    { 
     parent::initialize($config); 

     $this->table('tarifas_areas_turnos'); 
     $this->displayField('id'); 
     $this->primaryKey('id'); 

     $this->belongsTo('TarifaAreas', [ 
      'foreignKey' => 'tarifa_area_id', 
      'joinType' => 'INNER' 
     ]); 
     $this->belongsTo('Turnos', [ 
      'foreignKey' => 'turno_id', 
      'joinType' => 'INNER' 
     ]); 
    } 

    /** 
    * Default validation rules. 
    * 
    * @param \Cake\Validation\Validator $validator Validator instance. 
    * @return \Cake\Validation\Validator 
    */ 
    public function validationDefault(Validator $validator) 
    { 
     $validator 
      ->integer('id') 
      ->allowEmpty('id', 'create'); 

     $validator 
      ->numeric('valor') 
      ->requirePresence('valor', 'create') 
      ->notEmpty('valor'); 

     return $validator; 
    } 

    /** 
    * Returns a rules checker object that will be used for validating 
    * application integrity. 
    * 
    * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. 
    * @return \Cake\ORM\RulesChecker 
    */ 
    public function buildRules(RulesChecker $rules) 
    { 
     $rules->add($rules->existsIn(['tarifa_area_id'], 'TarifaAreas')); 
     $rules->add($rules->existsIn(['turno_id'], 'Turnos')); 

     return $rules; 
    } 
} 

これは私が(JSONのそれの一部)を保存したいデータです:

"tarifas": [ 
     { 
      "nome": "T1", 
      "dataInicial": "2017-01-10", 
      "dataFinal": "2018-01-10", 
      "dias": [ 
       { 
        "id": 1, 
        "_joinData": [] 
       }, 
       { 
        "id": 2, 
        "_joinData": [] 
       }, 
       { 
        "id": 3, 
        "_joinData": [] 
       }, 
       { 
        "id": 4, 
        "_joinData": [] 
       }, 
       { 
        "id": 5, 
        "_joinData": [] 
       } 
      ], 
      "TarifasAreas": [ 
       { 
        "area_id": 3, 
        "TarifasAreasTurnos": [ 
         { 
          "turno_id": 4, 
          "valor": 20 
         } 
        ] 
       } 
      ] 
     } 
    ] 

だから、TarifasTableに私はすべてのtarifasを保存するには、この機能をコード化された(私はまだデバッグてる):

これらのテーブルは相互に関連付ける方法

{ 
    "message": "Cannot marshal data for \"TarifasAreas\" association. It is not associated with \"Tarifas\".", 
    "url": "/project/api/contratos", 
    "code": 500 
} 

だから、どのように私は、CakePHPを言うことができる:

public function salvaTarifasContrato($idContrato, $dadosTarifas){ 
    $tarifas = $this->newEntities(
     $dadosTarifas, 
     ['associated' => ['TarifasAreas', 'TarifasAreas.TarifasAreasTurnos']] 
    ); 
    debug($tarifas); die(); 
} 

そして私は、このリターンを持っていますか?そのデータを一度にすべて保存する方法はありますか?

答えて

1

TarifasTarifasAreasの間にhasManyの関係を定義する必要があります。テーブルにbelongsToManyリレーションシップを定義するときは、明示的に指定されたテーブルのみが関連し、スルーテーブルは関係しません。限りTarifasためTarifasAreasの外部キーが、これは動作するはずtarifa_idあるよう

// TarifasTable.php 
$this->hasMany('TarifasAreas'); 

https://book.cakephp.org/3.0/en/orm/associations.html#hasmany-associations

+0

うん、それは動作します!しかし、CakePHP 3にはORMが「TarifasAreasテーブルを記述できません:それに0列あります」というバグがあるので、テーブル名を変更する必要がありました。 –

+0

これは奇妙です!命名規則と関係がありますか? - https://book.cakephp.org/3.0/ja/intro/conventions.html#model-and-database-conventions - 通常、テーブル名はアルファベットの 'AreasTarifas' – cjquinn

関連する問題