#6245: HABTM primaryKey identified in one direction only, bad DELETE queries ---------------------------------+------------------------------------------ Reporter: cuppett | Type: Bug Status: new | Priority: High Milestone: 1.2.x.x | Component: General Version: 1.2 Final | Severity: Major Keywords: HABTM primaryKey | Php_version: PHP 5 Cake_version: 1.2.2.8120 | ---------------------------------+------------------------------------------ Environment:
Windows Server 2003 PHP 5.2.8 CakePHP 1.2.2 or 1.2.1 Database: PostgreSQL 8.3.6 Problem: When HABTM models are defined in both directions (e.g. within Tag and Post model definitions) with default values for 'with' and 'unique', it will define the $assoc model once for both of them and choose just one of the columns as primaryKey based on the first direction it sees. In the $assoc model, it seems that the $primaryKey attribute will be set to one of the columns in the join table (e.g. tag_id). This $primaryKey is used for the DELETE query in both directions. So, if you allow associating Tags on a Post as well as changing the Posts from a Tag, in one of the directions you'll get a bogus DELETE query that can remove the Post from all other Tags. Editing Post and Associating Tags to a Post: DELETE FROM posts_tags WHERE post_id IN ( 8 ); INSERT; INSERT; INSERT; Editing Tags and Associating Posts to a Tag: DELETE FROM posts_tags WHERE post_id IN ( 8, 14, 23 ); INSERT; INSERT; INSERT; In the second, it removes posts from all tags (instead of just the tag being used) before re-adding it to just the one Tag. This behavior seems to depend on the order which models are loaded in the controller. The first one seems to get the primaryKey in the $assoc for both of them. I traced the code in Model->__saveMulti. On line 1273 it seems $conditions would be good for the delete. Then, by 1296, $idField seems to get the wrong idea about a primary key field. Then, down in dbo_source.php on 1447, it gets back a WHERE clause containing only IDs for what it considers $primaryKey which is wrong in one of the two directions. Extra Information: I had defined the table as PRIMARY KEY (tag_id, post_id) and I thought when Cake loads up it was choosing one of the columns and trying to identify the multi-part key. This is not the case. I removed the primary key here and it didn't help. I tried re-ordering the models in my $uses array for the Controller. This changed the direction in which the wrong DELETE would get executed, so it definitely seems related to schema recognition when it starts up rather than execution code happening in __saveMulti(). I also tried just putting an unset($this->{$join}->primaryKey) in various forms and places in there and it just made it barf in various ways deeper in the code or flow. Workaround: I was able to get around the problem by adding another 'id' column to the join table and setting it as the primary key. In this way, it's unambiguous to CakePHP what the $primaryKey on the $join table is and DELETEs utilize that column to identify the relationship. However, this will churn through the sequence relatively quickly with larger datasets and the DELETE before INSERT usage of HABTM. -- Ticket URL: <https://trac.cakephp.org/ticket/6245> CakePHP : The Rapid Development Framework for PHP <https://trac.cakephp.org/> Cake is a rapid development framework for PHP which uses commonly known design patterns like ActiveRecord, Association Data Mapping, Front Controller and MVC. Our primary goal is to provide a structured framework that enables PHP users at all levels to rapidly develop robust web applications, without any loss to flexibility. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "tickets cakephp" group. To post to this group, send email to tickets-cakephp@googlegroups.com To unsubscribe from this group, send email to tickets-cakephp+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/tickets-cakephp?hl=en -~----------~----~----~----~------~----~------~--~---