function test_many_to_many_set_when_already_in_a_transaction() { $this->assertTrue(No2_SQLQuery::_beginTransaction()); $admin = User::all()->root()->select(); $admin->set_roles([Role::ADMIN_ID]); $roles = $admin->roles()->select(); $this->assertTrue(No2_SQLQuery::_commitTransaction()); $this->assertCount(1, $roles, 'root should have exactly one role'); $this->assertEquals(Role::ADMIN_ID, $roles[0]->id, 'the only root role should be ADMIN'); }
/** * Links this model to the others: handles all the stuff about the join table. * * @param * array $relation: The relation to use * * Define the relation with an array containing 3 values: * - The target key: the column linked to this model in the join table * - The join table name * - The linked key: the column linked to the other model in the join table * * @param * array $others: An array of Models or of ids * * @throws * InvalidArgumentException when the relation is not well defined * LogicException when $this is a new record * * @return * boolean: true on success, false otherwise */ protected function many_to_many_set($relation, $others = null) { if ($this->is_new_record()) { throw new LogicException('many_to_many_set called on a new record'); } if (!is_array($relation) || count($relation) < 3) { throw new InvalidArgumentException('The relation is not defined'); } list($target_key, $join_table, $linked_key) = $relation; $delete = 'DELETE FROM {join_table} WHERE {target_key} = :id'; $insert = 'INSERT INTO {join_table} ({target_key}, {linked_key}) VALUES'; $insert_params = $delete_params = ['{join_table}' => $join_table, '{target_key}' => $target_key, '{linked_key}' => $linked_key, ':id' => $this->id]; // build the VALUES (...) for the INSERT statment $values = []; if (is_array($others) && !empty($others)) { for ($i = 0, $n = count($others); $i < $n; $i++) { $other = $others[$i]; $label = ":val_{$i}"; $values[] = "(:id, {$label})"; $insert_params[$label] = is_object($other) && isset($other->id) ? $other->id : $other; } } $values = join(', ', $values); $profile = $this->__db_profile; $options = ['profile' => $profile]; if (empty($values)) { $success = No2_SQLQuery::execute($delete, $delete_params, $options) !== false; } else { // start a transaction if we're not already in one. $already_in_transaction = No2_SQLQuery::_inTransaction(); if (!$already_in_transaction) { No2_SQLQuery::_beginTransaction($profile); } // do the work $success = No2_SQLQuery::execute($delete, $delete_params, $options) !== false && No2_SQLQuery::execute("{$insert} {$values}", $insert_params, $options) !== false; // terminate the transaction if we started it. if (!$already_in_transaction) { if ($success) { No2_SQLQuery::_commitTransaction($profile); } else { No2_SQLQuery::_rollBackTransaction($profile); } } } return $success; }