CakePhp HABTM: Editando um item casus HABTM Row para ser recriado, destrói dados extras
-
21-09-2019 - |
Pergunta
Estou tendo problemas com meu relacionamento HABTM em CakePhp.
Eu tenho dois modelos como isso: Department
HABTM Location
. Uma grande empresa tem muitos edifícios e cada edifício fornece um número limitado de serviços. Cada edifício também tem sua própria página da web; portanto, além do relacionamento HABTM, cada linha HABTM também tem um url
Campo onde o usuário pode visitar para encontrar informações adicionais sobre o serviço que estão interessadas e como ele opera no edifício em que está interessado.
Eu configurei os modelos como assim:
<?php
class Location extends AppModel {
var $name = 'Location';
var $hasAndBelongsToMany = array(
'Department' => array(
'with' => 'DepartmentsLocation',
'unique' => true
)
);
}
?>
<?php
class Department extends AppModel {
var $name = 'Department';
var $hasAndBelongsToMany = array(
'Location' => array(
'with' => 'DepartmentsLocation',
'unique' => true
)
);
}
?>
<?php
class DepartmentsLocation extends AppModel {
var $name = 'DepartmentsLocation';
var $belongsTo = array(
'Department',
'Location'
);
// I'm pretty sure this method is unrelated. It's not being called when this error
// occurs. Its purpose is to prevent having two HABTM rows with the same location
// and department.
function beforeSave() {
// kill any existing rows with same associations
$this->log(__FILE__ . ": killing existing HABTM rows", LOG_DEBUG);
$result = $this->find('all', array("conditions" =>
array("location_id" => $this->data['DepartmentsLocation']['location_id'],
"department_id" => $this->data['DepartmentsLocation']['department_id'])));
foreach($result as $row) {
$this->delete($row['DepartmentsLocation']['id']);
}
return true;
}
}
?>
Os controladores são completamente desinteressantes.
O problema:Se eu editar o nome de um Location
, todos os DepartmentsLocation
s que estavam ligados a isso Location
são recriados com URLs vazios. Como os modelos especificam que o único é verdadeiro, isso também faz com que todas as linhas mais recentes substituam as linhas mais antigas, o que destrói essencialmente todos os URLs.
Eu gostaria de saber duas coisas: posso parar com isso? Se sim, como?
E, em uma nota menos técnica e mais chorosa: por que isso acontece? Parece -me bizarro que a edição de um campo através do bolo deve causar tantos problemas, quando eu posso facilmente passar por phpmyadmin, editar o Location
Nome lá e obtenha exatamente o resultado que eu esperaria. Por que o CakePhp toca os dados do HABTM quando estou apenas editando um campo em uma linha? Não é nem uma chave estrangeira!
Solução
Do livro de receitas, o 1º problema é:
Por padrão, ao salvar um relacionamento de Hasandbelongstomany, o bolo excluirá todas as linhas na mesa de junção antes de salvar novas.
Não sei por que o bolo está tentando salvar os dados do HABTM, mesmo que você não tenha uma chave estrangeira em seus dados, mas existe uma solução fácil para isso. Simplesmente destruir a associação Para a chamada salvadora:
$this->Location->unbindModel(
array('hasAndBelongsToMany' => array('Department'))
);
Outras dicas
Estou pensando em uma das razões pelas quais isso pode estar acontecendo. Quando você recupera Location
, você também recupera locations_departments
dados. E quando você faz um save($this->data)
Ele procura modelos na matriz e os salva.
Uma maneira de resolver isso é definir o recursive
atributo (de um modelo) a -1 ou 0 (tente, não tenho certeza, basta imprimir os dados para ver o que sai). Você pode defini -lo no modelo: var $recursive = -1;
ou no método do controlador (ação): $this->ModelName->recursive = -1;
Mais sobre recursivo: http://book.cakephp.org/view/439/recursive
É realmente parecido com o que Harpax Sugerido, apenas se você não precisar desses dados, diga para bolo, para que não o busque.
O problema é que, ao salvar seu Location
, você deu ao método salvar uma matriz contendo todo o DepartmentsLocations
também. Assim, Cakephp destrói tudo e tenta recriá -lo.
Este é um erro comum com o bolo, pois geralmente puxa muitos resultados para você.
Certifique -se de passar apenas os dados que precisam ser salvos ou melhor buscar apenas os dados que você precisa.