Doctrine 1
  1. Doctrine 1
  2. DC-79

Unexpected exception type when saving a relation with an invalid model in it

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.1.4, 1.2.0-ALPHA1
    • Fix Version/s: 1.2.0-ALPHA3
    • Labels:
      None
    • Environment:
      Ubuntu Linux, PostgreSQL 8.3, PHP 5.2.6

      Description

      When creating two related models and saving the main one to the database, both models get stored in the database. That is expected behavior. Now, when one of the two models has a validation problem and I call save() on it - without first linking it to the other model - I get a Doctrine_Validator_Exception. That is expected behavior. Now (patience, we're getting to the bug now), when one or both of the models has a validation problem and I link them prior to saving them, I don't get a Doctrine_Validator_Exception, but instead a database level exception Doctrine_Connection_Pgsql_Exception. That is unexpected behavior.

      One wouldn't notice this issue when doing code like:

        try {
          $object->save();
        } catch (Exception $e) {
          // .. handle the exception
        }
      

      However, code like we are using it in our project more often looks like this:

        try {
          $object->save();
        } catch (Doctrine_Validator_Exception $e) {
          // .. handle the validation exception
        } catch (One_Of_Our_Exception $e) {
          // .. handle our exception
        } catch (Exception $e) {
          throw $e; // unexpected exception, re-throw and pray 
        }
      

      In the attachment you find a test.yml and a test.php that I used for figuring out the behavior. Here's the output from running the test script:

      1. OK, got expected exception
      2. OK, record A saved
      3. OK, got expected exception
      4. OK, record B saved
      5. OK, record A saved with a linked record B
      6. Error: unexpected exception was thrown.
         Type: Doctrine_Connection_Pgsql_Exception
         Message: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "b_id" violates not-null constraint
      7. Error: unexpected exception was thrown.
         Type: Doctrine_Connection_Pgsql_Exception
         Message: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "a_id" violates not-null constraint
      8. Error: unexpected exception was thrown.
         Type: Doctrine_Connection_Pgsql_Exception
         Message: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "a_id" violates not-null constraint
      

      Inspecting the Connection/UnitOfWork.php code, I see that saveGraph() calls $isValid = $this->insert($record). Now, when insert() sees that the record is invalid, it returns a false value. Somewhat later this results in calling $conn->transaction->addInvalid($record) to register the problem. At the end of the code block, I find (around line 126):

                      // save the MANY-TO-MANY associations
                      $this->saveAssociations($record);
      

      That is the point where things break. Even when an associated record does not validate, saveAssociations() will be called, resulting in a db level error about a reference id not being set (logical, since the related record was not saved and did not get an id assigned to it).

      In my opinion, this shouldn't happen, but I'm only using Doctrine for one day, so if I am missing some important piece of knowledge or documentation here, then please let me know.

      1. test.php
        2 kB
        Maurice Makaay
      2. test.yml
        0.6 kB
        Maurice Makaay

        Activity

        Hide
        Maurice Makaay added a comment -

        Note: I have tested some more and like expected, I got the correct exception when loading an existing A->B relation, breaking B and calling A->save(). In that case, storing the AB relation won't fail, because B already has an id. Saving the relation is successful and in the end, the validation exception is thrown as expected.

        Test code for this extra test case:

        $at = Doctrine::getTable('A');
        $a = $at->find(1); 
        
        $a->Bs[0]->field = null;
        
        $a->save();
        
        Show
        Maurice Makaay added a comment - Note: I have tested some more and like expected, I got the correct exception when loading an existing A->B relation, breaking B and calling A->save(). In that case, storing the AB relation won't fail, because B already has an id. Saving the relation is successful and in the end, the validation exception is thrown as expected. Test code for this extra test case: $at = Doctrine::getTable('A'); $a = $at->find(1); $a->Bs[0]->field = null ; $a->save();

          People

          • Assignee:
            Jonathan H. Wage
            Reporter:
            Maurice Makaay
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: