/** * @param JsonData $images * @param bool $removeFromCloud * @throws Scalr_Exception_Core * @throws \Scalr\Exception\ModelException */ public function xRemoveAction(JsonData $images, $removeFromCloud = false) { $this->restrictAccess('IMAGES', 'MANAGE'); $errors = []; $processed = []; $pending = []; foreach ($images as $hash) { try { /* @var $im Image */ $im = Image::findPk($hash); if ($im) { $this->checkPermissions($im, true); if (!$im->getUsed()) { if ($removeFromCloud && $this->user->isUser()) { if ($im->isUsedGlobal()) { throw new Exception(sprintf("Unable to delete %s, this Image may be:\n- Still registered in another Environment or Account\n- Currently in-use by a Server in another Environment", $im->id)); } $im->status = Image::STATUS_DELETE; $im->save(); $pending[] = $im->hash; } else { if ($this->user->isScalrAdmin() && $im->isUsedGlobal()) { throw new Exception(sprintf("Unable to delete %s, this Image may be:\n- Still registered in another Environment or Account\n- Currently in-use by a Server in another Environment", $im->id)); } $im->delete(); $processed[] = $im->hash; } } } } catch (Exception $e) { $errors[] = $e->getMessage(); } } $this->response->data(['processed' => $processed, 'pending' => $pending]); if (count($errors)) { $this->response->warning("Images(s) successfully removed, but some errors occurred:\n" . implode("\n", $errors)); } else { $this->response->success('Images(s) successfully removed'); } }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof Entity\Image) { throw new \InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\Image class")); } if ($entity->hash !== null) { //Checks if the image does exist if (!Entity\Image::findPk($entity->hash)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Image with ID: %d", $entity->hash)); } } else { $image = Entity\Image::findOne([['id' => $entity->id], ['platform' => $entity->platform], ['cloudLocation' => (string) $entity->cloudLocation], ['$or' => [['accountId' => null], ['$and' => [['accountId' => $entity->accountId], ['$or' => [['envId' => null], ['envId' => $entity->envId]]]]]]]]); if ($image) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "This Image has already been registered in Scalr"); } } //Is this a new Image if (!$entity->hash) { $entity->createdByEmail = $this->controller->getUser()->email; $entity->createdById = $this->controller->getUser()->id; } if (!Entity\Role::isValidName($entity->name)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid name of the Image"); } if (empty($entity->architecture)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property 'architecture'"); } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } //We only allow to either create or modify Environment Scope Roles if ($entity->getScope() !== $this->controller->getScope()) { throw new ApiErrorException(403, ErrorMessage::ERR_SCOPE_VIOLATION, sprintf("Invalid scope")); } if (empty($entity->osId)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property 'os.id'"); } //Tries to find out the specified OS if (empty(Entity\Os::findPk($entity->osId))) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "OS with id '{$entity->osId}' not found."); } if (empty($entity->platform)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property platform"); } if (!isset(SERVER_PLATFORMS::GetList()[$entity->platform])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Unexpected platform value"); } }
/** * @test */ public function testAccountRolesFunctional() { $db = \Scalr::getDb(); $testName = str_replace('-', '', static::getTestName()); $roles = null; $uri = self::getAccountApiUrl('/roles'); do { $query = []; if (isset($roles->pagination->next)) { $parts = parse_url($roles->pagination->next); parse_str($parts['query'], $query); } $describe = $this->request($uri, Request::METHOD_GET, $query); $this->assertDescribeResponseNotEmpty($describe); $this->assertNotEmpty($describe->getBody()); $roles = $describe->getBody(); foreach ($roles->data as $role) { $this->assertRolesObjectNotEmpty($role); if ($role->name == $testName) { $delete = $this->request($uri . '/' . $role->id, Request::METHOD_DELETE); $this->assertEquals(200, $delete->status); } } } while (!empty($roles->pagination->next)); // test create action $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => 'invalid']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid scope'); $create = $this->request($uri, Request::METHOD_POST); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Invalid body'); $create = $this->request($uri, Request::METHOD_POST, [], ['invalid' => 'value']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'You are trying to set'); $create = $this->request($uri, Request::METHOD_POST, [], ['id' => 'value']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid name'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => 'invalidName^$&&']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid name of the Role'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'description' => 'invalidDesc<br/>']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid description'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Role category should be provided'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => 'not int']]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid identifier of the category'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => -1]]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'The Role category does not exist'); $rolesCat = RoleCategory::findOne(); /* @var $rolesCat RoleCategory */ $this->assertNotEmpty($rolesCat); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => $rolesCat->id]]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property 'os.id'"); $os = Os::findOne([['status' => Os::STATUS_ACTIVE], ['family' => 'ubuntu'], ['generation' => '12.04']]); /* @var $os Os */ $this->assertNotEmpty($os); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => $rolesCat->id], 'os' => ['id' => -1]]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid identifier of the OS'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => $rolesCat->id], 'os' => ['id' => 'invalid']]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, "OS with id 'invalid' not found."); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'description' => $testName, 'category' => $rolesCat->id, 'os' => $os->id, 'quickStart' => true, 'deprecated' => true]); $body = $create->getBody(); $this->assertEquals(201, $create->response->getStatus()); $this->assertFetchResponseNotEmpty($create); $this->assertRolesObjectNotEmpty($body->data); $this->assertNotEmpty($body->data->id); $this->assertEquals($testName, $body->data->name); $this->assertEquals($testName, $body->data->description); $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $body->data->scope); $this->assertEquals($rolesCat->id, $body->data->category->id); $this->assertEquals($os->id, $body->data->os->id); $this->assertEquals(true, $body->data->quickStart); $this->assertEquals(true, $body->data->deprecated); // test images actions $roleId = $body->data->id; $imagesUri = $uri . '/' . $roleId . '/images'; $images = null; do { $query = []; if (isset($images->pagination->next)) { $parts = parse_url($images->pagination->next); parse_str($parts['query'], $query); } $describeImages = $this->request($imagesUri, Request::METHOD_GET, $query); $this->assertDescribeResponseNotEmpty($describeImages); $images = $describeImages->getBody(); foreach ($images->data as $imageRole) { $this->assertRoleImageObjectNotEmpty($imageRole); $this->assertEquals($roleId, $imageRole->role->id); $image = Image::findPk($imageRole->image->id); /* @var $image Image */ if ($image->name == $testName) { $delete = $this->request($imagesUri . '/' . $imageRole->image->id, Request::METHOD_DELETE); $this->assertEquals(200, $delete->status); } } } while (!empty($images->pagination->next)); $env = \Scalr_Environment::init()->loadById(static::$testEnvId); $platform = \SERVER_PLATFORMS::EC2; if (!$env->isPlatformEnabled($platform)) { $env->setPlatformConfig([$platform . '.is_enabled' => 1]); } $region = null; $cloudImageId = null; foreach (Aws::getCloudLocations() as $cloudLocation) { $cloudImageId = $this->getNewImageId($env, $cloudLocation); if (!empty($cloudImageId)) { $region = $cloudLocation; break; } } $this->assertNotNull($cloudImageId); $this->assertNotNull($cloudLocation); $image = $this->createEntity(new Image(), ['accountId' => $this->getUser()->accountId, 'name' => $testName, 'osId' => $os->id, 'platform' => $platform, 'cloudLocation' => $region, 'id' => $cloudImageId, 'architecture' => 'x86_64', 'source' => Image::SOURCE_MANUAL, 'status' => Image::STATUS_ACTIVE]); $createRoleImage = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId + 10], 'image' => ['id' => $image->hash]]); $this->assertErrorMessageStatusEquals(400, $createRoleImage); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $createRoleImage); $createRoleImage = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId]]); $this->assertErrorMessageStatusEquals(400, $createRoleImage); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $createRoleImage); $createRoleImage = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId], 'image' => ['id' => '11111111-1111-1111-1111-111111111111']]); $this->assertErrorMessageStatusEquals(404, $createRoleImage); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $createRoleImage); $createRoleImage = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId], 'image' => ['id' => $image->hash]]); $createRoleImageBody = $createRoleImage->getBody(); $this->assertEquals(201, $createRoleImage->response->getStatus()); $this->assertFetchResponseNotEmpty($createRoleImage); $this->assertRoleImageObjectNotEmpty($createRoleImageBody->data); $createRoleImageError = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId], 'image' => ['id' => $image->hash]]); $this->assertErrorMessageStatusEquals(400, $createRoleImageError); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_BAD_REQUEST, $createRoleImageError); $fetchImage = $this->request($imagesUri . '/' . $createRoleImageBody->data->image->id, Request::METHOD_GET); $fetchImageBody = $fetchImage->getBody(); $this->assertEquals(200, $fetchImage->response->getStatus()); $this->assertFetchResponseNotEmpty($fetchImage); $this->assertImageObjectNotEmpty($fetchImageBody->data); $this->assertEquals($cloudImageId, $fetchImageBody->data->cloudImageId); $this->assertEquals($testName, $fetchImageBody->data->name); // test role images filtering $describeRoleImages = $this->request($imagesUri, Request::METHOD_GET, ['role' => $roleId]); $this->assertDescribeResponseNotEmpty($describeRoleImages); foreach ($describeRoleImages->getBody()->data as $data) { $this->assertRoleImageObjectNotEmpty($data); $this->assertEquals($roleId, $data->role->id); } $describeRoleImages = $this->request($imagesUri, Request::METHOD_GET, ['image' => $image->hash]); $this->assertDescribeResponseNotEmpty($describeRoleImages); foreach ($describeRoleImages->getBody()->data as $data) { $this->assertRoleImageObjectNotEmpty($data); $this->assertEquals($image->hash, $data->image->id); } $describeRoleImages = $this->request($imagesUri, Request::METHOD_GET, ['invalid' => 'value']); $this->assertErrorMessageContains($describeRoleImages, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Unsupported filter'); $currentRole = Role::findPk($roleId); /* @var $currentRole Role */ $this->assertNotEmpty($currentRole); $adminImages = Image::find([['envId' => null], ['status' => Image::STATUS_ACTIVE], ['cloudLocation' => $region]]); $this->assertNotEmpty($adminImages); $adminImage = null; foreach ($adminImages as $aImage) { /* @var $aImage Image */ $imageOs = $aImage->getOs(); if (!empty($imageOs) && $imageOs->generation == $currentRole->getOs()->generation && $imageOs->family == $currentRole->getOs()->family) { $adminImage = $aImage; break; } } /* @var $adminImage Image */ $this->assertNotEmpty($adminImage); $this->assertNotEquals($createRoleImageBody->data->image->id, $adminImage->hash); $replaceImage = $this->request($imagesUri . '/' . $createRoleImageBody->data->image->id . '/actions/replace', Request::METHOD_POST, [], ['role' => $roleId, 'image' => $adminImage->hash]); $replaceImageBody = $replaceImage->getBody(); $this->assertEquals(200, $replaceImage->response->getStatus()); $this->assertFetchResponseNotEmpty($replaceImage); $this->assertRoleImageObjectNotEmpty($replaceImageBody->data); $this->assertEquals($adminImage->hash, $replaceImageBody->data->image->id); $deleteImage = $this->request($imagesUri . '/' . $replaceImageBody->data->image->id, Request::METHOD_DELETE); $this->assertEquals(200, $deleteImage->response->getStatus()); $delete = $this->request(static::getAccountApiUrl("images/{$image->hash}"), Request::METHOD_DELETE); $this->assertEquals(200, $delete->response->getStatus()); // test get action $notFoundRoleId = 10 + $db->GetOne("SELECT MAX(r.id) FROM roles r"); $get = $this->request($uri . '/' . $notFoundRoleId, Request::METHOD_GET); $this->assertErrorMessageContains($get, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "The Role either does not exist or isn't in scope for the current Environment"); $get = $this->request($uri . '/' . $body->data->id, Request::METHOD_GET); $getBody = $get->getBody(); $this->assertEquals(200, $get->response->getStatus()); $this->assertFetchResponseNotEmpty($get); $this->assertRolesObjectNotEmpty($getBody->data); $this->assertEquals($body->data->id, $getBody->data->id); $this->assertEquals($testName, $getBody->data->name); $this->assertEquals($testName, $getBody->data->description); $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $getBody->data->scope); $this->assertEquals($rolesCat->id, $getBody->data->category->id); $this->assertEquals($os->id, $getBody->data->os->id); // test filters $describe = $this->request($uri, Request::METHOD_GET, ['description' => $testName]); $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Unsupported filter'); $describe = $this->request($uri, Request::METHOD_GET, ['scope' => 'wrong<br>']); $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, 'Unexpected scope value'); $describe = $this->request($uri, Request::METHOD_GET, ['scope' => ScopeInterface::SCOPE_SCALR]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertRolesObjectNotEmpty($data); } $describe = $this->request($uri, Request::METHOD_GET, ['scope' => ScopeInterface::SCOPE_ACCOUNT]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertRolesObjectNotEmpty($data); $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $data->scope); } $describe = $this->request($uri, Request::METHOD_GET, ['name' => $testName]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertRolesObjectNotEmpty($data); $this->assertEquals($testName, $data->name); } $describe = $this->request($uri, Request::METHOD_GET, ['id' => $roleId]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertRolesObjectNotEmpty($data); $this->assertEquals($roleId, $data->id); } $describe = $this->request($uri, Request::METHOD_GET, ['os' => $os->id]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertRolesObjectNotEmpty($data); $this->assertEquals($os->id, $data->os->id); } $describe = $this->request($uri, Request::METHOD_GET, ['os' => 'invalid*&^^%']); $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, "Invalid identifier of the OS"); $describe = $this->request($uri, Request::METHOD_GET, ['category' => $rolesCat->id]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertRolesObjectNotEmpty($data); $this->assertEquals($rolesCat->id, $data->category->id); } $describe = $this->request($uri, Request::METHOD_GET, ['category' => '']); $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, "Invalid identifier of the category"); // test modify action $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH); $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Invalid body'); $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH, [], ['id' => 123]); $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_STRUCTURE); $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH, [], ['invalid' => 'err']); $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'You are trying to set'); $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH, [], ['scope' => 'environment']); $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_VALUE); $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH, [], ['description' => '']); $modifyBody = $modify->getBody(); $this->assertEquals(200, $modify->response->getStatus()); $this->assertFetchResponseNotEmpty($modify); $this->assertRolesObjectNotEmpty($modifyBody->data); $this->assertEquals($body->data->id, $modifyBody->data->id); $this->assertEquals($testName, $modifyBody->data->name); $this->assertEquals('', $modifyBody->data->description); $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $modifyBody->data->scope); $this->assertEquals($rolesCat->id, $modifyBody->data->category->id); $this->assertEquals($os->id, $modifyBody->data->os->id); // test delete action $delete = $this->request(static::getAccountApiUrl("/roles/{$notFoundRoleId}"), Request::METHOD_DELETE); $this->assertErrorMessageContains($delete, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); $delete = $this->request($uri . '/' . $body->data->id, Request::METHOD_DELETE); $this->assertEquals(200, $delete->status); $db->Execute("INSERT INTO roles SET\n name = ?,\n dtadded = NOW(),\n env_id\t = NULL,\n client_id = NULL,\n generation = 2\n ", [$testName]); $insertedId = $db->_insertid(); $db->Execute("INSERT INTO role_images SET\n role_id = ?,\n platform = 'ec2',\n image_id = 'test'\n ", [$insertedId]); $delete = $this->request($uri . '/' . $insertedId, Request::METHOD_DELETE); $db->Execute("DELETE FROM roles WHERE name = ? AND id = ?", [$testName, $insertedId]); $this->assertErrorMessageContains($delete, 403, ErrorMessage::ERR_SCOPE_VIOLATION); }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof Entity\Image) { throw new \InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\Image class")); } if ($entity->hash !== null) { //Checks if the image does exist if (!Entity\Image::findPk($entity->hash)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Image with ID: %d", $entity->hash)); } } else { $image = Entity\Image::findOne([['id' => $entity->id], ['$or' => [['envId' => $entity->envId], ['envId' => null]]], ['platform' => $entity->platform], ['cloudLocation' => $entity->cloudLocation]]); if ($image) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "This Image has already been registered in Scalr"); } } //Is this a new Image if (!$entity->hash) { $entity->createdByEmail = $this->controller->getUser()->email; $entity->createdById = $this->controller->getUser()->id; } if (!Entity\Role::validateName($entity->name)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid name of the Image"); } $entity->architecture = $entity->architecture ?: 'x86_64'; if (!in_array($entity->architecture, ['i386', 'x86_64'])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid architecture of the Image."); } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } //We only allow to either create or modify Environment Scope Roles if ($entity->getScope() !== ScopeInterface::SCOPE_ENVIRONMENT) { throw new ApiErrorException(403, ErrorMessage::ERR_SCOPE_VIOLATION, sprintf("Only %s scope is allowed.", ScopeInterface::SCOPE_ENVIRONMENT)); } //Validates OS if (!empty($entity->osId)) { //Tries to find out the specified OS $os = Entity\Os::findPk($entity->osId); if (!$os instanceof Entity\Os) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Specified OS does not exist"); } } else { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "OS must be provided with the request."); } }