/** * Handling for is_primary. * $params is_primary could be * # 1 - find other entries with is_primary = 1 & reset them to 0 * # 0 - make sure at least one entry is set to 1 * - if no other entry is 1 change to 1 * - if one other entry exists change that to 1 * - if more than one other entry exists change first one to 1 * @fixme - perhaps should choose by location_type * # empty - same as 0 as once we have checked first step * we know if it should be 1 or 0 * * if $params['id'] is set $params['contact_id'] may need to be retrieved * * @param array $params * @static */ public static function handlePrimary(&$params, $class) { $table = CRM_Core_DAO_AllCoreTables::getTableForClass($class); if (!$table) { throw new API_Exception("Failed to locate table for class [{$class}]"); } // contact_id in params might be empty or the string 'null' so cast to integer $contactId = (int) CRM_Utils_Array::value('contact_id', $params); // If id is set & we haven't been passed a contact_id, retrieve it if (!empty($params['id']) && !isset($params['contact_id'])) { $entity = new $class(); $entity->id = $params['id']; $entity->find(TRUE); $contactId = $entity->contact_id; } // If entity is not associated with contact, concept of is_primary not relevant if (!$contactId) { return; } // if params is_primary then set all others to not be primary & exit out if (!empty($params['is_primary'])) { $sql = "UPDATE {$table} SET is_primary = 0 WHERE contact_id = %1"; $sqlParams = array(1 => array($contactId, 'Integer')); // we don't want to create unecessary entries in the log_ tables so exclude the one we are working on if (!empty($params['id'])) { $sql .= " AND id <> %2"; $sqlParams[2] = array($params['id'], 'Integer'); } CRM_Core_DAO::executeQuery($sql, $sqlParams); return; } //Check what other emails exist for the contact $existingEntities = new $class(); $existingEntities->contact_id = $contactId; $existingEntities->orderBy('is_primary DESC'); if (!$existingEntities->find(TRUE) || !empty($params['id']) && $existingEntities->id == $params['id']) { // ie. if no others is set to be primary then this has to be primary set to 1 so change $params['is_primary'] = 1; return; } else { /* * If the only existing email is the one we are editing then we must set * is_primary to 1 * CRM-10451 */ if ($existingEntities->N == 1 && $existingEntities->id == CRM_Utils_Array::value('id', $params)) { $params['is_primary'] = 1; return; } if ($existingEntities->is_primary == 1) { return; } // so at this point we are only dealing with ones explicity setting is_primary to 0 // since we have reverse sorted by email we can either set the first one to // primary or return if is already is $existingEntities->is_primary = 1; $existingEntities->save(); } }
public function testGetTableForClass() { $this->assertEquals('civicrm_email', CRM_Core_DAO_AllCoreTables::getTableForClass('CRM_Core_DAO_Email')); $this->assertEquals('civicrm_email', CRM_Core_DAO_AllCoreTables::getTableForClass('CRM_Core_BAO_Email')); }
/** * Joins onto an fk field * * Adds one or more joins to the query to make this field available for use in a clause. * * Enforces permissions at the api level and by appending the acl clause for that entity to the join. * * @param $fkFieldName * @return array|null * Returns the table and field name for adding this field to a SELECT or WHERE clause * @throws \API_Exception * @throws \Civi\API\Exception\UnauthorizedException */ private function addFkField($fkFieldName) { $stack = explode('.', $fkFieldName); if (count($stack) < 2) { return NULL; } $prev = 'a'; foreach ($stack as $depth => $fieldName) { // Setup variables then skip the first level if (!$depth) { $fk = $fieldName; // We only join on core fields // @TODO: Custom contact ref fields could be supported too if (!in_array($fk, $this->entityFieldNames)) { return NULL; } $fkField =& $this->apiFieldSpec[$fk]; continue; } // More than 4 joins deep seems excessive - DOS attack? if ($depth > self::MAX_JOINS) { throw new UnauthorizedException("Maximum number of joins exceeded for api.{$this->entity}.get in parameter {$fkFieldName}"); } if (!isset($fkField['FKApiName']) && !isset($fkField['FKClassName'])) { // Join doesn't exist - might be another param with a dot in it for some reason, we'll just ignore it. return NULL; } // Ensure we have permission to access the other api if (!$this->checkPermissionToJoin($fkField['FKApiName'], array_slice($stack, 0, $depth))) { throw new UnauthorizedException("Authorization failed to join onto {$fkField['FKApiName']} api in parameter {$fkFieldName}"); } if (!isset($fkField['FKApiSpec'])) { $fkField['FKApiSpec'] = \_civicrm_api_get_fields($fkField['FKApiName']); } $fieldInfo = \CRM_Utils_Array::value($fieldName, $fkField['FKApiSpec']); // FIXME: What if the foreign key is not the "id" column? if (!$fieldInfo || !isset($fkField['FKApiSpec']['id'])) { // Join doesn't exist - might be another param with a dot in it for some reason, we'll just ignore it. return NULL; } $fkTable = \CRM_Core_DAO_AllCoreTables::getTableForClass($fkField['FKClassName']); $tableAlias = implode('_to_', array_slice($stack, 0, $depth)) . "_to_{$fkTable}"; $joinClause = "LEFT JOIN {$fkTable} {$tableAlias} ON {$prev}.{$fk} = {$tableAlias}.id"; // Add acl condition $joinCondition = $this->getAclClause($tableAlias, $fkField['FKClassName']); if ($joinCondition !== NULL) { $joinClause .= " AND {$joinCondition}"; } $this->query->join($tableAlias, $joinClause); if (strpos($fieldName, 'custom_') === 0) { list($tableAlias, $fieldName) = $this->addCustomField($fieldInfo, $tableAlias); } // Get ready to recurse to the next level $fk = $fieldName; $fkField =& $fkField['FKApiSpec'][$fieldName]; $prev = $tableAlias; } return array($tableAlias, $fieldName); }
/** * @param $testEntityClass * @param $createParams * @param $updateParams * @param $expectedError * @dataProvider badUpdateProvider */ public function testCreateWithBadUpdate($testEntityClass, $createParams, $updateParams, $expectedError) { $entity = CRM_Core_DAO::createTestObject($testEntityClass); $entity_table = CRM_Core_DAO_AllCoreTables::getTableForClass($testEntityClass); $this->assertTrue(is_numeric($entity->id)); $createResult = $this->callAPISuccess('Attachment', 'create', $createParams + array('entity_table' => $entity_table, 'entity_id' => $entity->id)); $fileId = $createResult['id']; $this->assertTrue(is_numeric($fileId)); $updateResult = $this->callAPIFailure('Attachment', 'create', $updateParams + array('id' => $fileId)); $this->assertRegExp($expectedError, $updateResult['error_message']); }