Pergunta

Estou construindo um aplicativo com cakePHP e sou novo nisso.o que eu quero fazer agora é isso.Deixe-me explicar em poucas palavras:Tenho 2 modelos, Item e Tipologias.Um item pode ter muitas tipologias.Portanto, a tabela de tipologia possui uma chave estrangeira - item_id - que se refere ao item.Agora quero evitar que o usuário exclua Itens caso ainda existam tipologias referentes a este Item.

Meu modelo de item é este:

<?php
App::uses('AppModel', 'Model');
/**
 * Item Model
 *
 * @property ItemLocation $ItemLocation
 * @property ItemCharacteristic $ItemCharacteristic
 * @property FirstSeller $FirstSeller
 * @property SecondSeller $SecondSeller
 * @property User $User
 * @property Contact $Contact
 * @property ItemPicture $ItemPicture
 * @property Typology $Typology
 */
class Item extends AppModel {
public $name = 'Item';

/**
 * Primary key field
 *
 * @var string
 */
    public $primaryKey = 'id';
/**
 * Display field
 *
 * @var string
 */
    public $displayField = 'title';

/**
 * Validation rules
 *
 * @var array
 */
    public $validate = array(
        'id' => array(
            'blank' => array(
                'rule' => 'blank',
                'on' => 'create',
            ),
        ),
        'title' => array(
            'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'The Item name can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxLength', 100),
                'message' => 'The Item name must not be longer than 100 characters.',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'The Item name must not be empty.',
            ),
            'isUnique' => array(
                 'rule' => 'isUnique',
                 'message' => 'This Item name already exists.',
            ),
        ),

        'user_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                //'message' => 'Your custom message here',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Not Empty',
            ),
        ),
        'created' => array(
            'datetime' => array(
                'rule' => array('datetime'),
                //'message' => 'Your custom message here',
            ),
        ),
    );

/**
 * belongsTo associations
 *
 * @var array
 */
    public $belongsTo = array(
        'ItemUser' => array(
            'className' => 'User',
            'foreignKey' => 'user_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );

/**
 * hasMany associations
 *
 * @var array
 */
    public $hasMany = array(
        'ItemTypologies' => array(
            'className' => 'Typology',
            'foreignKey' => 'item_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        )
    );

E o Modelo de Tipologia é este:

<?php
App::uses('AppModel', 'Model');
/**
 * Typology Model
 *
 * @property Item $Item
 * @property TypologyCategory $TypologyCategory
 * @property TypologyCondition $TypologyCondition
 * @property User $User
 * @property TypologyPicture $TypologyPicture
 */
class Typology extends AppModel {
public $name = 'Typology';
/**
 * Primary key field
 *
 * @var string
 */
    public $primaryKey = 'id';
/**
 * Display field
 *
 * @var string
 */
    public $displayField = 'title';

/**
 * Validation rules
 *
 * @var array
 */
    public $validate = array(
        'id' => array(
            'blank' => array(
                'rule' => 'blank',
                'on' => 'create',
            ),
        ),
        'item_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                'message' => 'Chose Which Object This Typology Belongs To',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Can Not be Empty',
            ),
        ),
        'title' => array(
            'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'The Typology name can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxlength', 50),
                'message' => 'The Typology name must not be longer than 50 characters.',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Typology Title Can not be Empty',
            ),
            'isUnique' => array(
                'rule' => 'isUnique',
                'message' => 'Typology Name Should be Unique',
            ),
        ),
        'description' => array(
            'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'The Typology name can only contain letters, numbers and spaces.',
            ),
            'maxLength' => array(
                'rule' => array('maxlength', 350),
                'message' => 'The Typology name must not be longer than 350 characters.',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Description can not be Empty',
            ),
        ),

        'user_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                'message' => 'Chose the user who created this typology',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                //'message' => 'Your custom message here',
            ),
        ),
        'created' => array(
            'datetime' => array(
                'rule' => array('datetime'),
                //'message' => 'Your custom message here',
            ),
        ),
    );

/**
 * belongsTo associations
 *
 * @var array
 */
    public $belongsTo = array(
        'TypologyItem' => array(
            'className' => 'Item',
            'foreignKey' => 'item_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
        'TypologyUser' => array(
            'className' => 'User',
            'foreignKey' => 'user_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );

Agora o que vi e escrevi foi isso, e se alguém tiver alguma ideia eu agradeceria muito:

// using app/Model/Item.php
// In the following example, do not let an Item to be deleted if it
// still contains Typologies Attached to it.
// A call of $this->Typology->delete($id) from TypologiesController.php has set
// $this->id .
// Assuming 'ItemTypologies hasMany Typology', we can access $this->Typoogy
// in the model.

public function beforeDelete($cascade = true) {
    $count = $this->Typology->find('count', array('conditions' => array('item_id' => $this->Typology->id)));
    if ($count == 0) {
        return true;
    } else {
        return false;
    }
} 

E quando tento deletar um Item que possui tipologias ou Um item que não apresenta esse erro!

Fatal Error

Error: Call to a member function find() on a non-object
File: C:\wamp\www\project\app\Model\Item.php
Line: 449

Como posso resolver isso!!

Foi útil?

Solução

A lógica é semelhante à que theotherdy já explicado.

No código do seu controlador, o método delete() da seguinte forma:

public function delete($id = null) {
    $this->request->onlyAllow('post', 'delete');
    $options = array('conditions' => array('Item.' . $this->Field->primaryKey => $id));
    $item = $this->Item->find('first', $options);
    if (!$item) {
        throw new NotFoundException(__('Invalid item'));
    }
    if (isset($item['Typology']) && count($item['Typology'])) {
        $this->setFlash(__("Item '%s' is being used by %s Typologies.<br />Cannot delete.", $item['Item']['title'], count($item['Tipology'])));
    } else {
        $this->Item->id = $id;
        if ($this->Item->delete()) {
            $this->setFlash(__('Item deleted'));
        } else {
            $this->setFlash(__('Item was not deleted'));
        }
    }
    $this->redirect(array('action' => 'index'));
}

Outras dicas

Eu teria dito que você deseja que seu banco de dados evite a exclusão de itens mencionados por outras tipologias, certificando-se de que essas restrições de chave estrangeira estejam no banco de dados.Então, sua UI não deve dar às pessoas a opção de excluir itens mencionados por uma tipologia, mas talvez você queira dar a elas a opção de remover as tipologias de um item.

Não tenho ideia de que tipo de UI você está propondo, mas (na minha cabeça, código desmarcado, então peço desculpas por quaisquer erros de digitação/erros), digamos que você teve uma ação/visualização de índice de itens, você pode ter isso em seu ItemsController. ação do índice php:

$items = $this->Item->find('all')
$this->set('items', $items);

então em seu Views/Items/index.ctp você pode ter:

<?php foreach ($items as $item): ?>
    <h1><?php echo $item['Item']['name'];?>
    <?php 
    if(!isset($item['Typology'])||count($item['Typology'])==0){
        //ie this items has no Typologies 
        //Create delete button/link for this item
        }
    elseif(isset($item['Typology'])&&count($item['Typology'])>0){
        //we have some typologies for this item
        foreach ($item['Typology'] as $typology){
            //info about the typology and possible delete button/link
            }
        }
    ?>
<?php endforeach; ?>

HTH

ADICIONANDO MAIS DETALHES NO CONTROLADOR - expandindo a resposta de @savedario

Se seus modelos estiverem configurados com as restrições de chave estrangeira adequadas, então

$this->Item->delete()

irá falhar se houver alguma violação dessas restrições, então, como diz @savedario, você pode testar o sucesso com

if ($this->Item->delete())

ou você pode dar um passo adiante, como ilustra @savedario, mas que acho que é feito de forma mais elegante e genérica aqui: http://joshuapaling.com/post/captura-integrity-constraint-violations-when-deleting-records e lance uma exceção se houver registros vinculados que você possa testar a seguir (copiado do blog de joshuapaling):

 try {
    if ($this->MyModel->delete()) {
        $this->Session->setFlash('Record deleted', 'default', array(), 'good');
    } else {
        $this->Session->setFlash('Record was not deleted. Unknown error.', 'default', array(), 'bad');
    }
} catch (Exception $e) {
    $this->Session->setFlash("Delete failed. {$e->getMessage()}", 'default', array(), 'bad');
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top