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.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