/** * @covers ::many_to_many_get */ function test_many_to_many_get() { $admin = User::all()->root()->select(); No2_SQLQuery::execute('INSERT INTO {users_roles_table}(user_id, role_id) VALUES (:id, :admin_role_id), (:id, :anonymous_role_id)', ['{users_roles_table}' => 'users_roles', ':id' => $admin->id, ':admin_role_id' => Role::ADMIN_ID, ':anonymous_role_id' => Role::ANONYMOUS_ID]); $user_roles = array_map(function ($r) { return $r->id; }, $admin->roles()->select()); $this->assertCount(2, $user_roles, 'User should have two roles'); $this->assertContains(Role::ADMIN_ID, $user_roles, 'User should have admin role'); $this->assertContains(Role::ANONYMOUS_ID, $user_roles, 'User should have anonymous role'); }
/** * 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; }
/** * Find many rows with an SQL statment. * * Allow to create a complexe SELECT query that will return this type of * Model. This method is a wrapper around find_by_sql() which always return * an array. * * @see * No2_SQLQuery::execute(), No2_Database::execute() * * @return * An array with all instances found (one or zero results will still be * returned in a array). */ public static function find_all_by_sql($sql, $arguments = [], $options = []) { return No2_SQLQuery::execute($sql, $arguments, array_merge($options, ['factory' => get_called_class(), 'return_as_collection' => true])); }