CakePHP связать hasmany через отношения

Хорошо, это трудно объяснить, но я постараюсь.

у меня 3 стола

companies     products     product_availabilities
---------     --------     ----------------------
id            id           id
name          name         company_id
                           product_id
                           buys (tinyint)
                           sells (tinyint)

И их модели

class Company extends AppModel
{
        public $name = 'Company';

        public $hasMany = array(
            'ProductAvailability'
        );


class Product extends AppModel
{       
    public $name = 'Product';

    public $hasMany = array(
        'ProductAvailability'
    );


class ProductAvailability extends AppModel
{
    public $name = 'ProductAvailability';

    public $belongsTo = array(
        'Company',
        'Product'
    );
}

Что я хочу сделать, так это создать компанию, я хочу иметь возможность выбирать продукты, которые компания покупает или продает. Я видел пример сквозной связи hasMany в книге (http://book.cakephp.org/1.3/view/1650/hasMany-through-The-Join-Model), но они создают форму из " контроллер соединения с таблицей». Можно ли связать модель productAvailability с моделью моей компании, чтобы иметь возможность выбирать продукты при создании компании?

Редактировать: вот как я это сделал. Я знаю, что это не оптимально, так как задействовано много циклов, но это работает.

Контролер компании:

    $products = $this->Company->ProductAvailability->Product->find('list', array('fields' => array('Product.id', 'Product.label')));
    $this->set('products', $products);

    if($this->request->is('post')){             
        if($this->Company->save($this->request->data)){
            foreach($products as $product)
            {
                $tmpArray = array(
                    'company_id' => $this->Company->id,
                    'product_id' => $product['Product']['id']
                );

                foreach($this->request->data('BuyProducts.product_id') as $buyProduct)
                {
                    if($buyProduct == $product['Product']['id'])
                        $tmpArray['buys'] = 1;
                }
                foreach($this->request->data('SellProducts.product_id') as $sellProduct)
                {
                    if($sellProduct == $product['Product']['id'])
                        $tmpArray['sells'] = 1;
                }

                if(count($tmpArray) > 2)
                {
                    $this->Company->ProductAvailability->create();
                    $this->Company->ProductAvailability->set($tmpArray);
                    $this->Company->ProductAvailability->save();
                }  
            }

            $this->Session->setFlash('Yay', 'success');
            $this->redirect(array('action' => 'index'));
        } else {
            $this->Session->setFlash('Nay', 'error');
        }
    }

Форма добавления компании:

<?php echo $this->Form->create('Company'); ?>

<?php echo $this->Form->input('name', array( 'div' => 'full-form')); ?>

<?php echo $this->Form->input('BuyProducts.product_id', array('multiple' => 'checkbox', 'options' => $products, 'div' => 'full-form', 'label' => false)); ?>

<?php echo $this->Form->input('SellProducts.product_id', array('multiple' => 'checkbox', 'options' => $products, 'div' => 'full-form', 'label' => false)); ?>

<?php echo $this->Form->end(array('label' => __('Save'), 'div' => 'center', 'class' => 'bouton-vert')); ?>

person Dominic Horbas    schedule 25.07.2012    source источник


Ответы (2)


У вас есть два варианта. Либо позвольте CakePHP поколдовать с отношением hasAndBelongsToMany, либо сделайте это вручную, что необходимо, если вы добавляете атрибуты в таблицу соединений.

1. CakePHP HABTM

Используя возможности CakePHP и сделав прямое решение, я бы внес следующие изменения:

Модель

Если у одной компании более одного продукта, и продукты принадлежат многим компаниям. Это отношение hasAndBelongsToMany между Company‹->Product

// company.php
...
var $hasAndBelongsToMany = array(
    'Product' => array(
        'className' => 'Product',
        'joinTable' => 'companies_products',
        'foreignKey' => 'company_id',
        'associationForeignKey' => 'product_id',
        'unique' => true,
    )
);
...
// similar in product.php 

Добавьте в базу данных необходимую таблицу «companies_products».

Контроллер

Затем в функции добавить из контроллера компании должно быть что-то вроде:

$products = $this->Company->Product->find('list');
$this->set(compact('products'));

Просмотреть

Наконец, вставьте продукты в add.ctp, выбор должен позволять множественный выбор и позволяет CakePHP творить чудеса, например:

echo $this->Form->input('products', array( 
                         'label' => 'Products to buy (Ctr+multiple choice)' 
                          'type' => 'select', 
                      'multiple' => true,
                       ));

2. Вручную

Когда HABTM становится более «экзотичным» и включает в себя некоторые атрибуты, такие как в вашем случае «купить» или «продать», вам нужно сделать это вручную. Это делается в Product Controller, вручную устанавливая поля перед их вставкой в ​​базу данных. Что-то типа:

foreach($availableProducts as $availableProduct ){
  $this->Product->ProductAvailabilities->create();
  $this->Product->ProductAvailabilities->set( array(
    'company_id' => $this->Product->id,
    'product_id' => $availableProduct['Product']['id'],
    'buys' => $availableProduct['Product']['buy'], 
    'sells' => $availableProduct['Product']['sell'] 
             // or however you send it to the controller
  ));
$this->Product->ProductAvailabilities->save();
}

Будем надеяться, что это поможет вам...

person Carlos Morales    schedule 25.07.2012
comment
Спасибо за ваш ответ. К сожалению, в моем случае hasAndBelongsToMany не сработает, потому что я хочу сохранить данные в таблице соединений. Некоторые компании будут покупать продукты, а другие будут продавать их, или и то, и другое. - person Dominic Horbas; 25.07.2012
comment
Доминик, я обновил его, чтобы вы могли включить данные в таблицу соединений. - person Carlos Morales; 25.07.2012
comment
Моя проблема в том, что я не могу создать форму, которая будет публиковать правильную структуру для сохранения этих данных. Я должен сохранить все эти данные при создании компании. - person Dominic Horbas; 25.07.2012
comment
Оно работает! Я опубликую свое полное решение для других. Большое Вам спасибо. - person Dominic Horbas; 25.07.2012

вы планируете habtm-отношение (m:n) с возможностью иметь дополнительные поля в таблице соединений. Несмотря на то, что это можно сделать с помощью обычного habtm, я предпочитаю способ, которым вы выбираете и реализуете m:n как 1:n:1, что просто то же самое и дает вам больше возможностей при сохранении ваших данных.

Вот похожий вопрос и ответ

Что касается вашего вопроса: вы можете собирать данные из таблицы продуктов следующим образом:

$this->Company->ProductAvailability->Product->find('all', $params);

Также вы можете взглянуть на containable-behaviour, который очень полезен для этого варианта использования:

$params['conditions'] = array(
    'Company.id' => $id
);
$params['contain'] => array(
    'ProductAvailability' => array(
        'conditions' =>array(
            'buys' => 1
        ),
        'Product' => array(
            'order' => array(
                'name' => 'ASC'
            )
        )
    )
);
$this->Company->find('all', $params);
person harpax    schedule 25.07.2012
comment
Спасибо. Я привязывал свою модель продукта напрямую к моей компании в контроллере. Мне так больше нравится. - person Dominic Horbas; 25.07.2012