Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

Updated Apigility Admin to allow setting of the default API version #27

Closed
wants to merge 9 commits into from
2 changes: 1 addition & 1 deletion asset/zf-apigility-admin/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
border-right: 1px solid #563d7c;
}
#api-version {
margin-top: -100px;
margin-top: -125px;
}
div.alert {
position: fixed;
Expand Down
15 changes: 15 additions & 0 deletions asset/zf-apigility-admin/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ module.controller('ApiRestServicesController', ['$http', '$rootScope', '$scope',
$timeout(function () {
ApiRepository.getApi($scope.api.name, $scope.api.version, true).then(function (api) {
$scope.api = api;
$scope.currentVersion = api.currentVersion;
});
}, 500);
$scope.showNewRestServiceForm = false;
Expand Down Expand Up @@ -540,6 +541,7 @@ module.controller(
ApiRepository.getApi($routeParams.apiName, $routeParams.version).then(function (api) {
$scope.api = api;
$scope.currentVersion = api.version;
$scope.defaultApiVersion = api.default_version;
});

$scope.createNewApiVersion = function () {
Expand All @@ -552,6 +554,12 @@ module.controller(
});
};

$scope.setDefaultApiVersion = function () {
ApiRepository.setDefaultApiVersion($scope.api.name, $scope.defaultApiVersion).then(function (data) {
$scope.defaultApiVersion = data.version;
});
};

$scope.changeVersion = function () {
var curPath = $location.path();
var lastSegment = curPath.substr(curPath.lastIndexOf('/') + 1);
Expand Down Expand Up @@ -720,6 +728,13 @@ module.factory('ApiRepository', ['$rootScope', '$q', '$http', 'apiBasePath', fun
.then(function (response) {
return response.data;
});
},

setDefaultApiVersion: function (apiName, defaultApiVersion) {
return $http({method: 'patch', url: '/admin/api/default-version', data: {module: apiName, version: defaultApiVersion}})
.then(function (response) {
return response.data;
});
}
};

Expand Down
18 changes: 15 additions & 3 deletions asset/zf-apigility-admin/partials/api/version.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
<div id="api-version" class="pull-right" ng-controller="ApiVersionController">
<div>Current Version: {{ api.version }}</div>
<div>
<select ng-model="currentVersion" ng-options="ver for ver in api.versions" ng-change="changeVersion()"></select>
<label for="current-api-version">Current Version:</label>
<select id="current-api-version" ng-model="currentVersion" ng-options="ver for ver in api.versions"
ng-change="changeVersion()"></select>
</div>
<div>
<label for="default-api-version">Default Version:</label>
<select id="default-api-version" ng-model="defaultApiVersion" ng-options="ver for ver in api.versions"
ng-change="setDefaultApiVersion()"></select>
</div>
<div>
<button class="btn btn-primary btn-sm" ng-click="createNewApiVersion()">Create New Version</button>
</div>
</div>

<div ng-switch="section" class="clearfix">
<div ng-switch-when="info"><api-info></api-info></div>
<div ng-switch-when="rest-services"><api-rest-services></api-rest-services></div>
<div ng-switch-when="rpc-services"><api-rpc-services></api-rpc-services></div>
</div>
10 changes: 10 additions & 0 deletions config/module.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@
),
),
),
'default-version' => array(
'type' => 'literal',
'options' => array(
'route' => '/default-version',
'defaults' => array(
'controller' => 'ZF\Apigility\Admin\Controller\Versioning',
'action' => 'defaultVersion',
),
),
),
'module' => array(
'type' => 'segment',
'options' => array(
Expand Down
28 changes: 28 additions & 0 deletions src/ZF/Apigility/Admin/Controller/VersioningController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,34 @@ public function __construct(VersioningModelFactory $modelFactory)
$this->modelFactory = $modelFactory;
}

public function defaultVersionAction()
{
$module = $this->bodyParam('module', false);
if (!$module) {
return new ApiProblemModel(
new ApiProblem(422, 'Module parameter not provided', 'https://tools.ietf.org/html/rfc4918', 'Unprocessable Entity')
);
}

$version = $this->bodyParam('version', false);

if (!$version || !is_numeric($version)) {
return new ApiProblemModel(
new ApiProblem(422, 'Missing or invalid version', 'https://tools.ietf.org/html/rfc4918', 'Unprocessable Entity')
);
}

$model = $this->modelFactory->factory($module);

if ($model->setDefaultVersion($version)) {
return array('success' => true, 'version' => $version);
} else {
return new ApiProblemModel(
new ApiProblem(500, 'An unexpected error occurred while attempting to set the default version')
);
}
}

public function versioningAction()
{
$request = $this->getRequest();
Expand Down
29 changes: 23 additions & 6 deletions src/ZF/Apigility/Admin/Model/ModuleEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

class ModuleEntity
{
/**
* @var int
*/
protected $defaultVersion = 1;

/**
* @var string
*/
Expand Down Expand Up @@ -64,6 +69,14 @@ public function __construct($namespace, array $restServices = array(), array $rp
$this->isVendor = is_bool($isVendor) ? $isVendor : null;
}

/**
* @return int
*/
public function getDefaultVersion()
{
return $this->defaultVersion;
}

/**
* @return string
*/
Expand Down Expand Up @@ -173,6 +186,9 @@ public function exchangeArray(array $data)
}
$this->versions = $value;
break;
case 'default_version':
$this->defaultVersion = (int) $value;
break;
default:
break;
}
Expand All @@ -187,12 +203,13 @@ public function exchangeArray(array $data)
public function getArrayCopy()
{
return array(
'name' => $this->name,
'namespace' => $this->namespace,
'is_vendor' => $this->isVendor(),
'rest' => $this->getRestServices(),
'rpc' => $this->getRpcServices(),
'versions' => $this->versions,
'name' => $this->name,
'namespace' => $this->namespace,
'is_vendor' => $this->isVendor(),
'rest' => $this->getRestServices(),
'rpc' => $this->getRpcServices(),
'versions' => $this->versions,
'default_version' => $this->defaultVersion,
);
}

Expand Down
16 changes: 15 additions & 1 deletion src/ZF/Apigility/Admin/Model/ModuleModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Zend\View\Resolver;
use ZF\Apigility\Admin\Exception;
use ZF\Apigility\ApigilityModuleInterface;
use ZF\Configuration\Module;

class ModuleModel
{
Expand Down Expand Up @@ -235,7 +236,8 @@ protected function getEnabledModules()
$versions = $this->getVersionsByModule($moduleName, $module);
$entity = new ModuleEntity($moduleName, $services['rest'], $services['rpc']);
$entity->exchangeArray(array(
'versions' => $versions,
'versions' => $versions,
'default_version' => $this->getModuleDefaultVersion($module),
));

$this->modules[$entity->getName()] = $entity;
Expand All @@ -244,6 +246,18 @@ protected function getEnabledModules()
return $this->modules;
}

/**
* Retrieves the configured default version for the specified module.
*
* @param ApigilityModuleInterface $module
* @return int
*/
protected function getModuleDefaultVersion(ApigilityModuleInterface $module)
{
$config = $module->getConfig();
return isset($config['zf-versioning']['default-version']) ? $config['zf-versioning']['default-version'] : 1;
}

/**
* Retrieve all services for a given module
*
Expand Down
23 changes: 23 additions & 0 deletions src/ZF/Apigility/Admin/Model/VersioningModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,29 @@ public function getModuleVersions($module, $path = false)
return $versions;
}

/**
* Updates the default version of a module that will be used if no version is
* specified by the API consumer.
*
* @param integer $defaultVersion
* @return boolean
*/
public function setDefaultVersion($defaultVersion)
{
$defaultVersion = (int) $defaultVersion;

$this->configResource->patch(array(
'zf-versioning' => array(
'default-version' => $defaultVersion
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This key should be underscore separated, not dash (we use dash-separated for top-level keys representing modules, but underscore-separated for the options beneath them).

I'll modify this on merge.

)
), true);

$config = $this->configResource->fetch(true);

return isset($config['zf-versioning']['default-version'])
&& $config['zf-versioning']['default-version'] === $defaultVersion;
}

/**
* Copy file and folder recursively
*
Expand Down
22 changes: 22 additions & 0 deletions test/ZFTest/Apigility/Admin/Model/ModuleEntityTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/**
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
* @copyright Copyright (c) 2013 Zend Technologies USA Inc. (http://www.zend.com)
*/

namespace ZFTest\Apigility\Admin\Model;

use PHPUnit_Framework_TestCase as TestCase;
use ZF\Apigility\Admin\Model\ModuleEntity;

class ModuleEntityTest extends TestCase
{
public function testCanSetAndRetrieveModuleDefaultVersion()
{
$moduleEntity = new ModuleEntity('Test\Foo');
$this->assertSame(1, $moduleEntity->getDefaultVersion()); // initial state

$moduleEntity->exchangeArray(array('default_version' => 123));
$this->assertSame(123, $moduleEntity->getDefaultVersion());
}
}
29 changes: 29 additions & 0 deletions test/ZFTest/Apigility/Admin/Model/ModuleModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,33 @@ public function testVendorModulesAreMarkedAccordingly()
$this->assertTrue($module->isVendor());
}
}

public function testDefaultApiVersionIsSetProperly()
{
$modules = array(
'Test\Bar' => new Test\Bar\Module(),
'Test\Foo' => new Test\Foo\Module(),
);
$moduleManager = $this->getMockBuilder('Zend\ModuleManager\ModuleManager')
->disableOriginalConstructor()
->getMock();
$moduleManager->expects($this->any())
->method('getLoadedModules')
->will($this->returnValue($modules));

$model = new ModuleModel($moduleManager, array(), array());

$modules = $model->getModules();

$this->assertSame(
1,
$modules[0]->getDefaultVersion(),
'Did not default to version 1 as the default version for unconfigured default version of Test\Bar!'
);
$this->assertSame(
123,
$modules[1]->getDefaultVersion(),
'Did not read configured default version 123 for Test\Foo!'
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ return array (
),
),
),
'zf-versioning' => array (
'default-version' => 1,
),
'zf-apigility' => array (
'db-connected' => array (
'Version\\V1\\Rest\\Message\\MessageResource' => array (
Expand Down
11 changes: 11 additions & 0 deletions test/ZFTest/Apigility/Admin/Model/VersioningModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,15 @@ public function testCreateNewVersionClonesAuthorizationConfigurationForNewVersio
$this->assertEquals($originalAuthorization[$serviceName], $updatedAuthorization[$newServiceName]);
}
}

public function testSettingTheApiDefaultVersion()
{
$config = include $this->moduleConfigFile;
$this->assertSame(1, $config['zf-versioning']['default-version']);

$this->assertTrue($this->model->setDefaultVersion(1337));

$newConfig = include $this->moduleConfigFile;
$this->assertSame(1337, $newConfig['zf-versioning']['default-version']);
}
}
4 changes: 4 additions & 0 deletions vendor/Test/Bar/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@

class Module implements ApigilityModuleInterface
{
public function getConfig()
{
return array();
}
}
8 changes: 8 additions & 0 deletions vendor/Test/Foo/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,12 @@

class Module implements ApigilityModuleInterface
{
public function getConfig()
{
return array(
'zf-versioning' => array(
'default-version' => 123,
),
);
}
}