' +
'| ' + Lang.get('stage_' + stage) + ' | ' +
+ '' + step + ' | ' +
'' + pluginName + ' | ' +
'' +
this.statusLabels[data.status] +
diff --git a/public/assets/js/build-plugins/warnings.js b/public/assets/js/build-plugins/warnings.js
index 83d0daa52..d4a03ce06 100644
--- a/public/assets/js/build-plugins/warnings.js
+++ b/public/assets/js/build-plugins/warnings.js
@@ -24,13 +24,14 @@ var warningsPlugin = ActiveBuild.UiPlugin.extend({
displayOnUpdate: false,
rendered: false,
chartData: null,
+ showWidget: false,
register: function () {
var self = this;
var queries = [];
for (var key in self.keys) {
- queries.push(ActiveBuild.registerQuery(key, -1, {num_builds: 10, key: key}));
+ queries.push(ActiveBuild.registerQuery(key, -1, {num_builds: 20, key: key}));
}
$(window).on(Object.keys(self.keys).join(' '), function (data) {
@@ -65,6 +66,16 @@ var warningsPlugin = ActiveBuild.UiPlugin.extend({
var self = this;
var builds = e.queryData;
+ if (!self.showWidget) {
+ if (!e.queryData || $.isEmptyObject(e.queryData)) {
+ $('#build-warnings').hide();
+
+ return;
+ }
+ }
+
+ self.showWidget = true;
+
if (!builds || !builds.length) {
return;
}
@@ -122,10 +133,12 @@ var warningsPlugin = ActiveBuild.UiPlugin.extend({
var color = colors.shift();
self.chartData.datasets.push({
- label: self.keys[key],
- borderColor: color,
- color: color,
- data: []
+ label: self.keys[key],
+ borderColor: color,
+ backgroundColor: color,
+ data: [],
+ cubicInterpolationMode: 'monotone',
+ tension: 0.2
});
for (var build in self.data) {
@@ -148,7 +161,7 @@ var warningsPlugin = ActiveBuild.UiPlugin.extend({
var self = this;
if ($('#information').hasClass('active') && self.chartData) {
- $('#build-warnings-chart').show();
+ $('#build-warnings').show();
var ctx = $("#build-warnings-linechart").get(0).getContext("2d");
@@ -160,7 +173,8 @@ var warningsPlugin = ActiveBuild.UiPlugin.extend({
data: self.chartData,
options: {
datasetFill: false,
- multiTooltipTemplate: "<%=datasetLabel%>: <%= value %>"
+ multiTooltipTemplate: "<%=datasetLabel%>: <%= value %>",
+ maintainAspectRatio: false
}
});
diff --git a/public/assets/js/build.js b/public/assets/js/build.js
index f9c17b149..dcd585bdb 100644
--- a/public/assets/js/build.js
+++ b/public/assets/js/build.js
@@ -72,7 +72,7 @@ var Build = Class.extend({
var cb = function () {
var fullUri = window.APP_URL + uri;
- if (name == 'build-updated') {
+ if (name === 'build-updated') {
fullUri = window.APP_URL + 'build/ajax-data/' + self.buildId + '?per_page=' + PER_PAGE + '&page=' + PAGE + '&plugin=' + BUILD_PLUGIN + '&severity=' + BUILD_SEVERITY + '&is_new=' + BUILD_IS_NEW;
}
@@ -87,7 +87,7 @@ var Build = Class.extend({
});
};
- if (seconds != -1) {
+ if (REALTIME_UI && seconds !== -1) {
self.queries[name] = setInterval(cb, seconds * 1000);
}
diff --git a/public/assets/js/dashboard-widgets/all_projects.js b/public/assets/js/dashboard-widgets/all_projects.js
index 14af6bf6b..15f9ca01f 100644
--- a/public/assets/js/dashboard-widgets/all_projects.js
+++ b/public/assets/js/dashboard-widgets/all_projects.js
@@ -13,7 +13,9 @@ PHPCensor.widgets.allProjects = {
success: function (data) {
$(('#widget-all_projects-container')).html(data);
- PHPCensor.widgets.allProjects.interval = setInterval(PHPCensor.widgets.allProjects.update, 10000);
+ if (REALTIME_UI) {
+ PHPCensor.widgets.allProjects.interval = setInterval(PHPCensor.widgets.allProjects.update, 10000);
+ }
},
error: PHPCensor.handleFailedAjax
diff --git a/public/assets/js/dashboard-widgets/build_errors.js b/public/assets/js/dashboard-widgets/build_errors.js
index b4b070d06..7ba7f675f 100644
--- a/public/assets/js/dashboard-widgets/build_errors.js
+++ b/public/assets/js/dashboard-widgets/build_errors.js
@@ -13,7 +13,9 @@ PHPCensor.widgets.buildErrors = {
success: function (data) {
$(('#widget-build_errors-container')).html(data);
- PHPCensor.widgets.buildErrors.interval = setInterval(PHPCensor.widgets.buildErrors.update, 10000);
+ if (REALTIME_UI) {
+ PHPCensor.widgets.buildErrors.interval = setInterval(PHPCensor.widgets.buildErrors.update, 10000);
+ }
},
error: PHPCensor.handleFailedAjax
diff --git a/public/assets/js/dashboard-widgets/last_builds.js b/public/assets/js/dashboard-widgets/last_builds.js
index b064fb708..924a0f0f8 100644
--- a/public/assets/js/dashboard-widgets/last_builds.js
+++ b/public/assets/js/dashboard-widgets/last_builds.js
@@ -13,7 +13,9 @@ PHPCensor.widgets.lastBuilds = {
success: function (data) {
$(('#widget-last_builds-container')).html(data);
- PHPCensor.widgets.lastBuilds.interval = setInterval(PHPCensor.widgets.lastBuilds.update, 10000);
+ if (REALTIME_UI) {
+ PHPCensor.widgets.lastBuilds.interval = setInterval(PHPCensor.widgets.lastBuilds.update, 10000);
+ }
},
error: PHPCensor.handleFailedAjax
diff --git a/public/index.php b/public/index.php
index 753adf5e2..5e7564542 100644
--- a/public/index.php
+++ b/public/index.php
@@ -1,8 +1,19 @@
handleRequest();
+$request = Request::createFromGlobals();
+$application = new Application($configuration, $storeRegistry, $request, $session);
+
+$application->handleRequest()->send();
diff --git a/rector.php b/rector.php
new file mode 100644
index 000000000..a5d4ab021
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,23 @@
+paths([
+ __DIR__ . '/src'
+ ]);
+
+ // register a single rule
+ $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
+
+ $rectorConfig->sets([
+ SetList::PHP_74,
+ //SetList::CODE_QUALITY,
+ //SetList::TYPE_DECLARATION_STRICT,
+ //SetList::DEAD_CODE,
+ ]);
+};
diff --git a/src/Application.php b/src/Application.php
index 0d8772ae9..a02659c55 100644
--- a/src/Application.php
+++ b/src/Application.php
@@ -1,57 +1,56 @@
+ * @author Dmitry Khomutov
*/
class Application
{
- /**
- * @var array
- */
- protected $route;
+ private ?array $route;
- /**
- * @var Controller|WebController
- */
- protected $controller;
+ private Controller $controller;
- /**
- * @var Request
- */
- protected $request;
+ private Request $request;
- /**
- * @var Config
- */
- protected $config;
+ private Session $session;
- /**
- * @var Router
- */
- protected $router;
+ private ConfigurationInterface $configuration;
- public function __construct(Config $config, Request $request = null)
- {
- $this->config = $config;
+ private StoreRegistry $storeRegistry;
- if (!is_null($request)) {
- $this->request = $request;
- } else {
- $this->request = new Request();
- }
+ private Router $router;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ StoreRegistry $storeRegistry,
+ Request $request,
+ Session $session
+ ) {
+ $this->configuration = $configuration;
+ $this->storeRegistry = $storeRegistry;
+ $this->request = $request;
+ $this->session = $session;
- $this->router = new Router($this, $this->request, $this->config);
+ $this->router = new Router($this, $this->request);
$this->init();
}
@@ -59,16 +58,19 @@ public function __construct(Config $config, Request $request = null)
/**
* Initialise Application - Handles session verification, routing, etc.
*/
- public function init()
+ public function init(): void
{
$request = & $this->request;
$route = '/:controller/:action';
$opts = ['controller' => 'Home', 'action' => 'index'];
+ $session = $this->session;
+
// Inlined as a closure to fix "using $this when not in object context" on 5.3
- $validateSession = function () {
- if (!empty($_SESSION['php-censor-user-id'])) {
- $user = Factory::getStore('User')->getByPrimaryKey($_SESSION['php-censor-user-id']);
+ $validateSession = function () use ($session) {
+ $sessionUserId = $session->get('php-censor-user-id');
+ if (!empty($sessionUserId)) {
+ $user = $this->storeRegistry->get('User')->getById((int)$sessionUserId);
if ($user) {
return true;
@@ -81,17 +83,17 @@ public function init()
$skipAuth = [$this, 'shouldSkipAuth'];
// Handler for the route we're about to register, checks for a valid session where necessary:
- $routeHandler = function (&$route, Response &$response) use (&$request, $validateSession, $skipAuth) {
- $skipValidation = in_array($route['controller'], ['session', 'webhook', 'build-status'], true);
+ $routeHandler = function ($route, Response &$response) use (&$request, $validateSession, $skipAuth, $session) {
+ $skipValidation = \in_array($route['controller'], ['session', 'webhook', 'build-status'], true);
- if (!$skipValidation && !$validateSession() && (!is_callable($skipAuth) || !$skipAuth())) {
- if ($request->isAjax()) {
- $response->setResponseCode(401);
- $response->setContent('');
+ if (!$skipValidation && !$validateSession() && (!\is_callable($skipAuth) || !$skipAuth())) {
+ if ($request->isXmlHttpRequest()) {
+ $response->setStatusCode(Response::HTTP_UNAUTHORIZED);
+ $response->setContent(null);
} else {
- $_SESSION['php-censor-login-redirect'] = substr($request->getPath(), 1);
- $response = new RedirectResponse($response);
- $response->setHeader('Location', APP_URL . 'session/login');
+ $session->set('php-censor-login-redirect', \substr($request->getPathInfo(), 1));
+
+ $response = new RedirectResponse(APP_URL . 'session/login');
}
return false;
@@ -105,11 +107,9 @@ public function init()
}
/**
- * @return Response
- *
* @throws NotFoundException
*/
- protected function handleRequestInner()
+ protected function handleRequestInner(): Response
{
$this->route = $this->router->dispatch();
@@ -123,45 +123,64 @@ protected function handleRequestInner()
}
if (!$this->controllerExists($this->route)) {
- throw new NotFoundException('Controller ' . $this->toPhpName($this->route['controller']) . ' does not exist!');
+ throw new NotFoundException(
+ 'Controller ' . $this->toPhpName($this->route['controller']) . ' does not exist!'
+ );
}
- $action = lcfirst($this->toPhpName($this->route['action']));
+ $action = \lcfirst($this->toPhpName($this->route['action']));
if (!$this->getController()->hasAction($action)) {
- throw new NotFoundException('Controller ' . $this->toPhpName($this->route['controller']) . ' does not have action ' . $action . '!');
+ throw new NotFoundException(
+ 'Controller ' . $this->toPhpName($this->route['controller']) . ' does not have action ' . $action . '!'
+ );
}
return $this->getController()->handleAction($action, $this->route['args']);
}
+ /**
+ * @throws Common\Exception\RuntimeException
+ * @throws HttpException
+ */
+ private function getUser(): ?User
+ {
+ $sessionUserId = $this->session->get('php-censor-user-id');
+ if (empty($sessionUserId)) {
+ return null;
+ }
+
+ /** @var UserStore $userStore */
+ $userStore = $this->storeRegistry->get('User');
+
+ return $userStore->getById((int)$sessionUserId);
+ }
+
/**
* Handle an incoming web request.
*
- * @return Response
+ * @throws Common\Exception\RuntimeException
+ * @throws HttpException
*/
- public function handleRequest()
+ public function handleRequest(): Response
{
try {
$response = $this->handleRequestInner();
} catch (HttpException $ex) {
- $this->config->set('page_title', 'Error');
-
$view = new View('exception');
$view->exception = $ex;
+ $view->user = $this->getUser();
$response = new Response();
- $response->setResponseCode($ex->getErrorCode());
+ $response->setStatusCode($ex->getErrorCode());
$response->setContent($view->render());
- } catch (Exception $ex) {
- $this->config->set('page_title', 'Error');
-
+ } catch (\Throwable $ex) {
$view = new View('exception');
$view->exception = $ex;
$response = new Response();
- $response->setResponseCode(500);
+ $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
$response->setContent($view->render());
}
@@ -170,15 +189,11 @@ public function handleRequest()
/**
* Loads a particular controller, and injects our layout view into it.
- *
- * @param string $class
- *
- * @return Controller
*/
- protected function loadController($class)
+ protected function loadController(string $class): Controller
{
/** @var Controller $controller */
- $controller = new $class($this->config, $this->request);
+ $controller = new $class($this->configuration, $this->storeRegistry, $this->request, $this->session);
$controller->init();
@@ -188,16 +203,15 @@ protected function loadController($class)
/**
* Check whether we should skip auth (because it is disabled)
*
- * @return bool
+ * @throws Common\Exception\RuntimeException
*/
- protected function shouldSkipAuth()
+ protected function shouldSkipAuth(): bool
{
- $config = Config::getInstance();
- $disableAuth = (bool)$config->get('php-censor.security.disable_auth', false);
- $defaultUserId = (int)$config->get('php-censor.security.default_user_id', 1);
+ $disableAuth = (bool)$this->configuration->get('php-censor.security.disable_auth', false);
+ $defaultUserId = (int)$this->configuration->get('php-censor.security.default_user_id', 1);
if ($disableAuth && $defaultUserId) {
- $user = Factory::getStore('User')->getByPrimaryKey($defaultUserId);
+ $user = $this->storeRegistry->get('User')->getById($defaultUserId);
if ($user) {
return true;
@@ -207,10 +221,7 @@ protected function shouldSkipAuth()
return false;
}
- /**
- * @return Controller
- */
- public function getController()
+ public function getController(): Controller
{
if (empty($this->controller)) {
$controllerClass = $this->getControllerClass($this->route);
@@ -220,33 +231,19 @@ public function getController()
return $this->controller;
}
- /**
- * @param array $route
- *
- * @return bool
- */
- protected function controllerExists($route)
+ protected function controllerExists(array $route): bool
{
- return class_exists($this->getControllerClass($route));
+ return \class_exists($this->getControllerClass($route));
}
- /**
- * @param array $route
- *
- * @return string
- */
- protected function getControllerClass($route)
+ protected function getControllerClass(array $route): string
{
- $namespace = $this->toPhpName($route['namespace']);
$controller = $this->toPhpName($route['controller']);
- return 'PHPCensor\\' . $namespace . '\\' . $controller . 'Controller';
+ return 'PHPCensor\Controller\\' . $controller . 'Controller';
}
- /**
- * @return bool
- */
- public function isValidRoute(array $route)
+ public function isValidRoute(array $route): bool
{
if ($this->controllerExists($route)) {
return true;
@@ -255,17 +252,11 @@ public function isValidRoute(array $route)
return false;
}
- /**
- * @param string $string
- *
- * @return string
- */
- protected function toPhpName($string)
+ protected function toPhpName(string $string): string
{
- $string = str_replace('-', ' ', $string);
- $string = ucwords($string);
- $string = str_replace(' ', '', $string);
+ $string = \str_replace('-', ' ', $string);
+ $string = \ucwords($string);
- return $string;
+ return \str_replace(' ', '', $string);
}
}
diff --git a/src/ArrayConfiguration.php b/src/ArrayConfiguration.php
new file mode 100644
index 000000000..78b77d223
--- /dev/null
+++ b/src/ArrayConfiguration.php
@@ -0,0 +1,22 @@
+
+ */
+class ArrayConfiguration extends ParameterBag implements ConfigurationInterface
+{
+ public function load(): void
+ {
+ return;
+ }
+}
diff --git a/src/BuildFactory.php b/src/BuildFactory.php
index cce0531ae..c79bcdd57 100644
--- a/src/BuildFactory.php
+++ b/src/BuildFactory.php
@@ -1,87 +1,108 @@
+ * @author Dmitry Khomutov
*/
class BuildFactory
{
+ private ConfigurationInterface $configuration;
+
+ private StoreRegistry $storeRegistry;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ StoreRegistry $storeRegistry
+ ) {
+ $this->configuration = $configuration;
+ $this->storeRegistry = $storeRegistry;
+ }
+
/**
- * @param int $buildId
- *
- * @return Build|null
- *
+ * @throws Common\Exception\RuntimeException
* @throws Exception\HttpException
*/
- public static function getBuildById($buildId)
+ public function getBuildById(int $buildId): ?Build
{
- $build = Factory::getStore('Build')->getById($buildId);
+ /** @var Build $build */
+ $build = $this->storeRegistry->get('Build')->getById($buildId);
- if (empty($build)) {
+ if (!$build) {
return null;
}
- return self::getBuild($build);
+ return $this->getBuild($build);
}
/**
* Takes a generic build and returns a type-specific build model.
*
- * @param Build $build The build from which to get a more specific build type.
- *
- * @return Build
- *
* @throws Exception\HttpException
*/
- public static function getBuild(Build $build)
+ public function getBuild(Build $build): Build
{
$project = $build->getProject();
-
if (!empty($project)) {
switch ($project->getType()) {
case Project::TYPE_LOCAL:
$type = 'LocalBuild';
+
break;
case Project::TYPE_GIT:
$type = 'GitBuild';
+
break;
case Project::TYPE_GITHUB:
$type = 'GithubBuild';
+
break;
case Project::TYPE_BITBUCKET:
$type = 'BitbucketBuild';
+
break;
case Project::TYPE_GITLAB:
$type = 'GitlabBuild';
+
break;
case Project::TYPE_GOGS:
$type = 'GogsBuild';
+
break;
case Project::TYPE_HG:
$type = 'HgBuild';
+
break;
case Project::TYPE_BITBUCKET_HG:
$type = 'BitbucketHgBuild';
+
break;
case Project::TYPE_BITBUCKET_SERVER:
$type = 'BitbucketServerBuild';
+
break;
case Project::TYPE_SVN:
$type = 'SvnBuild';
+
break;
default:
return $build;
}
$class = '\\PHPCensor\\Model\\Build\\' . $type;
- $build = new $class($build->getDataArray());
+ $build = new $class($this->configuration, $this->storeRegistry, $build->getDataArray());
}
return $build;
diff --git a/src/Builder.php b/src/Builder.php
index d0f5ddcc5..075b78095 100644
--- a/src/Builder.php
+++ b/src/Builder.php
@@ -1,158 +1,145 @@
+ * @author Dmitry Khomutov
*/
-class Builder implements LoggerAwareInterface
+class Builder
{
- /**
- * @var string
- */
- public $buildPath;
+ public string $buildPath = '';
/**
* @var string[]
*/
- public $ignore = [];
+ public array $ignore = [];
- /**
- * @var string[]
- */
- public $binaryPath = '';
+ public string $binaryPath = '';
- /**
- * @var string[]
- */
- public $priorityPath = 'local';
+ public string $priorityPath = 'local';
- /**
- * @var string
- */
- public $directory;
+ public string $directory = '';
- /**
- * @var string|null
- */
- protected $currentStage = null;
+ protected ?string $currentStage = null;
- /**
- * @var bool
- */
- protected $verbose = true;
+ protected bool $verbose = true;
- /**
- * @var Build
- */
- protected $build;
+ protected Build $build;
- /**
- * @var LoggerInterface
- */
- protected $logger;
+ protected LoggerInterface $logger;
- /**
- * @var array
- */
- protected $config = [];
+ protected array $config = [];
- /**
- * @var string
- */
- protected $lastOutput;
+ protected BuildInterpolator $interpolator;
- /**
- * @var BuildInterpolator
- */
- protected $interpolator;
+ protected BuildStore $store;
- /**
- * @var BuildStore
- */
- protected $store;
+ protected Executor $pluginExecutor;
- /**
- * @var Executor
- */
- protected $pluginExecutor;
+ protected CommandExecutorInterface $commandExecutor;
- /**
- * @var Helper\CommandExecutorInterface
- */
- protected $commandExecutor;
+ protected BuildLogger $buildLogger;
- /**
- * @var Logging\BuildLogger
- */
- protected $buildLogger;
+ protected BuildErrorWriter $buildErrorWriter;
- /**
- * @var BuildErrorWriter
- */
- private $buildErrorWriter;
+ protected ConfigurationInterface $configuration;
+
+ protected DatabaseManager $databaseManager;
+
+ protected StoreRegistry $storeRegistry;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ Build $build,
+ BuildLogger $buildLogger
+ ) {
+ $this->configuration = $configuration;
+ $this->databaseManager = $databaseManager;
+ $this->storeRegistry = $storeRegistry;
+ $this->buildLogger = $buildLogger;
- /**
- * Set up the builder.
- *
- */
- public function __construct(Build $build, LoggerInterface $logger = null)
- {
$this->build = $build;
- $this->store = Factory::getStore('Build');
- $this->buildLogger = new BuildLogger($logger, $build);
- $pluginFactory = $this->buildPluginFactory($build);
- $this->pluginExecutor = new Plugin\Util\Executor($pluginFactory, $this->buildLogger);
+ /** @var BuildStore $buildStore */
+ $buildStore = $this->storeRegistry->get('Build');
+ /** @var SecretStore $secretStore */
+ $secretStore = $this->storeRegistry->get('Secret');
+ /** @var EnvironmentStore $environmentStore */
+ $environmentStore = $this->storeRegistry->get('Environment');
- $executorClass = 'PHPCensor\Helper\CommandExecutor';
+ $this->store = $buildStore;
+
+ $pluginFactory = new PluginFactory($this, $build);
+
+ $this->pluginExecutor = new Plugin\Util\Executor(
+ $this->storeRegistry,
+ $pluginFactory,
+ $this->buildLogger,
+ $buildStore
+ );
+
+ $executorClass = CommandExecutor::class;
$this->commandExecutor = new $executorClass(
$this->buildLogger,
ROOT_DIR,
$this->verbose
);
- $this->interpolator = new BuildInterpolator();
- $this->buildErrorWriter = new BuildErrorWriter($this->build->getProjectId(), $this->build->getId());
+ $this->interpolator = new BuildInterpolator($environmentStore, $secretStore);
+ $this->buildErrorWriter = new BuildErrorWriter(
+ $this->configuration,
+ $this->databaseManager,
+ $this->storeRegistry,
+ $this->build->getProjectId(),
+ $this->build->getId()
+ );
}
- /**
- * @return BuildLogger
- */
- public function getBuildLogger()
+ public function getBuildLogger(): BuildLogger
{
return $this->buildLogger;
}
- /**
- * @return string|null
- */
- public function getCurrentStage()
+ public function getConfiguration(): ConfigurationInterface
+ {
+ return $this->configuration;
+ }
+
+ public function getCurrentStage(): ?string
{
return $this->currentStage;
}
/**
* Set the config array, as read from .php-censor.yml
- *
- * @throws Exception
*/
- public function setConfig(array $config)
+ public function setConfig(array $config): void
{
$this->config = $config;
}
@@ -160,11 +147,9 @@ public function setConfig(array $config)
/**
* Access a variable from the .php-censor.yml file.
*
- * @param string $key
- *
* @return mixed
*/
- public function getConfig($key = null)
+ public function getConfig(?string $key = null)
{
$value = null;
if (null === $key) {
@@ -176,33 +161,7 @@ public function getConfig($key = null)
return $value;
}
- /**
- * Access a variable from the config.yml
- *
- * @param string $key
- *
- * @return mixed
- */
- public function getSystemConfig($key)
- {
- return Config::getInstance()->get($key);
- }
-
- /**
- * @return string The title of the project being built.
- *
- * @throws Exception\HttpException
- */
- public function getBuildProjectTitle()
- {
- return $this->build->getProject()->getTitle();
- }
-
- /**
- * @throws Exception\HttpException
- * @throws Exception\InvalidArgumentException
- */
- public function execute()
+ public function execute(): void
{
$this->build->setStatusRunning();
$this->build->setStartDate(new DateTime());
@@ -212,10 +171,10 @@ public function execute()
$success = true;
$previousBuild = $this->build->getProject()->getPreviousBuild($this->build->getBranch());
- $previousState = Build::STATUS_PENDING;
+ $previousBuildStatus = Build::STATUS_PENDING;
if ($previousBuild) {
- $previousState = $previousBuild->getStatus();
+ $previousBuildStatus = $previousBuild->getStatus();
}
try {
@@ -238,7 +197,7 @@ public function execute()
} else {
$this->build->setStatusFailed();
}
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$success = false;
$this->build->setStatusFailed();
$this->buildLogger->logFailure('Exception: ' . $ex->getMessage(), $ex);
@@ -249,7 +208,7 @@ public function execute()
$this->currentStage = Build::STAGE_SUCCESS;
$this->pluginExecutor->executePlugins($this->config, Build::STAGE_SUCCESS);
- if (Build::STATUS_FAILED === $previousState) {
+ if (Build::STATUS_FAILED === $previousBuildStatus) {
$this->currentStage = Build::STAGE_FIXED;
$this->pluginExecutor->executePlugins($this->config, Build::STAGE_FIXED);
}
@@ -257,12 +216,12 @@ public function execute()
$this->currentStage = Build::STAGE_FAILURE;
$this->pluginExecutor->executePlugins($this->config, Build::STAGE_FAILURE);
- if (Build::STATUS_SUCCESS === $previousState || Build::STATUS_PENDING === $previousState) {
+ if (Build::STATUS_SUCCESS === $previousBuildStatus || Build::STATUS_PENDING === $previousBuildStatus) {
$this->currentStage = Build::STAGE_BROKEN;
$this->pluginExecutor->executePlugins($this->config, Build::STAGE_BROKEN);
}
}
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$this->buildLogger->logFailure('Exception: ' . $ex->getMessage(), $ex);
}
@@ -280,7 +239,7 @@ public function execute()
// Complete stage plugins are always run
$this->currentStage = Build::STAGE_COMPLETE;
$this->pluginExecutor->executePlugins($this->config, Build::STAGE_COMPLETE);
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$this->buildLogger->logFailure('Exception: ' . $ex->getMessage());
}
@@ -288,7 +247,7 @@ public function execute()
$this->build->sendStatusPostback();
$this->build->setFinishDate(new DateTime());
- $removeBuilds = (bool)Config::getInstance()->get('php-censor.build.remove_builds', true);
+ $removeBuilds = (bool)$this->configuration->get('php-censor.build.remove_builds', true);
if ($removeBuilds) {
// Clean up:
$this->buildLogger->log('');
@@ -299,15 +258,12 @@ public function execute()
$this->buildErrorWriter->flush();
$this->setErrorTrend();
+ $this->setTestCoverageTrend();
$this->store->save($this->build);
}
- /**
- * @throws Exception\HttpException
- * @throws Exception\InvalidArgumentException
- */
- protected function setErrorTrend()
+ protected function setErrorTrend(): void
{
$this->build->setErrorsTotal($this->store->getErrorsCount($this->build->getId()));
@@ -317,15 +273,25 @@ protected function setErrorTrend()
$this->build->getBranch()
);
- if (isset($trend[1])) {
- $previousBuild = $this->store->getById($trend[1]['build_id']);
- if ($previousBuild &&
- !in_array(
- $previousBuild->getStatus(),
- [Build::STATUS_PENDING, Build::STATUS_RUNNING],
- true
- )) {
- $this->build->setErrorsTotalPrevious((int)$trend[1]['count']);
+ if (isset($trend[0])) {
+ $this->build->setErrorsTotalPrevious((int)$trend[0]['count']);
+ }
+ }
+
+ protected function setTestCoverageTrend(): void
+ {
+ $this->build->setTestCoverage($this->store->getTestCoverage($this->build->getId()));
+
+ $trend = $this->store->getBuildTestCoverageTrend(
+ $this->build->getId(),
+ $this->build->getProjectId(),
+ $this->build->getBranch()
+ );
+
+ if (!empty($trend[0]) && !empty($trend[0]['coverage'])) {
+ $coverage = \json_decode($trend[0]['coverage'], true);
+ if (isset($coverage['lines'])) {
+ $this->build->setTestCoveragePrevious($coverage['lines']);
}
}
}
@@ -333,31 +299,25 @@ protected function setErrorTrend()
/**
* Used by this class, and plugins, to execute shell commands.
*
- * @param string ...$params
- *
- * @return bool
+ * @param ...$params
*/
- public function executeCommand(...$params)
+ public function executeCommand(...$params): bool
{
return $this->commandExecutor->executeCommand($params);
}
/**
* Returns the output from the last command run.
- *
- * @return string
*/
- public function getLastOutput()
+ public function getLastOutput(): string
{
return $this->commandExecutor->getLastOutput();
}
/**
* Specify whether exec output should be logged.
- *
- * @param bool $enableLog
*/
- public function logExecOutput($enableLog = true)
+ public function logExecOutput(bool $enableLog = true): void
{
$this->commandExecutor->logExecOutput = $enableLog;
}
@@ -366,41 +326,35 @@ public function logExecOutput($enableLog = true)
* Find a binary required by a plugin.
*
* @param array|string $binary
- * @param string $priorityPath
- * @param string $binaryPath
- * @param array $binaryName
- * @return string
*
* @throws Exception when no binary has been found.
*/
- public function findBinary($binary, $priorityPath = 'local', $binaryPath = '', $binaryName = [])
- {
+ public function findBinary(
+ $binary,
+ string $priorityPath = 'local',
+ string $binaryPath = '',
+ array $binaryName = []
+ ): string {
return $this->commandExecutor->findBinary($binary, $priorityPath, $binaryPath, $binaryName);
}
/**
* Replace every occurrence of the interpolation vars in the given string
* Example: "This is build %BUILD_ID%" => "This is build 182"
- *
- * @param string $input
- *
- * @return string
*/
- public function interpolate($input)
+ public function interpolate(string $input, bool $useSecrets = false): string
{
- return $this->interpolator->interpolate($input);
+ return $this->interpolator->interpolate($input, $useSecrets);
}
/**
* Set up a working copy of the project for building.
*
* @throws Exception
- *
- * @return bool
*/
- protected function setupBuild()
+ protected function setupBuild(): bool
{
- $this->buildPath = $this->build->getBuildPath();
+ $this->buildPath = (string)$this->build->getBuildPath();
$this->commandExecutor->setBuildPath($this->buildPath);
@@ -434,14 +388,14 @@ protected function setupBuild()
}
if (!empty($this->config['build_settings']['binary_path'])) {
- $this->binaryPath = rtrim(
- $this->interpolate($this->config['build_settings']['binary_path']),
+ $this->binaryPath = \rtrim(
+ $this->interpolate($this->config['build_settings']['binary_path'], true),
'/\\'
) . '/';
}
if (!empty($this->config['build_settings']['priority_path']) &&
- in_array(
+ \in_array(
$this->config['build_settings']['priority_path'],
Plugin::AVAILABLE_PRIORITY_PATHS,
true
@@ -456,133 +410,46 @@ protected function setupBuild()
$directory = $this->config['build_settings']['directory'];
}
- $this->directory = rtrim(
- $this->interpolate($directory),
+ $this->directory = \rtrim(
+ $this->interpolate($directory, true),
'/\\'
) . '/';
- $this->buildLogger->logSuccess(sprintf('Working copy created: %s', $this->buildPath));
+ $this->buildLogger->logSuccess(\sprintf('Working copy created: %s', $this->buildPath));
if (!$workingCopySuccess) {
- throw new Exception('Could not create a working copy.');
+ throw new RuntimeException('Could not create a working copy.');
}
return true;
}
- /**
- * Sets a logger instance on the object
- */
- public function setLogger(LoggerInterface $logger)
- {
- $this->buildLogger->setLogger($logger);
- }
-
- /**
- * Write to the build log.
- *
- * @param string $message
- * @param string $level
- * @param array $context
- */
- public function log($message, $level = LogLevel::INFO, $context = [])
+ public function log(string $message, string $level = LogLevel::INFO, array $context = []): void
{
$this->buildLogger->log($message, $level, $context);
}
- /**
- * Add a warning-coloured message to the log.
- *
- * @param string $message
- */
- public function logWarning($message)
+ public function logWarning(string $message): void
{
$this->buildLogger->logWarning($message);
}
- /**
- * Add a success-coloured message to the log.
- *
- * @param string $message
- */
- public function logSuccess($message)
+ public function logSuccess(string $message): void
{
$this->buildLogger->logSuccess($message);
}
- /**
- * Add a failure-coloured message to the log.
- *
- * @param string $message
- * @param Exception $exception The exception that caused the error.
- */
- public function logFailure($message, Exception $exception = null)
+ public function logFailure(string $message, ?\Throwable $exception = null): void
{
$this->buildLogger->logFailure($message, $exception);
}
- /**
- * Add a debug-coloured message to the log.
- *
- * @param string $message
- */
- public function logDebug($message)
+ public function logDebug(string $message): void
{
$this->buildLogger->logDebug($message);
}
- /**
- * Returns a configured instance of the plugin factory.
- *
- * @return PluginFactory
- */
- private function buildPluginFactory(Build $build)
- {
- $pluginFactory = new PluginFactory();
-
- $self = $this;
- $pluginFactory->registerResource(
- function () use ($self) {
- return $self;
- },
- null,
- 'PHPCensor\Builder'
- );
-
- $pluginFactory->registerResource(
- function () use ($build) {
- return $build;
- },
- null,
- 'PHPCensor\Model\Build'
- );
-
- $logger = $this->logger;
- $pluginFactory->registerResource(
- function () use ($logger) {
- return $logger;
- },
- null,
- 'Psr\Log\LoggerInterface'
- );
-
- $pluginFactory->registerResource(
- function () use ($self) {
- $factory = new MailerFactory($self->getSystemConfig('php-censor'));
-
- return $factory->getSwiftMailerFromConfig();
- },
- null,
- 'Swift_Mailer'
- );
-
- return $pluginFactory;
- }
-
- /**
- * @return BuildErrorWriter
- */
- public function getBuildErrorWriter()
+ public function getBuildErrorWriter(): BuildErrorWriter
{
return $this->buildErrorWriter;
}
diff --git a/src/Command/Action/CreateAdmin.php b/src/Command/Action/CreateAdmin.php
new file mode 100644
index 000000000..73ad63b47
--- /dev/null
+++ b/src/Command/Action/CreateAdmin.php
@@ -0,0 +1,118 @@
+
+ */
+class CreateAdmin
+{
+ private QuestionHelper $questionHelper;
+
+ private InputInterface $input;
+
+ private OutputInterface $output;
+
+ private StoreRegistry $storeRegistry;
+
+ private UserStore $userStore;
+
+ public function __construct(
+ QuestionHelper $questionHelper,
+ InputInterface $input,
+ OutputInterface $output,
+ StoreRegistry $storeRegistry,
+ UserStore $userStore
+ ) {
+ $this->questionHelper = $questionHelper;
+ $this->input = $input;
+ $this->output = $output;
+ $this->userStore = $userStore;
+ $this->storeRegistry = $storeRegistry;
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ public function process(): array
+ {
+ $result = [];
+ $mailValidator = function ($answer) {
+ if (!\filter_var($answer, FILTER_VALIDATE_EMAIL)) {
+ throw new InvalidArgumentException('Must be a valid email address.');
+ }
+
+ return $answer;
+ };
+
+ if ($adminEmail = $this->input->getOption('admin-email')) {
+ $adminEmail = $mailValidator($adminEmail);
+ } else {
+ $questionEmail = new Question('Admin email: ');
+ $adminEmail = $this->questionHelper->ask($this->input, $this->output, $questionEmail);
+ }
+
+ if (!$adminName = $this->input->getOption('admin-name')) {
+ $questionName = new Question('Admin name: ');
+ $adminName = $this->questionHelper->ask($this->input, $this->output, $questionName);
+ }
+
+ if (!$adminPassword = $this->input->getOption('admin-password')) {
+ $questionPassword = new Question('Admin password: ');
+ $questionPassword->setHidden(true);
+ $questionPassword->setHiddenFallback(false);
+ $adminPassword = $this->questionHelper->ask($this->input, $this->output, $questionPassword);
+ }
+
+ $result['email'] = $adminEmail;
+ $result['name'] = $adminName;
+ $result['password'] = $adminPassword;
+
+ return $result;
+ }
+
+ public function create(array $adminDetails): bool
+ {
+ try {
+ $adminUser = $this->userStore->getByEmail($adminDetails['email']);
+ if ($adminUser) {
+ throw new RuntimeException('Admin account already exists!');
+ }
+
+ $userService = new UserService($this->storeRegistry, $this->userStore);
+
+ $userService->createUser(
+ $adminDetails['name'],
+ $adminDetails['email'],
+ 'internal',
+ ['type' => 'internal'],
+ $adminDetails['password'],
+ true
+ );
+
+ $this->output->writeln('User account created!');
+ } catch (\Throwable $ex) {
+ $this->output->writeln('PHP Censor failed to create your admin account!');
+ $this->output->writeln('' . $ex->getMessage() . '');
+
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/Command/AddSecretCommand.php b/src/Command/AddSecretCommand.php
new file mode 100644
index 000000000..754b3fa7c
--- /dev/null
+++ b/src/Command/AddSecretCommand.php
@@ -0,0 +1,95 @@
+
+ */
+class AddSecretCommand extends Command
+{
+ private SecretStore $secretStore;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ LoggerInterface $logger,
+ SecretStore $secretStore,
+ ?string $name = null
+ ) {
+ parent::__construct($configuration, $databaseManager, $storeRegistry, $logger, $name);
+
+ $this->secretStore = $secretStore;
+ }
+
+ /**
+ * Configure.
+ */
+ protected function configure(): void
+ {
+ $this
+ ->setName('php-censor:add-secret')
+
+ ->addArgument('secret-name', InputArgument::REQUIRED, 'Secret name')
+ ->addArgument('secret-value', InputArgument::REQUIRED, 'Secret value')
+
+ ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to update existing values')
+
+ ->setDescription('Update secret');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $secretName = (string)$input->getArgument('secret-name');
+ $secretValue = (string)$input->getArgument('secret-value');
+ $force = (bool)$input->getOption('force');
+
+ $secrets = $this->secretStore->getByNames([$secretName]);
+ if ($secrets && !$force) {
+ $output->writeln(
+ \sprintf('Secret with name "%s" already exists! Use flag "-f|--force" if you want update secret.', $secretName)
+ );
+
+ return 1;
+ }
+
+ if (!\preg_match(\sprintf('#%s#', Secret::SECRET_NAME_PATTERN), $secretName)) {
+ $output->writeln(
+ \sprintf('Secret name "%s" is invalid! Use only letters, numbers and "-" or "_".', $secretName)
+ );
+
+ return 2;
+ }
+
+ $secret = new Secret($this->storeRegistry);
+ $secret->setCreateDate(new \DateTime());
+ $secret->setUserId(null);
+ $secret->setName($secretName);
+
+ if ($secrets && $force) {
+ $secret = $secrets[$secretName];
+ }
+
+ $secret->setValue($secretValue);
+
+ $this->secretStore->save($secret);
+
+ return 0;
+ }
+}
diff --git a/src/Command/CheckLocalizationCommand.php b/src/Command/CheckLocalizationCommand.php
deleted file mode 100644
index 4b5dffef2..000000000
--- a/src/Command/CheckLocalizationCommand.php
+++ /dev/null
@@ -1,165 +0,0 @@
-basePath = __DIR__.'/../Languages';
- }
-
- /**
- * Configure.
- */
- protected function configure()
- {
- $this
- ->setName('php-censor:check-localizations')
- ->addOption(
- 'same',
- 0,
- InputOption::VALUE_OPTIONAL,
- 'Same than English version (0 = no, 1 = yes)'
- )
- ->addOption(
- 'langs',
- [],
- InputOption::VALUE_OPTIONAL,
- 'List of languages separated by commas. By default, all languages'
- )
- ->setDescription('Check localizations.');
- }
-
- /**
- * Loops through running.
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $output->writeln("\nCheck localizations!");
-
- $sameThanEnglish = (null !== $input->getOption('same'))
- ? $input->getOption('same')
- : false;
-
- $languagesList = (null !== $input->getOption('langs'))
- ? explode(',', $input->getOption('langs'))
- : [];
-
- // Get English version
- $english = $this->getTranslations($this->basePath.'/lang.en.php');
- $othersLanguages = $this->getLanguages($languagesList);
- $diffs = $this->compareTranslations($english, $othersLanguages);
-
- foreach ($diffs as $language => $value) {
- $output->writeln(sprintf("%s:", $language));
- if (!empty($value['not_present'])) {
- $output->writeln("\tNot present:\n\t\t" . implode("\n\t\t", $value['not_present']));
- }
-
- if ($sameThanEnglish === '1' && !empty($value['same'])) {
- $output->writeln("\tSame than English:\n\t\t" . implode("\n\t\t", $value['same']));
- }
- }
- }
-
- /**
- * Returns array of translations by language.
- *
- * @param string $language language code
- *
- * @return array
- */
- private function getTranslations($language)
- {
- return [
- include($language)
- ];
- }
-
- /**
- * Returns list of languages.
- *
- * @return array
- */
- private function getLanguages(array $languagesList = [])
- {
- $files = glob($this->basePath . '/*.php');
-
- $languages = array_map(function ($dir) use ($languagesList) {
- $name = basename($dir);
-
- if (in_array($name, $this->excluded, true)) {
- return null;
- }
-
- // Check if in list of languages.
- if (!empty($languagesList)) {
- $languageOfName = explode('.', $name);
-
- if (null == $languageOfName[1] || !in_array($languageOfName[1], $languagesList, true)) {
- return null;
- }
- }
-
- return $name;
- }, $files);
-
- return array_filter($languages);
- }
-
- /**
- * Compare translations.
- *
- * @param array $default language by default
- * @param array $languages others languages
- *
- * @return array
- */
- private function compareTranslations(array $default, array $languages)
- {
- $diffs = [];
-
- // Return diff language by language
- foreach ($languages as $language) {
- $current = $this->getTranslations($this->basePath.'/'.$language);
-
- foreach ($default as $key => $values) {
- $keyValues = array_keys($values);
-
- foreach ($keyValues as $key2) {
- if (!isset($current[$key][$key2])) {
- $diffs[$language]['not_present'][] = $key2;
- } elseif ($current[$key][$key2] === $default[$key][$key2]) {
- $diffs[$language]['same'][] = $key2;
- }
- }
- }
- }
-
- return $diffs;
- }
-}
diff --git a/src/Command/CheckLocalizationsCommand.php b/src/Command/CheckLocalizationsCommand.php
new file mode 100644
index 000000000..e655fa2e3
--- /dev/null
+++ b/src/Command/CheckLocalizationsCommand.php
@@ -0,0 +1,125 @@
+
+ */
+class CheckLocalizationsCommand extends Command
+{
+ protected string $basePath = __DIR__ . '/../Languages';
+
+ protected array $excluded = ['lang.en.php'];
+
+ protected function configure(): void
+ {
+ $this
+ ->setName('php-censor:check-localizations')
+
+ ->addOption('same', 's', InputOption::VALUE_NONE, 'Same than English version')
+ ->addOption('languages', 'l', InputOption::VALUE_OPTIONAL, 'List of languages separated by commas. By default, all languages', '')
+
+ ->setDescription('Check localizations');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $output->writeln("\nCheck localizations!");
+
+ $sameThanEnglish = (bool)$input->getOption('same');
+
+ $languages = $input->getOption('languages')
+ ? \explode(',', $input->getOption('languages'))
+ : [];
+
+ // Get English version
+ $english = $this->getTranslations($this->basePath . '/lang.en.php');
+ $othersLanguages = $this->getLanguages($languages);
+ $diffs = $this->compareTranslations($english, $othersLanguages);
+
+ foreach ($diffs as $language => $value) {
+ $output->writeln(\sprintf("%s:", $language));
+ if (!empty($value['not_present'])) {
+ $output->writeln("\tNot present:\n\t\t" . \implode("\n\t\t", $value['not_present']));
+ }
+
+ if ($sameThanEnglish === '1' && !empty($value['same'])) {
+ $output->writeln("\tSame than English:\n\t\t" . \implode("\n\t\t", $value['same']));
+ }
+ }
+
+ return 0;
+ }
+
+ private function getTranslations(string $language): array
+ {
+ return [
+ include $language,
+ ];
+ }
+
+ private function getLanguages(array $languagesList = []): array
+ {
+ $files = \glob($this->basePath . '/*.php');
+
+ $languages = \array_map(function ($dir) use ($languagesList) {
+ $name = \basename($dir);
+
+ if (\in_array($name, $this->excluded, true)) {
+ return null;
+ }
+
+ // Check if in list of languages.
+ if (!empty($languagesList)) {
+ $languageOfName = \explode('.', $name);
+
+ if (null === $languageOfName[1] || !\in_array($languageOfName[1], $languagesList, true)) {
+ return null;
+ }
+ }
+
+ return $name;
+ }, $files);
+
+ return \array_filter($languages);
+ }
+
+ /**
+ * Compare translations.
+ *
+ * @param array $default Language by default
+ * @param array $languages Others languages
+ */
+ private function compareTranslations(array $default, array $languages): array
+ {
+ $diffs = [];
+
+ // Return diff language by language
+ foreach ($languages as $language) {
+ $current = $this->getTranslations($this->basePath.'/'.$language);
+
+ foreach ($default as $key => $values) {
+ $keyValues = \array_keys($values);
+
+ foreach ($keyValues as $key2) {
+ if (!isset($current[$key][$key2])) {
+ $diffs[$language]['not_present'][] = $key2;
+ } elseif ($current[$key][$key2] === $default[$key][$key2]) {
+ $diffs[$language]['same'][] = $key2;
+ }
+ }
+ }
+ }
+
+ return $diffs;
+ }
+}
diff --git a/src/Command/Command.php b/src/Command/Command.php
new file mode 100644
index 000000000..a45558853
--- /dev/null
+++ b/src/Command/Command.php
@@ -0,0 +1,93 @@
+
+ */
+abstract class Command extends BaseCommand
+{
+ protected ConfigurationInterface $configuration;
+
+ protected DatabaseManager $databaseManager;
+
+ protected StoreRegistry $storeRegistry;
+
+ protected LoggerInterface $logger;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ LoggerInterface $logger,
+ ?string $name = null
+ ) {
+ parent::__construct($name);
+
+ $this->configuration = $configuration;
+ $this->databaseManager = $databaseManager;
+ $this->storeRegistry = $storeRegistry;
+ $this->logger = $logger;
+ }
+
+ protected function configureLogging(OutputInterface $output): void
+ {
+ $level = LogLevel::ERROR;
+ if ($output->isDebug()) {
+ $level = LogLevel::DEBUG;
+ } elseif ($output->isVeryVerbose()) {
+ $level = LogLevel::INFO;
+ } elseif ($output->isVerbose()) {
+ $level = LogLevel::NOTICE;
+ }
+
+ if ($this->logger instanceof Logger) {
+ $handlers = $this->logger->getHandlers();
+ foreach ($handlers as $handler) {
+ if ($handler instanceof AbstractHandler) {
+ $handler->setLevel($level);
+ }
+ }
+
+ if (!$output->isQuiet()) {
+ $this->logger->pushHandler(
+ new OutputLogHandler($output, $level)
+ );
+ }
+ }
+
+ if ($output->isDebug()) {
+ $this->logger->notice(
+ \sprintf('Command "%s" started in debug mode (-vvv).', $this->getName())
+ );
+
+ \define('DEBUG_MODE', true);
+ }
+ }
+
+ protected function execute(
+ InputInterface $input,
+ OutputInterface $output
+ ): int {
+ $this->configureLogging($output);
+
+ return 0;
+ }
+}
diff --git a/src/Command/CreateAdminCommand.php b/src/Command/CreateAdminCommand.php
index 4550b9f37..78ba1067f 100644
--- a/src/Command/CreateAdminCommand.php
+++ b/src/Command/CreateAdminCommand.php
@@ -1,38 +1,46 @@
* @author Wogan May (@woganmay)
*/
class CreateAdminCommand extends Command
{
- /**
- * @var UserStore
- */
- protected $userStore;
-
- public function __construct(UserStore $userStore)
- {
- parent::__construct();
+ protected UserStore $userStore;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ LoggerInterface $logger,
+ UserStore $userStore,
+ ?string $name = null
+ ) {
+ parent::__construct($configuration, $databaseManager, $storeRegistry, $logger, $name);
$this->userStore = $userStore;
}
- protected function configure()
+ protected function configure(): void
{
$this
->setName('php-censor:create-admin')
@@ -45,52 +53,24 @@ protected function configure()
}
/**
- * Creates an admin user in the existing database
- *
- * {@inheritDoc}
+ * @throws InvalidArgumentException
*/
- protected function execute(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
- /** @var $helper QuestionHelper */
- $helper = $this->getHelperSet()->get('question');
-
- // Function to validate email address.
- $mailValidator = function ($answer) {
- if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) {
- throw new InvalidArgumentException('Must be a valid email address.');
- }
-
- return $answer;
- };
-
- if ($adminEmail = $input->getOption('admin-email')) {
- $adminEmail = $mailValidator($adminEmail);
- } else {
- $questionEmail = new Question('Admin email: ');
- $adminEmail = $helper->ask($input, $output, $questionEmail);
- }
-
- if (!$adminName = $input->getOption('admin-name')) {
- $questionName = new Question('Admin name: ');
- $adminName = $helper->ask($input, $output, $questionName);
- }
-
- if (!$adminPassword = $input->getOption('admin-password')) {
- $questionPassword = new Question('Admin password: ');
- $questionPassword->setHidden(true);
- $questionPassword->setHiddenFallback(false);
- $adminPassword = $helper->ask($input, $output, $questionPassword);
- }
-
- try {
- $userService = new UserService($this->userStore);
- $userService->createUser($adminName, $adminEmail, 'internal', ['type' => 'internal'], $adminPassword, true);
-
- $output->writeln('User account created!');
- } catch (Exception $ex) {
- $output->writeln('PHP Censor failed to create your admin account!');
- $output->writeln('' . $ex->getMessage() . '');
- }
+ /** @var $questionHelper QuestionHelper */
+ $questionHelper = $this->getHelperSet()->get('question');
+
+ $createAdmin = new CreateAdmin(
+ $questionHelper,
+ $input,
+ $output,
+ $this->storeRegistry,
+ $this->userStore
+ );
+
+ $createAdmin->create(
+ $createAdmin->process()
+ );
return 0;
}
diff --git a/src/Command/CreateBuildCommand.php b/src/Command/CreateBuildCommand.php
index 1a646e239..b7422cf00 100644
--- a/src/Command/CreateBuildCommand.php
+++ b/src/Command/CreateBuildCommand.php
@@ -1,74 +1,84 @@
* @author Jérémy DECOOL (@jdecool)
*/
class CreateBuildCommand extends Command
{
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ protected ProjectStore $projectStore;
- /**
- * @var BuildService
- */
- protected $buildService;
+ protected BuildService $buildService;
- public function __construct(ProjectStore $projectStore, BuildService $buildService)
- {
- parent::__construct();
+ public function __construct(
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ LoggerInterface $logger,
+ ProjectStore $projectStore,
+ BuildService $buildService,
+ ?string $name = null
+ ) {
+ parent::__construct($configuration, $databaseManager, $storeRegistry, $logger, $name);
$this->projectStore = $projectStore;
$this->buildService = $buildService;
}
- /**
- * {@inheritDoc}
- */
- protected function configure()
+ protected function configure(): void
{
$this
->setName('php-censor:create-build')
- ->addArgument('projectId', InputArgument::REQUIRED, 'A project ID')
+ ->addArgument('project-id', InputArgument::REQUIRED, 'A project ID')
->addOption('commit', null, InputOption::VALUE_OPTIONAL, 'Commit ID to build')
->addOption('branch', null, InputOption::VALUE_OPTIONAL, 'Branch to build')
->addOption('email', null, InputOption::VALUE_OPTIONAL, 'Committer email')
->addOption('message', null, InputOption::VALUE_OPTIONAL, 'Commit message')
+ ->addOption('environment', null, InputOption::VALUE_OPTIONAL, 'Build environment')
->setDescription('Create a build for a project');
}
/**
- * {@inheritDoc}
+ * @throws InvalidArgumentException
+ * @throws RuntimeException
+ * @throws HttpException
*/
- public function execute(InputInterface $input, OutputInterface $output)
+ public function execute(InputInterface $input, OutputInterface $output): int
{
- $projectId = $input->getArgument('projectId');
+ $projectId = (int)$input->getArgument('project-id');
$commitId = $input->getOption('commit');
$branch = $input->getOption('branch');
- $environment = $input->hasOption('environment') ? $input->getOption('environment') : null;
+ $environment = $input->getOption('environment');
$ciEmail = $input->getOption('email');
$ciMessage = $input->getOption('message');
+ /** @var Project $project */
$project = $this->projectStore->getById($projectId);
if (empty($project) || $project->getArchived()) {
throw new InvalidArgumentException('Project does not exist: ' . $projectId);
@@ -76,8 +86,8 @@ public function execute(InputInterface $input, OutputInterface $output)
$environmentId = null;
if ($environment) {
- /** @var Store\EnvironmentStore $environmentStore */
- $environmentStore = Factory::getStore('Environment');
+ /** @var EnvironmentStore $environmentStore */
+ $environmentStore = $this->storeRegistry->get('Environment');
$environmentObject = $environmentStore->getByNameAndProjectId($environment, $project->getId());
if ($environmentObject) {
$environmentId = $environmentObject->getId();
@@ -99,9 +109,9 @@ public function execute(InputInterface $input, OutputInterface $output)
$output->writeln('Build Created');
return 0;
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
$output->writeln('Failed');
- $output->writeln(sprintf('%s', $e->getMessage()));
+ $output->writeln(\sprintf('%s', $e->getMessage()));
}
return 1;
diff --git a/src/Command/InstallCommand.php b/src/Command/InstallCommand.php
index 7a370cc29..f6bc9b360 100644
--- a/src/Command/InstallCommand.php
+++ b/src/Command/InstallCommand.php
@@ -1,41 +1,38 @@
* @author Dan Cryer
*/
class InstallCommand extends Command
{
- /**
- * @var string
- */
- protected $configPath = APP_DIR . 'config.yml';
+ protected string $configPath = APP_DIR . 'config.yml';
- protected function configure()
+ protected function configure(): void
{
$this
->setName('php-censor:install')
@@ -92,23 +89,19 @@ protected function configure()
->addOption(
'config-from-file',
null,
- InputOption::VALUE_OPTIONAL,
- 'Take config from file and ignore options',
- false
+ InputOption::VALUE_NONE,
+ 'Take config from file and ignore options'
)
->setDescription('Install PHP Censor');
}
- /**
- * Installs PHP Censor
- */
- protected function execute(InputInterface $input, OutputInterface $output)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$configFromFile = (bool)$input->getOption('config-from-file');
if (!$configFromFile && !$this->verifyNotInstalled($output)) {
- return;
+ return 1;
}
$output->writeln('');
@@ -139,24 +132,27 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->writeConfigFile($conf);
}
- $this->reloadConfig();
+ $this->configuration->load();
+
if (!$this->setupDatabase($output)) {
- return false;
+ return 2;
}
- $admin = $this->getAdminInformation($input, $output);
- $this->createAdminUser($admin, $output);
+ if (!$this->createAdminUser($input, $output)) {
+ return 3;
+ }
+
+ if (!$this->createDefaultGroup($output)) {
+ return 4;
+ }
- $this->createDefaultGroup($output);
+ return 0;
}
- /**
- * @return bool
- */
- protected function verifyNotInstalled(OutputInterface $output)
+ private function verifyNotInstalled(OutputInterface $output): bool
{
- if (file_exists($this->configPath)) {
- $content = file_get_contents($this->configPath);
+ if (\file_exists($this->configPath)) {
+ $content = \file_get_contents($this->configPath);
if (!empty($content)) {
$output->writeln(
@@ -176,23 +172,21 @@ protected function verifyNotInstalled(OutputInterface $output)
*
* @throws Exception
*/
- protected function checkRequirements(OutputInterface $output)
+ private function checkRequirements(OutputInterface $output): void
{
$output->writeln('Checking requirements...');
$errors = false;
- if (!(version_compare(PHP_VERSION, '7.4.0') >= 0)) {
+ if (!(\version_compare(PHP_VERSION, '7.4.0') >= 0)) {
$output->writeln('');
- $output->writeln(
- 'PHP Censor requires at least PHP 7.4.0! Installed PHP ' . PHP_VERSION . ''
- );
+ $output->writeln('PHP Censor requires at least PHP 7.4.0! Installed PHP ' . PHP_VERSION . '');
$errors = true;
}
$requiredExtensions = ['PDO', 'xml', 'json', 'curl', 'openssl'];
foreach ($requiredExtensions as $extension) {
- if (!extension_loaded($extension)) {
+ if (!\extension_loaded($extension)) {
$output->writeln('');
$output->writeln('Extension required: ' . $extension . '');
$errors = true;
@@ -202,7 +196,7 @@ protected function checkRequirements(OutputInterface $output)
$requiredFunctions = ['exec', 'shell_exec', 'proc_open'];
foreach ($requiredFunctions as $function) {
- if (!function_exists($function)) {
+ if (!\function_exists($function)) {
$output->writeln('');
$output->writeln(
'PHP Censor needs to be able to call the ' . $function .
@@ -213,7 +207,7 @@ protected function checkRequirements(OutputInterface $output)
}
if ($errors) {
- throw new Exception(
+ throw new RuntimeException(
'PHP Censor cannot be installed, as not all requirements are met. ' .
'Please review the errors above before continuing.'
);
@@ -223,69 +217,22 @@ protected function checkRequirements(OutputInterface $output)
$output->writeln('OK');
}
- /**
- * Load information for admin user form CLI options or ask info to user.
- *
- * @return array
- */
- protected function getAdminInformation(InputInterface $input, OutputInterface $output)
- {
- $admin = [];
-
- /** @var $helper QuestionHelper */
- $helper = $this->getHelperSet()->get('question');
-
- // Function to validate email address.
- $mailValidator = function ($answer) {
- if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) {
- throw new InvalidArgumentException('Must be a valid email address.');
- }
-
- return $answer;
- };
-
- if ($adminEmail = $input->getOption('admin-email')) {
- $adminEmail = $mailValidator($adminEmail);
- } else {
- $questionEmail = new Question('Admin email: ');
- $adminEmail = $helper->ask($input, $output, $questionEmail);
- }
-
- if (!$adminName = $input->getOption('admin-name')) {
- $questionName = new Question('Admin name: ');
- $adminName = $helper->ask($input, $output, $questionName);
- }
-
- if (!$adminPassword = $input->getOption('admin-password')) {
- $questionPassword = new Question('Admin password: ');
- $questionPassword->setHidden(true);
- $questionPassword->setHiddenFallback(false);
- $adminPassword = $helper->ask($input, $output, $questionPassword);
- }
-
- $admin['email'] = $adminEmail;
- $admin['name'] = $adminName;
- $admin['password'] = $adminPassword;
-
- return $admin;
- }
-
/**
* Load configuration form CLI options or ask info to user.
*
- * @return array
+ * @throws Exception
*/
- protected function getConfigInformation(InputInterface $input, OutputInterface $output)
+ private function getConfigInformation(InputInterface $input, OutputInterface $output): array
{
/** @var $helper QuestionHelper */
$helper = $this->getHelperSet()->get('question');
- $urlValidator = function ($answer) {
- if (!filter_var($answer, FILTER_VALIDATE_URL)) {
- throw new Exception('Must be a valid URL.');
+ $urlValidator = function ($domain) {
+ if (!\filter_var($domain, FILTER_VALIDATE_URL)) {
+ throw new InvalidArgumentException("${domain} is not a valid URL!");
}
- return rtrim($answer, '/');
+ return \rtrim($domain, '/');
};
if ($url = $input->getOption('url')) {
@@ -302,11 +249,15 @@ protected function getConfigInformation(InputInterface $input, OutputInterface $
$queueConfig = $this->getQueueInformation($input, $output);
return [
- 'language' => 'en',
- 'per_page' => 10,
- 'url' => $url,
- 'queue' => $queueConfig,
- 'log' => [
+ 'language' => 'en',
+ 'per_page' => 10,
+ 'url' => $url,
+ 'queue' => $queueConfig,
+ 'realtime_ui' => true,
+ 'webhook' => [
+ 'log_requests' => false,
+ ],
+ 'log' => [
'rotate' => false,
'max_files' => 0,
],
@@ -371,15 +322,11 @@ protected function getConfigInformation(InputInterface $input, OutputInterface $
/**
* If the user wants to use a queue, get the necessary details.
- *
- * @return array
*/
- protected function getQueueInformation(InputInterface $input, OutputInterface $output)
+ private function getQueueInformation(InputInterface $input, OutputInterface $output): array
{
$queueConfig = [
- 'host' => null,
'port' => Pheanstalk::DEFAULT_PORT,
- 'name' => null,
'lifetime' => 600,
];
@@ -417,10 +364,8 @@ protected function getQueueInformation(InputInterface $input, OutputInterface $o
/**
* Load configuration for database form CLI options or ask info to user.
- *
- * @return array
*/
- protected function getDatabaseInformation(InputInterface $input, OutputInterface $output)
+ private function getDatabaseInformation(InputInterface $input, OutputInterface $output): array
{
$db = [];
@@ -429,7 +374,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface
if (!$dbType = $input->getOption('db-type')) {
$questionType = new Question('Enter your database type ("mysql" or "pgsql"): ');
- $dbType = trim(strtolower($helper->ask($input, $output, $questionType)));
+ $dbType = \trim(\strtolower($helper->ask($input, $output, $questionType)));
}
if (!$dbHost = $input->getOption('db-host')) {
@@ -437,7 +382,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface
'Enter your database host (default: "localhost"): ',
'localhost'
);
- $dbHost = trim($helper->ask($input, $output, $questionHost));
+ $dbHost = \trim($helper->ask($input, $output, $questionHost));
}
$defaultPort = 3306;
@@ -461,10 +406,10 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface
if (
$dbType === 'pgsql'
- && !$dbPgsqlSslmode = $input->getOption('db-pgsql-sslmode')
+ && !$dbPgsqlSslMode = $input->getOption('db-pgsql-sslmode')
) {
- $questionSslmode = new Question('Enter your database connection\'s SSL mode (default: prefer): ', 'prefer');
- $dbPgsqlSslmode = $helper->ask($input, $output, $questionSslmode);
+ $questionSslMode = new Question('Enter your database connection\'s SSL mode (default: prefer): ', 'prefer');
+ $dbPgsqlSslMode = $helper->ask($input, $output, $questionSslMode);
}
if (!$dbName = $input->getOption('db-name')) {
@@ -472,7 +417,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface
'Enter your database name (default: "php-censor-db"): ',
'php-censor-db'
);
- $dbName = trim($helper->ask($input, $output, $questionDb));
+ $dbName = \trim($helper->ask($input, $output, $questionDb));
}
if (!$dbUser = $input->getOption('db-user')) {
@@ -480,7 +425,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface
'Enter your database user (default: "php-censor-user"): ',
'php-censor-user'
);
- $dbUser = trim($helper->ask($input, $output, $questionUser));
+ $dbUser = \trim($helper->ask($input, $output, $questionUser));
}
if (!$dbPass = $input->getOption('db-password')) {
@@ -496,8 +441,8 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface
]
];
- if ($dbType === 'pgsql' && !empty($dbPgsqlSslmode)) {
- $dbServers[0]['pgsql-sslmode'] = $dbPgsqlSslmode;
+ if ($dbType === 'pgsql' && !empty($dbPgsqlSslMode)) {
+ $dbServers[0]['pgsql-sslmode'] = $dbPgsqlSslMode;
}
$dbServers[0]['port'] = $dbPort;
@@ -515,10 +460,8 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface
/**
* Try and connect to DB using the details provided
- *
- * @return bool
*/
- protected function verifyDatabaseDetails(array $db, OutputInterface $output)
+ private function verifyDatabaseDetails(array $db, OutputInterface $output): bool
{
$dns = $db['type'] . ':host=' . $db['servers']['write'][0]['host'];
@@ -552,7 +495,7 @@ protected function verifyDatabaseDetails(array $db, OutputInterface $output)
unset($pdo);
return true;
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$output->writeln(
'PHP Censor could not connect to database with the details provided. ' .
'Please try again.'
@@ -566,27 +509,27 @@ protected function verifyDatabaseDetails(array $db, OutputInterface $output)
/**
* Write the config.yml file.
*/
- protected function writeConfigFile(array $config)
+ private function writeConfigFile(array $config): void
{
$dumper = new Dumper();
$yaml = $dumper->dump($config, 4);
- file_put_contents($this->configPath, $yaml);
+ \file_put_contents($this->configPath, $yaml);
}
- protected function setupDatabase(OutputInterface $output)
+ private function setupDatabase(OutputInterface $output): bool
{
$output->write('Setting up your database...');
- exec(
+ \exec(
(ROOT_DIR . 'bin/console php-censor-migrations:migrate'),
$outputMigration,
$status
);
$output->writeln('');
- $output->writeln(implode(PHP_EOL, $outputMigration));
- if (0 == $status) {
+ $output->writeln(\implode(PHP_EOL, $outputMigration));
+ if (0 === $status) {
$output->writeln('OK');
return true;
@@ -600,69 +543,55 @@ protected function setupDatabase(OutputInterface $output)
/**
* Create admin user using information loaded before.
*
- * @param array $admin
- * @param OutputInterface $output
+ * @throws InvalidArgumentException
+ * @throws RuntimeException
*/
- protected function createAdminUser($admin, $output)
+ protected function createAdminUser(InputInterface $input, OutputInterface $output): bool
{
- try {
- /** @var UserStore $userStore */
- $userStore = Factory::getStore('User');
- $adminUser = $userStore->getByEmail($admin['email']);
- if ($adminUser) {
- throw new RuntimeException('Admin account already exists!');
- }
+ /** @var $questionHelper QuestionHelper */
+ $questionHelper = $this->getHelperSet()->get('question');
+
+ /** @var UserStore $userStore */
+ $userStore = $this->storeRegistry->get('User');
+
+ $createAdmin = new CreateAdmin(
+ $questionHelper,
+ $input,
+ $output,
+ $this->storeRegistry,
+ $userStore
+ );
- $userService = new UserService($userStore);
- $userService->createUser(
- $admin['name'],
- $admin['email'],
- 'internal',
- ['type' => 'internal'],
- $admin['password'],
- true
- );
+ $admin = $createAdmin->process();
- $output->writeln('User account created!');
- } catch (Exception $ex) {
- $output->writeln('PHP Censor failed to create your admin account!');
- $output->writeln('' . $ex->getMessage() . '');
- }
+ return $createAdmin->create($admin);
}
- /**
- * @param OutputInterface $output
- */
- protected function createDefaultGroup($output)
+ protected function createDefaultGroup(OutputInterface $output): bool
{
try {
/** @var ProjectGroupStore $projectGroupStore */
- $projectGroupStore = Factory::getStore('ProjectGroup');
+ $projectGroupStore = $this->storeRegistry->get('ProjectGroup');
$projectGroup = $projectGroupStore->getByTitle('Projects');
if ($projectGroup) {
throw new RuntimeException('Default project group already exists!');
}
- $group = new ProjectGroup();
+ $group = new ProjectGroup($this->storeRegistry);
$group->setTitle('Projects');
$group->setCreateDate(new DateTime());
$group->setUserId(null);
- Factory::getStore('ProjectGroup')->save($group);
+ $this->storeRegistry->get('ProjectGroup')->save($group);
$output->writeln('Default project group created!');
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$output->writeln('PHP Censor failed to create default project group!');
$output->writeln('' . $ex->getMessage() . '');
- }
- }
-
- protected function reloadConfig()
- {
- $config = Config::getInstance();
- if (file_exists($this->configPath)) {
- $config->loadYaml($this->configPath);
+ return false;
}
+
+ return true;
}
}
diff --git a/src/Command/LoggingCommand.php b/src/Command/LoggingCommand.php
deleted file mode 100644
index d1f6cac2a..000000000
--- a/src/Command/LoggingCommand.php
+++ /dev/null
@@ -1,66 +0,0 @@
-logger = $logger;
- }
-
- protected function configureLogging(OutputInterface $output)
- {
- $level = Logger::ERROR;
- if ($output->isDebug()) {
- $level = Logger::DEBUG;
- } elseif ($output->isVeryVerbose()) {
- $level = Logger::INFO;
- } elseif ($output->isVerbose()) {
- $level = Logger::NOTICE;
- }
-
- $handlers = $this->logger->getHandlers();
- foreach ($handlers as $handler) {
- if ($handler instanceof AbstractHandler) {
- $handler->setLevel($level);
- }
- }
-
- if (!$output->isQuiet()) {
- $this->logger->pushHandler(
- new OutputLogHandler($output, $level)
- );
- }
-
- if ($output->isDebug()) {
- $this->logger->notice(
- sprintf('Command "%s" started in debug mode (-vvv).', $this->getName())
- );
-
- define('DEBUG_MODE', true);
- }
- }
-
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $this->configureLogging($output);
- }
-}
diff --git a/src/Command/RebuildQueueCommand.php b/src/Command/RebuildQueueCommand.php
index 64bb89597..3e06834ab 100644
--- a/src/Command/RebuildQueueCommand.php
+++ b/src/Command/RebuildQueueCommand.php
@@ -1,84 +1,76 @@
* @author Dan Cryer
*/
class RebuildQueueCommand extends Command
{
- /**
- * @var OutputInterface
- */
- protected $output;
-
- /**
- * @var Logger
- */
- protected $logger;
-
- /**
- * @param string $name
- */
- public function __construct(Logger $logger, $name = null)
- {
- parent::__construct($name);
- $this->logger = $logger;
- }
-
- protected function configure()
+ protected function configure(): void
{
$this
->setName('php-censor:rebuild-queue')
->setDescription('Rebuilds the PHP Censor worker queue.');
}
- protected function execute(InputInterface $input, OutputInterface $output)
+ /**
+ * @throws RuntimeException
+ * @throws HttpException
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
- $this->output = $output;
-
- // For verbose mode we want to output all informational and above
- // messages to the symphony output interface.
- if ($input->hasOption('verbose') && $input->getOption('verbose')) {
- $this->logger->pushHandler(
- new OutputLogHandler($this->output, Logger::INFO)
- );
- }
-
/** @var BuildStore $buildStore */
- $buildStore = Factory::getStore('Build');
+ $buildStore = $this->storeRegistry->get('Build');
/** @var ProjectStore $projectStore */
- $projectStore = Factory::getStore('Project');
+ $projectStore = $this->storeRegistry->get('Project');
$result = $buildStore->getByStatus(0);
- $this->logger->addInfo(sprintf('Found %d builds', count($result['items'])));
+ $this->logger->info(\sprintf('Found %d builds', \count($result['items'])));
- $buildService = new BuildService($buildStore, $projectStore);
+ $buildFactory = new BuildFactory(
+ $this->configuration,
+ $this->storeRegistry
+ );
- while (count($result['items'])) {
- $build = array_shift($result['items']);
- $build = BuildFactory::getBuild($build);
+ $buildService = new BuildService(
+ $this->configuration,
+ $this->storeRegistry,
+ $buildFactory,
+ $buildStore,
+ $projectStore
+ );
+
+ while (\count($result['items'])) {
+ $build = \array_shift($result['items']);
+ $build = $buildFactory->getBuild($build);
$project = $build->getProject();
- $this->logger->addInfo('Added build #' . $build->getId() . ' to queue.');
+ $this->logger->info('Added build #' . $build->getId() . ' to queue.');
$buildService->addBuildToQueue(
$build,
(null !== $project) ? $project->getBuildPriority() : Project::DEFAULT_BUILD_PRIORITY
);
}
+
+ return 0;
}
}
diff --git a/src/Command/RemoveOldBuildsCommand.php b/src/Command/RemoveOldBuildsCommand.php
index 3ab764ed0..512828a4d 100644
--- a/src/Command/RemoveOldBuildsCommand.php
+++ b/src/Command/RemoveOldBuildsCommand.php
@@ -1,46 +1,51 @@
* @author David Sloan
*/
class RemoveOldBuildsCommand extends Command
{
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ protected ProjectStore $projectStore;
- /**
- * @var BuildService
- */
- protected $buildService;
+ protected BuildService $buildService;
- public function __construct(ProjectStore $projectStore, BuildService $buildService)
- {
- parent::__construct();
+ public function __construct(
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ LoggerInterface $logger,
+ ProjectStore $projectStore,
+ BuildService $buildService,
+ ?string $name = null
+ ) {
+ parent::__construct($configuration, $databaseManager, $storeRegistry, $logger, $name);
- /** @var ProjectStore $projectStore */
$this->projectStore = $projectStore;
-
- /** @var BuildStore $buildStore */
$this->buildService = $buildService;
}
/**
* Configure.
*/
- protected function configure()
+ protected function configure(): void
{
$this
->setName('php-censor:remove-old-builds')
@@ -48,13 +53,17 @@ protected function configure()
}
/**
- * Loops through projects.
- */
- protected function execute(InputInterface $input, OutputInterface $output)
+ * Loops through projects.
+ *
+ * @throws HttpException
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$projects = $this->projectStore->getAll();
foreach ($projects['items'] as $project) {
$this->buildService->deleteOldByProject($project->getId());
}
+
+ return 0;
}
}
diff --git a/src/Command/WorkerCommand.php b/src/Command/WorkerCommand.php
index 3175b4874..7d70be3b0 100644
--- a/src/Command/WorkerCommand.php
+++ b/src/Command/WorkerCommand.php
@@ -1,50 +1,57 @@
* @author Dan Cryer
*/
-class WorkerCommand extends LoggingCommand
+class WorkerCommand extends Command
{
- public const MIN_QUEUE_PRIORITY = 24;
- public const MAX_QUEUE_PRIORITY = 2025;
+ private const MIN_QUEUE_PRIORITY = 24;
+ private const MAX_QUEUE_PRIORITY = 2025;
- /**
- * @var BuildService
- */
- protected $buildService;
+ protected BuildService $buildService;
+
+ protected BuildFactory $buildFactory;
- /**
- * @param string $name
- */
public function __construct(
- Logger $logger,
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ LoggerInterface $logger,
BuildService $buildService,
- $name = null
+ BuildFactory $buildFactory,
+ ?string $name = null
) {
- parent::__construct($logger, $name);
+ parent::__construct($configuration, $databaseManager, $storeRegistry, $logger, $name);
$this->buildService = $buildService;
+ $this->buildFactory = $buildFactory;
}
- protected function configure()
+ protected function configure(): void
{
- $whenHints = 'soon=when next job done (default), done=when current jobs done, idle=when waiting for jobs';
$this
->setName('php-censor:worker')
->addOption(
@@ -57,52 +64,83 @@ protected function configure()
'stop-worker',
's',
InputOption::VALUE_OPTIONAL,
- "Gracefully stop one worker ($whenHints)",
- false // default value is used when option not given
+ "Gracefully stop one worker ('soon' = when next job done, 'done' = when current jobs done, 'idle' = when waiting for jobs)",
+ ''
)
->setDescription('Runs the PHP Censor build worker.');
}
/**
- * @throws Exception
+ * @throws RuntimeException
*/
- protected function execute(InputInterface $input, OutputInterface $output)
+ private function checkQueueSettings(array $config): void
{
- parent::execute($input, $output);
-
- $config = Config::getInstance()->get('php-censor.queue', []);
if (empty($config['host']) || empty($config['name'])) {
throw new RuntimeException(
'The worker is not configured. You must set a host and queue in your config.yml file.'
);
}
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ */
+ private function processWorkerStopFlag(InputInterface $input): bool
+ {
$value = $input->getOption('stop-worker');
- if (false !== $value) {
- if ('soon' === $value || null === $value) {
+ if (!empty($value)) {
+ if ('soon' === $value) {
$priority = self::MIN_QUEUE_PRIORITY; // high priority, stop soon
} elseif ('done' === $value) {
- $priority = Pheanstalk::DEFAULT_PRIORITY;
+ $priority = PheanstalkInterface::DEFAULT_PRIORITY;
} elseif ('idle' === $value) {
$priority = self::MAX_QUEUE_PRIORITY; // low priority, stop late
} else {
- $msg = sprintf('Invalid value "%s" for --stop-worker, valid are soon, done and idle;', $value);
-
- throw new InvalidArgumentException($msg);
+ throw new InvalidArgumentException(
+ \sprintf('Invalid value "%s" for --stop-worker, valid are soon, done and idle;', $value)
+ );
}
+
$jobData = [];
$this->buildService->addJobToQueue(BuildWorker::JOB_TYPE_STOP_FLAG, $jobData, $priority);
- return;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ parent::execute($input, $output);
+
+ $config = $this->configuration->get('php-censor.queue', []);
+ $this->checkQueueSettings($config);
+
+ $needToStopWorker = $this->processWorkerStopFlag($input);
+ if ($needToStopWorker) {
+ return 0;
}
- (new BuildWorker(
+ $periodicalWork = (bool)$input->getOption('periodical-work');
+ $worker = new BuildWorker(
+ $this->configuration,
+ $this->databaseManager,
+ $this->storeRegistry,
$this->logger,
$this->buildService,
+ $this->buildFactory,
$config['host'],
- Config::getInstance()->get('php-censor.queue.port', Pheanstalk::DEFAULT_PORT),
+ (int)$this->configuration->get('php-censor.queue.port', PheanstalkInterface::DEFAULT_PORT),
$config['name'],
- ($input->hasOption('periodical-work') && $input->getOption('periodical-work'))
- ))
- ->startWorker();
+ $periodicalWork
+ );
+
+ $worker->startWorker();
+
+ return 0;
}
}
diff --git a/src/Config.php b/src/Config.php
deleted file mode 100644
index 7fdb186a4..000000000
--- a/src/Config.php
+++ /dev/null
@@ -1,210 +0,0 @@
-setArray($settings);
- } elseif (is_string($settings) && file_exists($settings)) {
- $this->loadYaml($settings);
- }
- }
-
- /**
- * @param string $yamlFile
- */
- public function loadYaml($yamlFile)
- {
- // Path to a YAML file.
- $parser = new YamlParser();
- $yaml = file_get_contents($yamlFile);
- $config = (array)$parser->parse($yaml);
-
- if (empty($config)) {
- return;
- }
-
- $this->setArray($config);
- }
-
- /**
- * Get a configuration value by key, returning a default value if not set.
- *
- * @param string $key
- * @param mixed $default
- *
- * @return mixed
- */
- public function get($key, $default = null)
- {
- $keyParts = explode('.', $key);
- $selected = $this->config;
-
- $i = -1;
- $lastPart = count($keyParts) - 1;
- while ($part = array_shift($keyParts)) {
- $i++;
-
- if (!array_key_exists($part, $selected)) {
- return $default;
- }
-
- if ($i === $lastPart) {
- return $selected[$part];
- } else {
- $selected = $selected[$part];
- }
- }
-
- return $default;
- }
-
- /**
- * Set a value by key.
- *
- * @param string $key
- * @param mixed $value
- *
- * @return bool
- */
- public function set($key, $value = null)
- {
- $this->config[$key] = $value;
-
- return true;
- }
-
- /**
- * Set an array of values.
- *
- */
- public function setArray($array)
- {
- self::deepMerge($this->config, $array);
- }
-
- /**
- * Short-hand syntax for get()
- * @see Config::get()
- *
- * @param string $key
- *
- * @return mixed
- */
- public function __get($key)
- {
- return $this->get($key);
- }
-
- /**
- * Short-hand syntax for set()
- * @see Config::set()
- *
- * @param string $key
- * @param mixed $value
- *
- * @return bool
- */
- public function __set($key, $value = null)
- {
- return $this->set($key, $value);
- }
-
- /**
- * Is set
- *
- * @param string $key
- *
- * @return bool
- */
- public function __isset($key)
- {
- return isset($this->config[$key]);
- }
-
- /**
- * Unset
- *
- * @param string $key
- */
- public function __unset($key)
- {
- unset($this->config[$key]);
- }
-
- /**
- * Deeply merge the $target array onto the $source array. The $source array will be modified!
- *
- * @param array $source
- * @param array $target
- */
- public static function deepMerge(&$source, $target)
- {
- if (count($source) === 0) {
- $source = $target;
-
- return;
- }
-
- foreach ($target as $targetKey => $targetValue) {
- if (isset($source[$targetKey])) {
- if (!is_array($source[$targetKey]) && !is_array($targetValue)) {
- // Neither value is an array, overwrite
- $source[$targetKey] = $targetValue;
- } elseif (is_array($source[$targetKey]) && is_array($targetValue)) {
- // Both are arrays, deep merge them
- self::deepMerge($source[$targetKey], $targetValue);
- } elseif (is_array($source[$targetKey])) {
- // Source is the array, push target value
- $source[$targetKey][] = $targetValue;
- } else {
- // Target is the array, push source value and copy back
- $targetValue[] = $source[$targetKey];
- $source[$targetKey] = $targetValue;
- }
- } else {
- // No merge required, just set the value
- $source[$targetKey] = $targetValue;
- }
- }
- }
-
- /**
- * @return array
- */
- public function getArray()
- {
- return $this->config;
- }
-}
diff --git a/src/Configuration.php b/src/Configuration.php
new file mode 100644
index 000000000..a8712cefb
--- /dev/null
+++ b/src/Configuration.php
@@ -0,0 +1,47 @@
+
+ */
+class Configuration extends ParameterBag implements ConfigurationInterface
+{
+ private string $configurationPath;
+
+ public function __construct(string $configurationPath)
+ {
+ parent::__construct([]);
+
+ $this->configurationPath = $configurationPath;
+
+ $this->load();
+ }
+
+ public function load(): void
+ {
+ $parameters = [];
+ if ($this->configurationPath && \file_exists($this->configurationPath)) {
+ $parameters = $this->loadYaml($this->configurationPath);
+ }
+
+ $this->parameters = $parameters;
+ }
+
+ private function loadYaml(string $configurationPath): array
+ {
+ $parser = new YamlParser();
+ $yaml = \file_get_contents($configurationPath);
+
+ return (array)$parser->parse($yaml);
+ }
+}
diff --git a/src/Console/Application.php b/src/Console/Application.php
index 000554f66..d4d6098a8 100644
--- a/src/Console/Application.php
+++ b/src/Console/Application.php
@@ -1,5 +1,7 @@
*/
class Application extends BaseApplication
{
- public const LOGO = <<<'LOGO'
+ private const LOGO = <<<'LOGO'
____ __ ______ ______
/ __ \/ / / / __ \ / ____/__ ____ _________ _____
/ /_/ / /_/ / /_/ / / / / _ \/ __ \/ ___/ __ \/ ___/
@@ -46,12 +54,16 @@ class Application extends BaseApplication
LOGO;
+ private ConfigurationInterface $configuration;
+
+ private DatabaseManager $databaseManager;
+
+ private StoreRegistry $storeRegistry;
+
/**
- * @return Logger
- *
* @throws Exception
*/
- protected function initLogger(Config $applicationConfig)
+ protected function initLogger(ConfigurationInterface $applicationConfig): Logger
{
$rotate = (bool)$applicationConfig->get('php-censor.log.rotate', false);
$maxFiles = (int)$applicationConfig->get('php-censor.log.max_files', 0);
@@ -72,24 +84,26 @@ protected function initLogger(Config $applicationConfig)
return $logger;
}
- /**
- * @param string $name
- * @param string $version
- *
- * @throws Exception
- */
- public function __construct($name = 'PHP Censor', $version = 'UNKNOWN')
- {
- $version = (string)\trim(\file_get_contents(ROOT_DIR . 'VERSION.md'));
+ public function __construct(
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ string $name = 'PHP Censor',
+ string $version = 'UNKNOWN'
+ ) {
+ $version = \trim(\file_get_contents(ROOT_DIR . 'VERSION.md'));
$version = !empty($version) ? $version : '0.0.0 (UNKNOWN)';
parent::__construct($name, $version);
- $applicationConfig = Config::getInstance();
- $oldDatabaseSettings = $applicationConfig->get('b8.database', []);
- $databaseSettings = $applicationConfig->get('php-censor.database', []);
+ $this->configuration = $configuration;
+ $this->databaseManager = $databaseManager;
+ $this->storeRegistry = $storeRegistry;
+
+ $oldDatabaseSettings = $this->configuration->get('b8.database', []);
+ $databaseSettings = $this->configuration->get('php-censor.database', []);
if ($oldDatabaseSettings && !$databaseSettings) {
- throw new \RuntimeException(
+ throw new InvalidArgumentException(
'Missing database settings in application config "config.yml" (Section: "php-censor.database")'
);
}
@@ -127,7 +141,7 @@ public function __construct($name = 'PHP Censor', $version = 'UNKNOWN')
if (!empty($databaseSettings['type'])
&& $databaseSettings['type'] === 'pgsql'
) {
- if (!array_key_exists('pgsql-sslmode', $databaseSettings['servers']['write'][0])) {
+ if (!\array_key_exists('pgsql-sslmode', $databaseSettings['servers']['write'][0])) {
$databaseSettings['servers']['write'][0]['pgsql-sslmode'] = 'prefer';
}
@@ -159,32 +173,43 @@ public function __construct($name = 'PHP Censor', $version = 'UNKNOWN')
);
/** @var UserStore $userStore */
- $userStore = Factory::getStore('User');
+ $userStore = $this->storeRegistry->get('User');
/** @var ProjectStore $projectStore */
- $projectStore = Factory::getStore('Project');
+ $projectStore = $this->storeRegistry->get('Project');
/** @var BuildStore $buildStore */
- $buildStore = Factory::getStore('Build');
-
- $buildService = new BuildService($buildStore, $projectStore);
- $logger = $this->initLogger($applicationConfig);
-
- $this->add(new InstallCommand());
- $this->add(new CreateAdminCommand($userStore));
- $this->add(new CreateBuildCommand($projectStore, $buildService));
- $this->add(new RemoveOldBuildsCommand($projectStore, $buildService));
- $this->add(new WorkerCommand($logger, $buildService));
- $this->add(new RebuildQueueCommand($logger));
- $this->add(new CheckLocalizationCommand());
+ $buildStore = $this->storeRegistry->get('Build');
+
+ /** @var SecretStore $secretStore */
+ $secretStore = $this->storeRegistry->get('Secret');
+
+ $buildFactory = new BuildFactory(
+ $this->configuration,
+ $this->storeRegistry
+ );
+
+ $buildService = new BuildService(
+ $this->configuration,
+ $this->storeRegistry,
+ $buildFactory,
+ $buildStore,
+ $projectStore
+ );
+
+ $logger = $this->initLogger($this->configuration);
+
+ $this->add(new InstallCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger));
+ $this->add(new CreateAdminCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger, $userStore));
+ $this->add(new CreateBuildCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger, $projectStore, $buildService));
+ $this->add(new RemoveOldBuildsCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger, $projectStore, $buildService));
+ $this->add(new WorkerCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger, $buildService, $buildFactory));
+ $this->add(new RebuildQueueCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger));
+ $this->add(new CheckLocalizationsCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger));
+ $this->add(new AddSecretCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger, $secretStore));
}
- /**
- * Returns help.
- *
- * @return string
- */
- public function getHelp()
+ public function getHelp(): string
{
return self::LOGO . parent::getHelp();
}
@@ -194,8 +219,8 @@ public function getHelp()
*
* @return string The long application version
*/
- public function getLongVersion()
+ public function getLongVersion(): string
{
- return sprintf('%s v%s', $this->getName(), $this->getVersion());
+ return \sprintf('%s v%s', $this->getName(), $this->getVersion());
}
}
diff --git a/src/Controller.php b/src/Controller.php
index 8456fa65c..a3c7f783b 100644
--- a/src/Controller.php
+++ b/src/Controller.php
@@ -1,45 +1,51 @@
+ * @author Dmitry Khomutov
+ */
abstract class Controller
{
- /**
- * @var Request
- */
- protected $request;
+ protected Request $request;
- /**
- * @var Config
- */
- protected $config;
+ protected Session $session;
- public function __construct(Config $config, Request $request)
- {
- $this->config = $config;
- $this->request = $request;
+ protected ConfigurationInterface $configuration;
+
+ protected StoreRegistry $storeRegistry;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ StoreRegistry $storeRegistry,
+ Request $request,
+ Session $session
+ ) {
+ $this->configuration = $configuration;
+ $this->storeRegistry = $storeRegistry;
+ $this->request = $request;
+ $this->session = $session;
}
/**
* Initialise the controller.
*/
- abstract public function init();
+ abstract public function init(): void;
- /**
- * @param string $name
- *
- * @return bool
- */
- public function hasAction($name)
+ public function hasAction(string $name): bool
{
- if (method_exists($this, $name)) {
- return true;
- }
-
- if (method_exists($this, '__call')) {
+ if (\method_exists($this, $name)) {
return true;
}
@@ -49,57 +55,22 @@ public function hasAction($name)
/**
* Handles an action on this controller and returns a Response object.
*
- * @param string $action
- * @param array $actionParams
- *
- * @return Response
+ * @return Response|string
*/
- public function handleAction($action, $actionParams)
+ public function handleAction(string $action, array $actionParams)
{
- return call_user_func_array([$this, $action], $actionParams);
- }
-
- /**
- * Get a hash of incoming request parameters ($_GET, $_POST)
- *
- * @return array
- */
- public function getParams()
- {
- return $this->request->getParams();
+ return \call_user_func_array([$this, $action], $actionParams);
}
/**
* Get a specific incoming request parameter.
*
- * @param string $key
* @param mixed $default Default return value (if key does not exist)
*
* @return mixed
*/
- public function getParam($key, $default = null)
- {
- return $this->request->getParam($key, $default);
- }
-
- /**
- * Change the value of an incoming request parameter.
- *
- * @param string $key
- * @param mixed $value
- */
- public function setParam($key, $value)
- {
- $this->request->setParam($key, $value);
- }
-
- /**
- * Remove an incoming request parameter.
- *
- * @param string $key
- */
- public function unsetParam($key)
+ public function getParam(string $key, $default = null)
{
- $this->request->unsetParam($key);
+ return $this->request->get($key, $default);
}
}
diff --git a/src/Controller/BuildController.php b/src/Controller/BuildController.php
index 9934f7558..ebc0ca394 100644
--- a/src/Controller/BuildController.php
+++ b/src/Controller/BuildController.php
@@ -1,82 +1,87 @@
+ * @author Dmitry Khomutov
*/
class BuildController extends WebController
{
- /**
- * @var string
- */
- public $layoutName = 'layout';
+ public string $layoutName = 'layout';
- /**
- * @var BuildStore
- */
- protected $buildStore;
+ protected BuildStore $buildStore;
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ protected ProjectStore $projectStore;
- /**
- * @var BuildService
- */
- protected $buildService;
+ protected BuildService $buildService;
- public function init()
+ protected BuildFactory $buildFactory;
+
+ public function init(): void
{
parent::init();
- $this->buildStore = Factory::getStore('Build');
- $this->projectStore = Factory::getStore('Project');
+ $this->buildStore = $this->storeRegistry->get('Build');
+ $this->projectStore = $this->storeRegistry->get('Project');
+
+ $this->buildFactory = new BuildFactory(
+ $this->configuration,
+ $this->storeRegistry
+ );
- $this->buildService = new BuildService($this->buildStore, $this->projectStore);
+ $this->buildService = new BuildService(
+ $this->configuration,
+ $this->storeRegistry,
+ $this->buildFactory,
+ $this->buildStore,
+ $this->projectStore
+ );
}
/**
* View a specific build.
*
- * @param int $buildId
- *
* @throws NotFoundException
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
*/
- public function view($buildId)
+ public function view(int $buildId): void
{
$page = (int)$this->getParam('page', 1);
$plugin = $this->getParam('plugin', '');
$isNew = $this->getParam('is_new', '');
- $severity = $this->getParam('severity', null);
+ $severity = $this->getParam('severity');
if (null !== $severity && '' !== $severity) {
$severity = (int)$severity;
} else {
$severity = null;
}
- $build = BuildFactory::getBuildById($buildId);
+ $build = $this->buildFactory->getBuildById($buildId);
if (!$build) {
throw new NotFoundException(Lang::get('build_x_not_found', $buildId));
@@ -84,28 +89,29 @@ public function view($buildId)
/** @var User $user */
$user = $this->getUser();
- $perPage = $user->getFinalPerPage();
+ $perPage = $user->getFinalPerPage($this->configuration);
$data = $this->getBuildData($build, $plugin, $severity, $isNew, (($page - 1) * $perPage), $perPage);
$pages = ($data['errors'] === 0)
? 1
- : (int)ceil($data['errors'] / $perPage);
+ : (int)\ceil($data['errors'] / $perPage);
if ($page > $pages) {
$page = $pages;
}
/** @var BuildErrorStore $errorStore */
- $errorStore = Factory::getStore('BuildError');
+ $errorStore = $this->storeRegistry->get('BuildError');
- $this->view->uiPlugins = $this->getUiPlugins();
- $this->view->build = $build;
- $this->view->data = $data;
+ $this->view->uiPlugins = $this->getUiPlugins();
+ $this->view->build = $build;
+ $this->view->data = $data;
+ $this->view->environment = $this->storeRegistry->get('Environment')->getById((int)$build->getEnvironmentId());
- $this->view->plugin = urldecode($plugin);
+ $this->view->plugin = \urldecode($plugin);
$this->view->plugins = $errorStore->getKnownPlugins($buildId, $severity, $isNew);
- $this->view->severity = urldecode(null !== $severity ? $severity : '');
+ $this->view->severity = \urldecode(null !== $severity ? (string)$severity : '');
$this->view->severities = $errorStore->getKnownSeverities($buildId, $plugin, $isNew);
- $this->view->isNew = urldecode($isNew);
+ $this->view->isNew = \urldecode($isNew);
$this->view->isNews = ['only_new', 'only_old'];
$this->view->page = $page;
@@ -126,18 +132,22 @@ public function view($buildId)
switch ($build->getStatus()) {
case 0:
$this->layout->skin = 'blue';
+
break;
case 1:
$this->layout->skin = 'yellow';
+
break;
case 2:
$this->layout->skin = 'green';
+
break;
case 3:
$this->layout->skin = 'red';
+
break;
}
@@ -149,7 +159,7 @@ public function view($buildId)
$delete = Lang::get('delete_build');
$deleteLink = APP_URL . 'build/delete/' . $build->getId();
- $project = Factory::getStore('Project')->getByPrimaryKey($build->getProjectId());
+ $project = $this->storeRegistry->get('Project')->getById((int)$build->getProjectId());
$actions = '';
if (!$project->getArchived()) {
@@ -168,16 +178,15 @@ public function view($buildId)
/**
* Returns an array of the JS plugins to include.
- * @return array
*/
- protected function getUiPlugins()
+ protected function getUiPlugins(): array
{
$rtn = [];
$path = PUBLIC_DIR . 'assets/js/build-plugins/';
- $dir = opendir($path);
+ $dir = \opendir($path);
- while ($item = readdir($dir)) {
- if (substr($item, 0, 1) == '.' || substr($item, -3) != '.js') {
+ while ($item = \readdir($dir)) {
+ if (\substr($item, 0, 1) === '.' || \substr($item, -3) !== '.js') {
continue;
}
@@ -190,36 +199,38 @@ protected function getUiPlugins()
/**
* Get build data from database and json encode it.
*
- * @param string $plugin
- * @param int $severity
- * @param string $isNew
- * @param int $start
- * @param int $perPage
- *
- * @return array
+ * @throws \PHPCensor\Common\Exception\InvalidArgumentException
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
*/
- protected function getBuildData(Build $build, $plugin, $severity, $isNew, $start = 0, $perPage = 10)
- {
+ protected function getBuildData(
+ Build $build,
+ string $plugin,
+ ?int $severity,
+ string $isNew,
+ int $start = 0,
+ int $perPage = 10
+ ): array {
$data = [];
$data['status'] = (int)$build->getStatus();
- $data['log'] = $this->cleanLog($build->getLog());
+ $data['log'] = $this->cleanLog((string)$build->getLog());
- $data['create_date'] = !is_null($build->getCreateDate())
+ $data['create_date'] = !\is_null($build->getCreateDate())
? $build->getCreateDate()->format('Y-m-d H:i:s')
: null;
- $data['start_date'] = !is_null($build->getStartDate())
+ $data['start_date'] = !\is_null($build->getStartDate())
? $build->getStartDate()->format('Y-m-d H:i:s')
: null;
- $data['finish_date'] = !is_null($build->getFinishDate())
+ $data['finish_date'] = !\is_null($build->getFinishDate())
? $build->getFinishDate()->format('Y-m-d H:i:s')
: null;
$data['duration'] = $build->getDuration();
/** @var BuildErrorStore $errorStore */
- $errorStore = Factory::getStore('BuildError');
+ $errorStore = $this->storeRegistry->get('BuildError');
$errors = $errorStore->getByBuildId($build->getId(), $perPage, $start, $plugin, $severity, $isNew);
$errorView = new View('Build/errors');
@@ -233,19 +244,15 @@ protected function getBuildData(Build $build, $plugin, $severity, $isNew, $start
return $data;
}
- /**
- * @param int $buildId
- * @param string $plugin
- * @param int $severity
- * @param string $isNew
- * @param int $total
- * @param int $perPage
- * @param int $page
- *
- * @return string
- */
- protected function getPaginatorHtml($buildId, $plugin, $severity, $isNew, $total, $perPage, $page)
- {
+ protected function getPaginatorHtml(
+ int $buildId,
+ string $plugin,
+ ?int $severity,
+ string $isNew,
+ int $total,
+ int $perPage,
+ int $page
+ ): string {
$view = new View('pagination');
$urlPattern = APP_URL . 'build/view/' . $buildId;
@@ -262,10 +269,10 @@ protected function getPaginatorHtml($buildId, $plugin, $severity, $isNew, $total
$params['is_new'] = $isNew;
}
- $urlPattern = $urlPattern . '?' . str_replace(
+ $urlPattern = $urlPattern . '?' . \str_replace(
'%28%3Anum%29',
'(:num)',
- http_build_query(array_merge($params, ['page' => '(:num)']))
+ \http_build_query(\array_merge($params, ['page' => '(:num)']))
) . '#errors';
$paginator = new Paginator($total, $perPage, $page, $urlPattern);
@@ -277,14 +284,14 @@ protected function getPaginatorHtml($buildId, $plugin, $severity, $isNew, $total
/**
* Create a build using an existing build as a template:
*
- *
- * @return RedirectResponse
* @throws NotFoundException
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
*/
- public function rebuild($buildId)
+ public function rebuild(int $buildId): Response
{
- $copy = BuildFactory::getBuildById($buildId);
- $project = Factory::getStore('Project')->getByPrimaryKey($copy->getProjectId());
+ $copy = $this->buildFactory->getBuildById($buildId);
+ $project = $this->storeRegistry->get('Project')->getById((int)$copy->getProjectId());
if (!$copy || $project->getArchived()) {
throw new NotFoundException(Lang::get('build_x_not_found', $buildId));
@@ -301,51 +308,47 @@ public function rebuild($buildId)
$build = $this->buildService->createDuplicateBuild($copy, Build::SOURCE_MANUAL_REBUILD_WEB);
if ($this->buildService->queueError) {
- $_SESSION['global_error'] = Lang::get('add_to_queue_failed');
+ $this->session->set('global_error', Lang::get('add_to_queue_failed'));
}
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL.'build/view/' . $build->getId());
-
- return $response;
+ return new RedirectResponse(APP_URL.'build/view/' . $build->getId());
}
/**
- * Delete a build.
- */
- public function delete($buildId)
+ * Delete a build.
+ *
+ * @throws NotFoundException
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
+ */
+ public function delete(int $buildId): Response
{
$this->requireAdmin();
- $build = BuildFactory::getBuildById($buildId);
-
+ $build = $this->buildFactory->getBuildById($buildId);
if (!$build) {
throw new NotFoundException(Lang::get('build_x_not_found', $buildId));
}
$this->buildService->deleteBuild($build);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL.'project/view/' . $build->getProjectId());
-
- return $response;
+ return new RedirectResponse(APP_URL.'project/view/' . $build->getProjectId());
}
/**
- * Parse log for unix colours and replace with HTML.
- */
- protected function cleanLog($log)
+ * Parse log for unix colours and replace with HTML.
+ */
+ protected function cleanLog(string $log): string
{
- return AnsiConverter::convert($log);
+ $converter = new AnsiToHtmlConverter(null, false);
+
+ return $converter->convert($log);
}
/**
* Formats a list of builds into rows suitable for the dropdowns in the header bar.
- *
- *
- * @return array
*/
- protected function formatBuilds($builds)
+ protected function formatBuilds(array $builds): array
{
$rtn = ['count' => $builds['count'], 'items' => []];
@@ -357,19 +360,19 @@ protected function formatBuilds($builds)
$rtn['items'][$build->getId()]['header_row'] = $header->render();
}
- ksort($rtn['items']);
+ \ksort($rtn['items']);
return $rtn;
}
- public function ajaxData($buildId)
+ public function ajaxData(int $buildId): Response
{
$page = (int)$this->getParam('page', 1);
$perPage = (int)$this->getParam('per_page', 10);
- $plugin = $this->getParam('plugin', null);
- $isNew = $this->getParam('is_new', null);
+ $plugin = $this->getParam('plugin');
+ $isNew = $this->getParam('is_new');
- $severity = $this->getParam('severity', null);
+ $severity = $this->getParam('severity');
if (null !== $severity && '' !== $severity) {
$severity = (int)$severity;
} else {
@@ -377,11 +380,11 @@ public function ajaxData($buildId)
}
$response = new JsonResponse();
- $build = BuildFactory::getBuildById($buildId);
+ $build = $this->buildFactory->getBuildById($buildId);
if (!$build) {
- $response->setResponseCode(404);
- $response->setContent([]);
+ $response->setStatusCode(404);
+ $response->setData([]);
return $response;
}
@@ -405,38 +408,32 @@ public function ajaxData($buildId)
$page
);
- $response->setContent($data);
+ $response->setData($data);
return $response;
}
- public function ajaxMeta($buildId)
+ public function ajaxMeta(int $buildId): Response
{
- $build = BuildFactory::getBuildById($buildId);
- $key = $this->getParam('key', null);
- $numBuilds = $this->getParam('num_builds', 1);
- $data = null;
+ $build = $this->buildFactory->getBuildById($buildId);
+ $key = $this->getParam('key');
+ $numBuilds = (int)$this->getParam('num_builds', 1);
+ $data = [];
if ($key && $build) {
$data = $this->buildStore->getMeta($key, $build->getProjectId(), $buildId, $build->getBranch(), $numBuilds);
}
- $response = new JsonResponse();
- $response->setContent($data);
-
- return $response;
+ return new JsonResponse($data);
}
- public function ajaxQueue()
+ public function ajaxQueue(): Response
{
$rtn = [
'pending' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_PENDING)),
'running' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_RUNNING)),
];
- $response = new JsonResponse();
- $response->setContent($rtn);
-
- return $response;
+ return new JsonResponse($rtn);
}
}
diff --git a/src/Controller/BuildStatusController.php b/src/Controller/BuildStatusController.php
index fc5c442ac..0ccf5d6cc 100644
--- a/src/Controller/BuildStatusController.php
+++ b/src/Controller/BuildStatusController.php
@@ -1,53 +1,58 @@
+ * @author Dmitry Khomutov
*/
class BuildStatusController extends WebController
{
- /**
- * @var string
- */
- public $layoutName = 'layoutPublic';
+ public string $layoutName = 'layoutPublic';
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ protected ProjectStore $projectStore;
- /**
- * @var BuildStore
- */
- protected $buildStore;
+ protected BuildStore $buildStore;
+
+ protected BuildFactory $buildFactory;
+
+ public function init(): void
+ {
+ parent::init();
+
+ $this->buildStore = $this->storeRegistry->get('Build');
+ $this->projectStore = $this->storeRegistry->get('Project');
+
+ $this->buildFactory = new BuildFactory(
+ $this->configuration,
+ $this->storeRegistry
+ );
+ }
/**
* Returns status of the last build
- *
- * @param string $branch
- *
- * @return string
*/
- protected function getStatus(Project $project, $branch)
+ protected function getStatus(Project $project, string $branch): string
{
$status = 'passing';
try {
@@ -59,7 +64,7 @@ protected function getStatus(Project $project, $branch)
if (isset($build) && $build instanceof Build && $build->getStatus() !== Build::STATUS_SUCCESS) {
$status = 'failed';
}
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
$status = 'error';
}
@@ -69,15 +74,12 @@ protected function getStatus(Project $project, $branch)
/**
* Returns coverage of the last build
*
- * @param string $branch
- * @param string $type
- *
* @return string
*/
- protected function getPhpunitCoverage(Project $project, $branch, $type = 'lines')
+ protected function getPhpunitCoverage(Project $project, string $branch, string $type = 'lines')
{
$coverage = 0;
- if (!in_array($type, ['classes', 'methods', 'lines'], true)) {
+ if (!\in_array($type, ['classes', 'methods', 'lines'], true)) {
$type = 'lines';
}
@@ -99,36 +101,27 @@ protected function getPhpunitCoverage(Project $project, $branch, $type = 'lines'
$coverage = $coverageMeta[0]['meta_value'][$type];
}
}
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
}
return $coverage;
}
- /**
- *
- * @return Response
- */
- protected function renderXml(SimpleXMLElement $xml = null)
+ protected function renderXml(?SimpleXMLElement $xml = null): Response
{
$response = new Response();
- $response->setHeader('Content-Type', 'text/xml');
+ $response->headers->set('Content-Type', 'text/xml');
$response->setContent($xml->asXML());
return $response;
}
/**
- * @param int $projectId
- * @param string $branch
- *
* @throws HttpException
* @throws InvalidArgumentException
- *
- * @return array
*/
- protected function getLatestBuilds($projectId, $branch)
+ protected function getLatestBuilds(int $projectId, string $branch): array
{
$criteria = [
'project_id' => $projectId,
@@ -139,28 +132,20 @@ protected function getLatestBuilds($projectId, $branch)
$builds = $this->buildStore->getWhere($criteria, 10, 0, $order);
foreach ($builds['items'] as &$build) {
- $build = BuildFactory::getBuild($build);
+ $build = $this->buildFactory->getBuild($build);
}
return $builds['items'];
}
- public function init()
- {
- parent::init();
-
- $this->buildStore = Factory::getStore('Build');
- $this->projectStore = Factory::getStore('Project');
- }
-
/**
* Returns the appropriate build PHPUnit coverage image in SVG format for a given project.
*
- *
- * @return Response
+ * @throws HttpException
*/
- public function phpunitCoverageImage($projectId)
+ public function phpunitCoverageImage(int $projectId): Response
{
+ /** @var Project $project */
$project = $this->projectStore->getById($projectId);
// plastic|flat|flat-squared|social
@@ -177,7 +162,7 @@ public function phpunitCoverageImage($projectId)
];
$coverage = $this->getPhpunitCoverage($project, $branch, $type);
- $imageUrl = sprintf(
+ $imageUrl = \sprintf(
'http://img.shields.io/badge/%s-%s-%s.svg?style=%s',
$label,
$coverage. '%25',
@@ -192,17 +177,17 @@ public function phpunitCoverageImage($projectId)
}
$cacheDir = RUNTIME_DIR . 'status_cache/';
- $cacheFile = $cacheDir . md5($imageUrl) . '.svg';
- if (!is_file($cacheFile)) {
- $image = file_get_contents($imageUrl);
- file_put_contents($cacheFile, $image);
+ $cacheFile = $cacheDir . \md5($imageUrl) . '.svg';
+ if (!\is_file($cacheFile)) {
+ $image = \file_get_contents($imageUrl);
+ \file_put_contents($cacheFile, $image);
}
- $image = file_get_contents($cacheFile);
+ $image = \file_get_contents($cacheFile);
$response = new Response();
- $response->setHeader('Content-Type', 'image/svg+xml');
+ $response->headers->set('Content-Type', 'image/svg+xml');
$response->setContent($image);
return $response;
@@ -211,10 +196,9 @@ public function phpunitCoverageImage($projectId)
/**
* Returns the appropriate build status image in SVG format for a given project.
*
- *
- * @return Response
+ * @throws HttpException
*/
- public function image($projectId)
+ public function image(int $projectId): Response
{
$project = $this->projectStore->getById($projectId);
@@ -232,15 +216,12 @@ public function image($projectId)
$status = $this->getStatus($project, $branch);
- if (is_null($status)) {
- $response = new RedirectResponse();
- $response->setHeader('Location', '/');
-
- return $response;
+ if (\is_null($status)) {
+ return new RedirectResponse('/');
}
- $color = ($status == 'passing') ? 'green' : 'red';
- $imageUrl = sprintf(
+ $color = ($status === 'passing') ? 'green' : 'red';
+ $imageUrl = \sprintf(
'http://img.shields.io/badge/%s-%s-%s.svg?style=%s',
$label,
$status,
@@ -255,17 +236,17 @@ public function image($projectId)
}
$cacheDir = RUNTIME_DIR . 'status_cache/';
- $cacheFile = $cacheDir . md5($imageUrl) . '.svg';
- if (!is_file($cacheFile)) {
- $image = file_get_contents($imageUrl);
- file_put_contents($cacheFile, $image);
+ $cacheFile = $cacheDir . \md5($imageUrl) . '.svg';
+ if (!\is_file($cacheFile)) {
+ $image = \file_get_contents($imageUrl);
+ \file_put_contents($cacheFile, $image);
}
- $image = file_get_contents($cacheFile);
+ $image = \file_get_contents($cacheFile);
$response = new Response();
- $response->setHeader('Content-Type', 'image/svg+xml');
+ $response->headers->set('Content-Type', 'image/svg+xml');
$response->setContent($image);
return $response;
@@ -274,15 +255,12 @@ public function image($projectId)
/**
* View the public status page of a given project, if enabled.
*
- * @param int $projectId
- *
- * @return string
- *
* @throws HttpException
* @throws InvalidArgumentException
* @throws NotFoundException
+ * @throws \PHPCensor\Common\Exception\RuntimeException
*/
- public function view($projectId)
+ public function view(int $projectId): string
{
$project = $this->projectStore->getById($projectId);
$branch = $this->getParam('branch', $project->getDefaultBranch());
@@ -293,12 +271,13 @@ public function view($projectId)
$builds = $this->getLatestBuilds($projectId, $branch);
- if (count($builds)) {
+ if (\count($builds)) {
$this->view->latest = $builds[0];
}
- $this->view->builds = $builds;
- $this->view->project = $project;
+ $this->view->builds = $builds;
+ $this->view->project = $project;
+ $this->view->environmentStore = $this->storeRegistry->get('Environment');
return $this->view->render();
}
@@ -306,12 +285,9 @@ public function view($projectId)
/**
* Displays projects information in ccmenu format
*
- *
- * @return Response
- *
* @throws Exception
*/
- public function ccxml($projectId)
+ public function ccxml(int $projectId): Response
{
/* @var Project $project */
$project = $this->projectStore->getById($projectId);
@@ -337,7 +313,7 @@ public function ccxml($projectId)
}
}
}
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
$xml = new SimpleXMLElement('');
}
diff --git a/src/Controller/GroupController.php b/src/Controller/GroupController.php
index 0efbebeb1..ffa5ea5d6 100644
--- a/src/Controller/GroupController.php
+++ b/src/Controller/GroupController.php
@@ -1,45 +1,44 @@
+ * @author Dmitry Khomutov
*/
class GroupController extends WebController
{
- /**
- * @var string
- */
- public $layoutName = 'layout';
+ public string $layoutName = 'layout';
- /**
- * @var ProjectGroupStore
- */
- protected $groupStore;
+ protected ProjectGroupStore $groupStore;
- public function init()
+ public function init(): void
{
parent::init();
- $this->groupStore = Factory::getStore('ProjectGroup');
+ $this->groupStore = $this->storeRegistry->get('ProjectGroup');
}
/**
* List project groups.
*/
- public function index()
+ public function index(): void
{
$this->requireAdmin();
@@ -51,37 +50,40 @@ public function index()
'title' => $group->getTitle(),
'id' => $group->getId(),
];
- $projectsActive = Factory::getStore('Project')->getByGroupId($group->getId(), false);
- $projectsArchived = Factory::getStore('Project')->getByGroupId($group->getId(), true);
+ $projectsActive = $this->storeRegistry->get('Project')->getByGroupId($group->getId(), false);
+ $projectsArchived = $this->storeRegistry->get('Project')->getByGroupId($group->getId(), true);
- $thisGroup['projects'] = array_merge($projectsActive['items'], $projectsArchived['items']);
+ $thisGroup['projects'] = \array_merge($projectsActive['items'], $projectsArchived['items']);
$groups[] = $thisGroup;
}
$this->layout->title = Lang::get('group_projects');
$this->view->groups = $groups;
+ $this->view->user = $this->getUser();
}
/**
* Add or edit a project group.
*
- * @param null $groupId
+ * @return Response
*
- * @return RedirectResponse
+ * @throws \PHPCensor\Common\Exception\InvalidArgumentException
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
*/
- public function edit($groupId = null)
+ public function edit(?int $groupId = null)
{
$this->requireAdmin();
- if (!is_null($groupId)) {
+ if (!\is_null($groupId)) {
$group = $this->groupStore->getById($groupId);
} else {
- $group = new ProjectGroup();
+ $group = new ProjectGroup($this->storeRegistry);
}
- if ($this->request->getMethod() == 'POST') {
+ if ($this->request->getMethod() === 'POST') {
$group->setTitle($this->getParam('title'));
- if (is_null($groupId)) {
+ if (\is_null($groupId)) {
/** @var User $user */
$user = $this->getUser();
@@ -91,8 +93,7 @@ public function edit($groupId = null)
$this->groupStore->save($group);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL.'group');
+ $response = new RedirectResponse(APP_URL . 'group');
return $response;
}
@@ -100,9 +101,9 @@ public function edit($groupId = null)
$form = new Form();
$form->setMethod('POST');
- $form->setAction(APP_URL . 'group/edit' . (!is_null($groupId) ? '/' . $groupId : ''));
+ $form->setAction(APP_URL . 'group/edit' . (!\is_null($groupId) ? '/' . $groupId : ''));
- $form->addField(new Form\Element\Csrf('group_form'));
+ $form->addField(new Csrf($this->session, 'group_form'));
$title = new Form\Element\Text('title');
$title->setContainerClass('form-group');
@@ -122,17 +123,18 @@ public function edit($groupId = null)
/**
* Delete a project group.
- * @return RedirectResponse
+ *
+ * @throws \PHPCensor\Common\Exception\Exception
+ * @throws \PHPCensor\Common\Exception\InvalidArgumentException
+ * @throws \PHPCensor\Exception\HttpException
*/
- public function delete($groupId)
+ public function delete(int $groupId): Response
{
$this->requireAdmin();
$group = $this->groupStore->getById($groupId);
$this->groupStore->delete($group);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL.'group');
- return $response;
+ return new RedirectResponse(APP_URL . 'group');
}
}
diff --git a/src/Controller/HomeController.php b/src/Controller/HomeController.php
index f58b26452..ad91f7cb0 100644
--- a/src/Controller/HomeController.php
+++ b/src/Controller/HomeController.php
@@ -1,25 +1,26 @@
*/
class HomeController extends WebController
{
- /**
- * @var string
- */
- public $layoutName = 'layout';
+ public string $layoutName = 'layout';
/**
* Display dashboard:
*/
- public function index()
+ public function index(): string
{
$this->layout->title = Lang::get('dashboard');
@@ -28,7 +29,7 @@ public function index()
'right' => [],
];
- $widgetsConfig = Config::getInstance()->get('php-censor.dashboard_widgets', [
+ $widgetsConfig = $this->configuration->get('php-censor.dashboard_widgets', [
'all_projects' => [
'side' => 'left',
],
diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php
index 1f154b19b..ff2342e3e 100644
--- a/src/Controller/ProjectController.php
+++ b/src/Controller/ProjectController.php
@@ -1,8 +1,9 @@
+ * @author Dmitry Khomutov
*/
class ProjectController extends WebController
{
- /**
- * @var string
- */
- public $layoutName = 'layout';
+ public string $layoutName = 'layout';
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ protected ProjectStore $projectStore;
- /**
- * @var ProjectService
- */
- protected $projectService;
+ protected ProjectService $projectService;
- /**
- * @var BuildStore
- */
- protected $buildStore;
+ protected BuildStore $buildStore;
- /**
- * @var BuildService
- */
- protected $buildService;
+ protected BuildService $buildService;
+
+ protected BuildFactory $buildFactory;
/**
* Initialise the controller, set up stores and services.
*/
- public function init()
+ public function init(): void
{
parent::init();
- $this->buildStore = Factory::getStore('Build');
- $this->projectStore = Factory::getStore('Project');
- $this->projectService = new ProjectService($this->projectStore);
- $this->buildService = new BuildService($this->buildStore, $this->projectStore);
+ $this->buildStore = $this->storeRegistry->get('Build');
+ $this->projectStore = $this->storeRegistry->get('Project');
+
+ $this->projectService = new ProjectService($this->storeRegistry, $this->projectStore);
+
+ $this->buildFactory = new BuildFactory(
+ $this->configuration,
+ $this->storeRegistry
+ );
+
+ $this->buildService = new BuildService(
+ $this->configuration,
+ $this->storeRegistry,
+ $this->buildFactory,
+ $this->buildStore,
+ $this->projectStore
+ );
}
- /**
- * @param int $projectId
- *
- * @return PHPCensor\Http\Response
- */
- public function ajaxBuilds($projectId)
+ public function ajaxBuilds(int $projectId): Response
{
$branch = $this->getParam('branch', '');
$environment = $this->getParam('environment', '');
@@ -87,7 +87,7 @@ public function ajaxBuilds($projectId)
$perPage
);
- $response = new PHPCensor\Http\Response();
+ $response = new Response();
$response->setContent($builds[0]);
return $response;
@@ -96,13 +96,11 @@ public function ajaxBuilds($projectId)
/**
* View a specific project.
*
- * @param int $projectId
- *
* @throws NotFoundException
- *
- * @return string
+ * @throws PHPCensor\Exception\HttpException
+ * @throws RuntimeException
*/
- public function view($projectId)
+ public function view(int $projectId): string
{
$branch = $this->getParam('branch', '');
$environment = $this->getParam('environment', '');
@@ -115,11 +113,11 @@ public function view($projectId)
/** @var PHPCensor\Model\User $user */
$user = $this->getUser();
- $perPage = $user->getFinalPerPage();
+ $perPage = $user->getFinalPerPage($this->configuration);
$builds = $this->getLatestBuildsHtml($projectId, $branch, $environment, (($page - 1) * $perPage), $perPage);
$pages = ($builds[1] === 0)
? 1
- : (int)ceil($builds[1] / $perPage);
+ : (int)\ceil($builds[1] / $perPage);
if ($page > $pages) {
$page = $pages;
@@ -128,9 +126,9 @@ public function view($projectId)
$this->view->builds = $builds[0];
$this->view->total = $builds[1];
$this->view->project = $project;
- $this->view->branch = urldecode($branch);
+ $this->view->branch = \urldecode($branch);
$this->view->branches = $this->projectStore->getKnownBranches($projectId);
- $this->view->environment = urldecode($environment);
+ $this->view->environment = \urldecode($environment);
$this->view->environments = $project->getEnvironmentsNames();
$this->view->page = $page;
$this->view->perPage = $perPage;
@@ -142,6 +140,7 @@ public function view($projectId)
$perPage,
$page
);
+ $this->view->user = $this->getUser();
$this->layout->title = $project->getTitle();
$this->layout->subtitle = '';
@@ -155,18 +154,14 @@ public function view($projectId)
return $this->view->render();
}
- /**
- * @param int $projectId
- * @param string $branch
- * @param string $environment
- * @param int $total
- * @param int $perPage
- * @param int $page
- *
- * @return string
- */
- protected function getPaginatorHtml($projectId, $branch, $environment, $total, $perPage, $page)
- {
+ protected function getPaginatorHtml(
+ int $projectId,
+ string $branch,
+ string $environment,
+ int $total,
+ int $perPage,
+ int $page
+ ): string {
$view = new View('pagination');
$urlPattern = APP_URL . 'project/view/' . $projectId;
@@ -179,10 +174,10 @@ protected function getPaginatorHtml($projectId, $branch, $environment, $total, $
$params['environment'] = $environment;
}
- $urlPattern = $urlPattern . '?' . str_replace(
+ $urlPattern = $urlPattern . '?' . \str_replace(
'%28%3Anum%29',
'(:num)',
- http_build_query(array_merge($params, ['page' => '(:num)']))
+ \http_build_query(\array_merge($params, ['page' => '(:num)']))
);
$paginator = new Paginator($total, $perPage, $page, $urlPattern);
@@ -197,11 +192,8 @@ protected function getPaginatorHtml($projectId, $branch, $environment, $total, $
* @param int $projectId
*
* @throws NotFoundException
- *
- * @return RedirectResponse
- *
*/
- public function build($projectId)
+ public function build($projectId): RedirectResponse
{
/* @var Project $project */
$project = $this->projectStore->getById($projectId);
@@ -219,9 +211,11 @@ public function build($projectId)
switch ($type) {
case 'environment':
$environment = $id;
+
break;
case 'branch':
$branch = $id;
+
break;
}
@@ -239,7 +233,7 @@ public function build($projectId)
$environmentId = null;
if ($environment) {
/** @var EnvironmentStore $environmentStore */
- $environmentStore = Factory::getStore('Environment');
+ $environmentStore = $this->storeRegistry->get('Environment');
$environmentObject = $environmentStore->getByNameAndProjectId($environment, $project->getId());
if ($environmentObject) {
$environmentId = $environmentObject->getId();
@@ -262,13 +256,10 @@ public function build($projectId)
);
if ($this->buildService->queueError) {
- $_SESSION['global_error'] = Lang::get('add_to_queue_failed');
+ $this->session->set('global_error', Lang::get('add_to_queue_failed'));
}
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL.'build/view/' . $build->getId());
-
- return $response;
+ return new RedirectResponse(APP_URL.'build/view/' . $build->getId());
}
/**
@@ -282,13 +273,36 @@ public function delete($projectId)
{
$this->requireAdmin();
+ /** @var Project $project */
$project = $this->projectStore->getById($projectId);
$this->projectService->deleteProject($project);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL);
+ return new RedirectResponse(APP_URL);
+ }
- return $response;
+ /**
+ * @return RedirectResponse
+ *
+ * @throws PHPCensor\Exception\HttpException
+ * @throws PHPCensor\Exception\HttpException\ForbiddenException
+ */
+ public function clone(int $projectId)
+ {
+ $this->requireAdmin();
+
+ /** @var PHPCensor\Model\User $user */
+ $user = $this->getUser();
+
+ /** @var Project $project */
+ $project = $this->projectStore->getById($projectId);
+ $project->setId(null);
+ $project->setTitle('CLONE OF: ' . $project->getTitle());
+ $project->setCreateDate(new \DateTime());
+ $project->setUserId($user->getId());
+
+ $project = $this->projectStore->save($project);
+
+ return new RedirectResponse(APP_URL.'project/view/' . $project->getId());
}
/**
@@ -304,10 +318,7 @@ public function deleteAllBuilds($projectId)
$this->buildService->deleteAllByProject($projectId);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL . 'project/view/' . $projectId);
-
- return $response;
+ return new RedirectResponse(APP_URL . 'project/view/' . $projectId);
}
/**
@@ -323,10 +334,7 @@ public function deleteOldBuilds($projectId)
$this->buildService->deleteOldByProject($projectId);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL . 'project/view/' . $projectId);
-
- return $response;
+ return new RedirectResponse(APP_URL . 'project/view/' . $projectId);
}
/**
@@ -346,7 +354,7 @@ protected function getLatestBuildsHtml($projectId, $branch = '', $environment =
if (!empty($environment)) {
/** @var EnvironmentStore $environmentStore */
- $environmentStore = Factory::getStore('Environment');
+ $environmentStore = $this->storeRegistry->get('Environment');
$environmentObject = $environmentStore->getByNameAndProjectId($environment, $projectId);
if ($environmentObject) {
$criteria['environment_id'] = $environmentObject->getId();
@@ -362,10 +370,12 @@ protected function getLatestBuildsHtml($projectId, $branch = '', $environment =
$view = new View('Project/ajax-builds');
foreach ($builds['items'] as &$build) {
- $build = BuildFactory::getBuild($build);
+ $build = $this->buildFactory->getBuild($build);
}
- $view->builds = $builds['items'];
+ $view->builds = $builds['items'];
+ $view->environmentStore = $this->storeRegistry->get('Environment');
+ $view->user = $this->getUser();
return [
$view->render(),
@@ -381,12 +391,13 @@ public function add()
$this->layout->title = Lang::get('add_project');
$this->requireAdmin();
- $method = $this->request->getMethod();
- $values = $this->getParams();
+ $method = $this->request->getMethod();
+ $values = $this->request->request->all();
+
$values['default_branch'] = null;
if ($method !== 'POST') {
- $sshKey = new SshKey();
+ $sshKey = new SshKey($this->configuration);
$key = $sshKey->generate();
$values['ssh_private_key'] = $key['ssh_private_key'];
@@ -425,10 +436,7 @@ public function add()
$user = $this->getUser();
$project = $this->projectService->createProject($title, $type, $reference, $user->getId(), $options);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL.'project/view/' . $project->getId());
-
- return $response;
+ return new RedirectResponse(APP_URL.'project/view/' . $project->getId());
}
}
@@ -452,7 +460,7 @@ public function edit($projectId)
$values = $project->getDataArray();
$values['environments'] = $project->getEnvironments();
- if (in_array($values['type'], [
+ if (\in_array($values['type'], [
Project::TYPE_GITHUB,
Project::TYPE_GITLAB
], true)) {
@@ -461,10 +469,10 @@ public function edit($projectId)
$values['reference'] = $accessInfo['origin'];
} elseif (isset($accessInfo['domain']) && $accessInfo['domain']) {
$reference = $accessInfo['user'] .
- '@' . $accessInfo['domain'] . ':' . ltrim($project->getReference(), '/') . '.git';
+ '@' . $accessInfo['domain'] . ':' . \ltrim($project->getReference(), '/') . '.git';
if (isset($accessInfo['port']) && $accessInfo['port']) {
$reference = $accessInfo['user'] . '@' . $accessInfo['domain'] . ':' . $accessInfo['port'] . '/' .
- ltrim($project->getReference(), '/') . '.git';
+ \ltrim($project->getReference(), '/') . '.git';
}
$values['reference'] = $reference;
@@ -472,7 +480,7 @@ public function edit($projectId)
}
if ($method === 'POST') {
- $values = $this->getParams();
+ $values = $this->request->request->all();
}
$form = $this->projectForm($values, 'edit/' . $projectId);
@@ -511,10 +519,7 @@ public function edit($projectId)
$project = $this->projectService->updateProject($project, $title, $type, $reference, $options);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL.'project/view/' . $project->getId());
-
- return $response;
+ return new RedirectResponse(APP_URL.'project/view/' . $project->getId());
}
/**
@@ -527,7 +532,7 @@ protected function projectForm($values, $type = 'add')
$form->setMethod('POST');
$form->setAction(APP_URL . 'project/' . $type);
- $form->addField(new Form\Element\Csrf('project_form'));
+ $form->addField(new Csrf($this->session, 'project_form'));
$form->addField(new Form\Element\Hidden('ssh_public_key'));
$options = [
@@ -544,7 +549,7 @@ protected function projectForm($values, $type = 'add')
Project::TYPE_SVN => 'Svn (Subversion)',
];
- $sourcesPattern = sprintf('^(%s)', implode('|', Project::$allowedTypes));
+ $sourcesPattern = \sprintf('^(%s)', \implode('|', Project::$allowedTypes));
$field = Form\Element\Select::create('type', Lang::get('where_hosted'), true);
$field->setPattern($sourcesPattern);
@@ -598,22 +603,22 @@ protected function projectForm($values, $type = 'add')
$field->setClass('form-control')->setContainerClass('form-group');
$field->setRows(6);
$field->setValidator(new Form\Validator\Yaml());
- $field->setDataTransformator(new Form\DataTransformer\Yaml());
+ $field->setDataTransformer(new Form\DataTransformer\Yaml());
$form->addField($field);
$field = Form\Element\TextArea::create('environments', Lang::get('environments_label'), false);
$field->setClass('form-control')->setContainerClass('form-group');
$field->setRows(6);
$field->setValidator(new Form\Validator\Yaml());
- $field->setDataTransformator(new Form\DataTransformer\Yaml());
+ $field->setDataTransformer(new Form\DataTransformer\Yaml());
$form->addField($field);
$field = Form\Element\Select::create('group_id', Lang::get('project_group'), true);
$field->setClass('form-control')->setContainerClass('form-group')->setValue(null);
- $groups = [];
- $groupStore = Factory::getStore('ProjectGroup');
- $groupList = $groupStore->getWhere([], 100, 0, ['title' => 'ASC']);
+ $groups = [];
+ $groupStore = $this->storeRegistry->get('ProjectGroup');
+ $groupList = $groupStore->getWhere([], 100, 0, ['title' => 'ASC']);
foreach ($groupList['items'] as $group) {
$groups[$group->getId()] = $group->getTitle();
@@ -690,10 +695,10 @@ protected function getReferenceValidator($values)
],
];
- if (in_array($type, $validators, true) && !preg_match($validators[$type]['regex'], $val)) {
- throw new Exception($validators[$type]['message']);
- } elseif (Project::TYPE_LOCAL === $type && !is_dir($val)) {
- throw new Exception(Lang::get('error_path'));
+ if (\in_array($type, $validators, true) && !\preg_match($validators[$type]['regex'], $val)) {
+ throw new RuntimeException($validators[$type]['message']);
+ } elseif (Project::TYPE_LOCAL === $type && !\is_dir($val)) {
+ throw new RuntimeException(Lang::get('error_path'));
}
return true;
diff --git a/src/Controller/SecretController.php b/src/Controller/SecretController.php
new file mode 100644
index 000000000..3ed942c6d
--- /dev/null
+++ b/src/Controller/SecretController.php
@@ -0,0 +1,138 @@
+
+ */
+class SecretController extends WebController
+{
+ public string $layoutName = 'layout';
+
+ protected SecretStore $secretStore;
+
+ public function init(): void
+ {
+ parent::init();
+
+ $this->secretStore = $this->storeRegistry->get('Secret');
+ }
+
+ public function index(): void
+ {
+ $this->requireAdmin();
+
+ $secrets = [];
+ $secretList = $this->secretStore->getWhere([], 100, 0, ['name' => 'ASC']);
+
+ foreach ($secretList['items'] as $secret) {
+ $thisSecret = [
+ 'name' => $secret->getName(),
+ 'id' => $secret->getId(),
+ ];
+ $secrets[] = $thisSecret;
+ }
+
+ $this->layout->title = Lang::get('secrets');
+ $this->view->secrets = $secrets;
+ $this->view->user = $this->getUser();
+ }
+
+ /**
+ * @return Response
+ *
+ * @throws \PHPCensor\Common\Exception\InvalidArgumentException
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
+ */
+ public function edit(?int $secretId = null)
+ {
+ $this->requireAdmin();
+
+ if (!\is_null($secretId)) {
+ $secret = $this->secretStore->getById($secretId);
+ } else {
+ $secret = new Secret($this->storeRegistry);
+ }
+
+ if ($this->request->getMethod() === 'POST') {
+ $secret->setName($this->getParam('name'));
+ $secret->setValue($this->getParam('value'));
+ if (\is_null($secretId)) {
+ /** @var User $user */
+ $user = $this->getUser();
+
+ $secret->setCreateDate(new DateTime());
+ $secret->setUserId($user->getId());
+ }
+
+ $this->secretStore->save($secret);
+
+ $response = new RedirectResponse(APP_URL . 'secret');
+
+ return $response;
+ }
+
+ $form = new Form();
+
+ $form->setMethod('POST');
+ $form->setAction(APP_URL . 'secret/edit' . (!\is_null($secretId) ? '/' . $secretId : ''));
+
+ $form->addField(new Csrf($this->session, 'secret_form'));
+
+ $field = Form\Element\Text::create('name', Lang::get('secret_name'), true);
+ $field
+ ->setClass('form-control')
+ ->setContainerClass('form-group')
+ ->setPattern(Secret::SECRET_NAME_PATTERN)
+ ->setValue($secret->getName());
+ $form->addField($field);
+
+ $field = Form\Element\TextArea::create('value', Lang::get('secret_value'), true);
+ $field
+ ->setClass('form-control')
+ ->setContainerClass('form-group')
+ ->setRows(8)
+ ->setValue($secret->getValue());
+ $form->addField($field);
+
+ $submit = new Form\Element\Submit();
+ $submit->setClass('btn btn-success');
+ $submit->setValue(Lang::get('secret_save'));
+ $form->addField($submit);
+
+ $this->view->form = $form;
+ }
+
+ /**
+ * @throws \PHPCensor\Common\Exception\Exception
+ * @throws \PHPCensor\Common\Exception\InvalidArgumentException
+ * @throws \PHPCensor\Exception\HttpException
+ */
+ public function delete(int $secretId): Response
+ {
+ $this->requireAdmin();
+
+ $group = $this->secretStore->getById($secretId);
+
+ $this->secretStore->delete($group);
+
+ return new RedirectResponse(APP_URL . 'secret');
+ }
+}
diff --git a/src/Controller/SessionController.php b/src/Controller/SessionController.php
index 06690ed04..29035b76e 100644
--- a/src/Controller/SessionController.php
+++ b/src/Controller/SessionController.php
@@ -1,8 +1,9 @@
+ * @author Dmitry Khomutov
*/
class SessionController extends WebController
{
- /**
- * @var string
- */
- public $layoutName = 'layoutSession';
+ public string $layoutName = 'layoutSession';
- /**
- * @var UserStore
- */
- protected $userStore;
+ protected UserStore $userStore;
- /**
- * @var Service
- */
- protected $authentication;
+ protected Service $authentication;
/**
* Initialise the controller, set up stores and services.
*/
- public function init()
+ public function init(): void
{
parent::init();
- $this->userStore = Factory::getStore('User');
- $this->authentication = Service::getInstance();
+ $this->userStore = $this->storeRegistry->get('User');
+ $this->authentication = new Service($this->configuration, $this->storeRegistry);
}
- protected function loginForm($values)
+ protected function loginForm(array $values): Form
{
$form = new Form();
$form->setMethod('POST');
$form->setAction(APP_URL . 'session/login');
- $form->addField(new Csrf('login_form'));
+ $form->addField(new Csrf($this->session, 'login_form'));
$email = new Text('email');
$email->setLabel(Lang::get('login'));
@@ -91,25 +86,28 @@ protected function loginForm($values)
/**
* Handles user login (form and processing)
+ *
+ * @return Response|string
+ *
+ * @throws HttpException
+ * @throws \PHPCensor\Common\Exception\InvalidArgumentException
*/
public function login()
{
- if (!empty($_COOKIE['remember_key'])) {
- $user = $this->userStore->getByRememberKey($_COOKIE['remember_key']);
+ $rememberKey = $this->request->cookies->get('remember_key');
+ if (!empty($rememberKey)) {
+ $user = $this->userStore->getByRememberKey($rememberKey);
if ($user) {
- $_SESSION['php-censor-user-id'] = $user->getId();
-
- $response = new RedirectResponse();
- $response->setHeader('Location', $this->getLoginRedirect());
+ $this->session->set('php-censor-user-id', $user->getId());
- return $response;
+ return new RedirectResponse($this->getLoginRedirect());
}
}
$method = $this->request->getMethod();
if ($method === 'POST') {
- $values = $this->getParams();
+ $values = $this->request->request->all();
} else {
$values = [];
}
@@ -141,34 +139,33 @@ public function login()
if ($user && $provider->verifyPassword($user, $password)) {
$this->userStore->save($user);
$isLoginFailure = false;
+
break;
}
}
}
if (!$isLoginFailure) {
- $_SESSION['php-censor-user-id'] = $user->getId();
+ $this->session->set('php-censor-user-id', $user->getId());
+ $response = new RedirectResponse($this->getLoginRedirect());
if ($rememberMe) {
- $rememberKey = md5(random_bytes(64));
+ $rememberKey = \md5(\random_bytes(64));
$user->setRememberKey($rememberKey);
$this->userStore->save($user);
- setcookie(
+ $response->headers->setCookie(new Cookie(
'remember_key',
$rememberKey,
- (time() + 60 * 60 * 24 * 30),
- null,
- null,
+ (\time() + 60 * 60 * 24 * 30),
+ '/',
null,
+ false,
true
- );
+ ));
}
- $response = new RedirectResponse();
- $response->setHeader('Location', $this->getLoginRedirect());
-
return $response;
}
}
@@ -181,26 +178,23 @@ public function login()
}
/**
- * Handles user logout.
- */
- public function logout()
+ * Handles user logout.
+ */
+ public function logout(): Response
{
- unset($_SESSION['php-censor-user-id']);
+ $this->session->remove('php-censor-user-id');
+ $this->session->clear();
- session_destroy();
-
- setcookie(
+ $response = new RedirectResponse(APP_URL);
+ $response->headers->setCookie(new Cookie(
'remember_key',
- null,
- (time() - 1),
- null,
+ '',
+ (\time() - 1),
null,
null,
+ false,
true
- );
-
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL);
+ ));
return $response;
}
@@ -208,13 +202,11 @@ public function logout()
/**
* Allows the user to request a password reset email.
*
- * @return string
- *
* @throws HttpException
*/
- public function forgotPassword()
+ public function forgotPassword(): string
{
- if ($this->request->getMethod() == 'POST') {
+ if ($this->request->getMethod() === 'POST') {
$email = $this->getParam('email', null);
$user = $this->userStore->getByEmail($email);
@@ -224,10 +216,10 @@ public function forgotPassword()
return $this->view->render();
}
- $key = md5(date('Y-m-d') . $user->getHash());
+ $key = \md5(\date('Y-m-d') . $user->getHash());
$message = Lang::get('reset_email_body', $user->getName(), APP_URL, $user->getId(), $key);
- $email = new Email(Config::getInstance());
+ $email = new Email($this->configuration);
$email->setEmailTo($user->getEmail(), $user->getName());
$email->setSubject(Lang::get('reset_email_title', $user->getName()));
$email->setBody($message);
@@ -241,31 +233,32 @@ public function forgotPassword()
/**
* Allows the user to change their password after a password reset email.
- * @return string
+ *
+ * @return Response|string
+ *
+ * @throws HttpException
+ * @throws \PHPCensor\Common\Exception\InvalidArgumentException
*/
- public function resetPassword($userId, $key)
+ public function resetPassword(int $userId, string $key)
{
$user = $this->userStore->getById($userId);
- $userKey = md5(date('Y-m-d') . $user->getHash());
+ $userKey = \md5(\date('Y-m-d') . $user->getHash());
- if (empty($user) || $key != $userKey) {
+ if (empty($user) || $key !== $userKey) {
$this->view->error = Lang::get('reset_invalid');
return $this->view->render();
}
- if ($this->request->getMethod() == 'POST') {
- $hash = password_hash($this->getParam('password'), PASSWORD_DEFAULT);
+ if ($this->request->getMethod() === 'POST') {
+ $hash = \password_hash($this->getParam('password'), PASSWORD_DEFAULT);
$user->setHash($hash);
$this->userStore->save($user);
- $_SESSION['php-censor-user-id'] = $user->getId();
-
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL);
+ $this->session->set('php-censor-user-id', $user->getId());
- return $response;
+ return new RedirectResponse(APP_URL);
}
$this->view->id = $userId;
@@ -276,15 +269,16 @@ public function resetPassword($userId, $key)
/**
* Get the URL the user was trying to go to prior to being asked to log in.
- * @return string
*/
- protected function getLoginRedirect()
+ protected function getLoginRedirect(): string
{
$rtn = APP_URL;
- if (!empty($_SESSION['php-censor-login-redirect'])) {
- $rtn .= $_SESSION['php-censor-login-redirect'];
- $_SESSION['php-censor-login-redirect'] = null;
+ $sessionLoginRedirect = $this->session->get('php-censor-login-redirect');
+ if (!empty($sessionLoginRedirect)) {
+ $rtn .= $sessionLoginRedirect;
+
+ $this->session->remove('php-censor-login-redirect');
}
return $rtn;
diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php
index 0ba52b84d..a58279489 100644
--- a/src/Controller/UserController.php
+++ b/src/Controller/UserController.php
@@ -1,75 +1,74 @@
+ * @author Dmitry Khomutov
*/
class UserController extends WebController
{
- /**
- * @var string
- */
- public $layoutName = 'layout';
+ public string $layoutName = 'layout';
- /**
- * @var UserStore
- */
- protected $userStore;
+ protected UserStore $userStore;
- /**
- * @var UserService
- */
- protected $userService;
+ protected UserService $userService;
/**
* Initialise the controller, set up stores and services.
*/
- public function init()
+ public function init(): void
{
parent::init();
- $this->userStore = Factory::getStore('User');
- $this->userService = new UserService($this->userStore);
+ $this->userStore = $this->storeRegistry->get('User');
+ $this->userService = new UserService($this->storeRegistry, $this->userStore);
}
/**
* View user list.
*/
- public function index()
+ public function index(): string
{
- $users = $this->userStore->getWhere([], 1000, 0, ['email' => 'ASC']);
- $this->view->users = $users;
- $this->layout->title = Lang::get('manage_users');
+ $users = $this->userStore->getWhere([], 1000, 0, ['email' => 'ASC']);
+ $this->view->currentUser = $this->getUser();
+ $this->view->users = $users;
+
+ $this->layout->title = Lang::get('manage_users');
return $this->view->render();
}
/**
* Allows the user to edit their profile.
- * @return string
+ *
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
*/
- public function profile()
+ public function profile(): string
{
/** @var User $user */
$user = $this->getUser();
- if ($this->request->getMethod() == 'POST') {
+ if ($this->request->getMethod() === 'POST') {
$name = $this->getParam('name', null);
$email = $this->getParam('email', null);
$password = $this->getParam('password', null);
@@ -97,7 +96,7 @@ public function profile()
$form->setAction(APP_URL . 'user/profile');
$form->setMethod('POST');
- $form->addField(new Form\Element\Csrf('profile_form'));
+ $form->addField(new Csrf($this->session, 'profile_form'));
$name = new Form\Element\Text('name');
$name->setClass('form-control');
@@ -129,8 +128,8 @@ public function profile()
$language->setLabel(Lang::get('language'));
$language->setRequired(true);
$language->setOptions(
- array_merge(
- [null => Lang::get('default') . ' (' . Config::getInstance()->get('php-censor.language') . ')'],
+ \array_merge(
+ [null => Lang::get('default') . ' (' . $this->configuration->get('php-censor.language') . ')'],
Lang::getLanguageOptions()
)
);
@@ -143,7 +142,7 @@ public function profile()
$perPage->setLabel(Lang::get('per_page'));
$perPage->setRequired(true);
$perPage->setOptions([
- null => Lang::get('default') . ' (' . Config::getInstance()->get('php-censor.per_page') . ')',
+ null => Lang::get('default') . ' (' . $this->configuration->get('php-censor.per_page') . ')',
10 => 10,
25 => 25,
50 => 50,
@@ -163,8 +162,12 @@ public function profile()
}
/**
- * Add a user - handles both form and processing.
- */
+ * Add a user - handles both form and processing.
+ *
+ * @return Response|string
+ *
+ * @throws \PHPCensor\Exception\HttpException
+ */
public function add()
{
$this->requireAdmin();
@@ -174,14 +177,14 @@ public function add()
$method = $this->request->getMethod();
if ($method === 'POST') {
- $values = $this->getParams();
+ $values = $this->request->request->all();
} else {
$values = [];
}
$form = $this->userForm($values);
- if ($method !== 'POST' || ($method == 'POST' && !$form->validate())) {
+ if ($method !== 'POST' || ($method === 'POST' && !$form->validate())) {
$view = new View('User/edit');
$view->type = 'add';
$view->user = null;
@@ -205,23 +208,27 @@ public function add()
$isAdmin
);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL . 'user');
-
- return $response;
+ return new RedirectResponse(APP_URL . 'user');
}
/**
- * Edit a user - handles both form and processing.
- */
- public function edit($userId)
+ * Edit a user - handles both form and processing.
+ *
+ * @return Response|string
+ *
+ * @throws ForbiddenException
+ * @throws NotFoundException
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
+ */
+ public function edit(int $userId)
{
$currentUser = $this->getUser();
$method = $this->request->getMethod();
$user = $this->userStore->getById($userId);
- if (!$currentUser->getIsAdmin() && $currentUser != $user) {
+ if (!$currentUser->getIsAdmin() && $currentUser !== $user) {
throw new ForbiddenException('You do not have permission to do that.');
}
@@ -232,10 +239,10 @@ public function edit($userId)
$this->layout->title = $user->getName();
$this->layout->subtitle = Lang::get('edit_user');
- $values = array_merge($user->getDataArray(), $this->getParams());
+ $values = \array_merge($user->getDataArray(), $this->request->request->all());
$form = $this->userForm($values, 'edit/' . $userId);
- if ($method != 'POST' || ($method == 'POST' && !$form->validate())) {
+ if ($method !== 'POST' || ($method === 'POST' && !$form->validate())) {
$view = new View('User/edit');
$view->type = 'edit';
$view->user = $user;
@@ -256,16 +263,16 @@ public function edit($userId)
$this->userService->updateUser($user, $name, $email, $password, $isAdmin);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL . 'user');
-
- return $response;
+ return new RedirectResponse(APP_URL . 'user');
}
/**
- * Create user add / edit form.
- */
- protected function userForm($values, $type = 'add')
+ * Create user add / edit form.
+ *
+ * @throws \PHPCensor\Common\Exception\RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
+ */
+ protected function userForm(array $values, string $type = 'add'): Form
{
$currentUser = $this->getUser();
@@ -274,7 +281,7 @@ protected function userForm($values, $type = 'add')
$form->setMethod('POST');
$form->setAction(APP_URL . 'user/' . $type);
- $form->addField(new Form\Element\Csrf('user_form'));
+ $form->addField(new Csrf($this->session, 'user_form'));
$field = new Form\Element\Email('email');
$field->setRequired(true);
@@ -292,7 +299,7 @@ protected function userForm($values, $type = 'add')
$field = new Form\Element\Password('password');
- if ($type == 'add') {
+ if ($type === 'add') {
$field->setRequired(true);
$field->setLabel(Lang::get('password'));
} else {
@@ -324,9 +331,12 @@ protected function userForm($values, $type = 'add')
}
/**
- * Delete a user.
- */
- public function delete($userId)
+ * Delete a user.
+ *
+ * @throws NotFoundException
+ * @throws \PHPCensor\Exception\HttpException
+ */
+ public function delete(int $userId): Response
{
$this->requireAdmin();
@@ -338,9 +348,6 @@ public function delete($userId)
$this->userService->deleteUser($user);
- $response = new RedirectResponse();
- $response->setHeader('Location', APP_URL . 'user');
-
- return $response;
+ return new RedirectResponse(APP_URL . 'user');
}
}
diff --git a/src/Controller/WebhookController.php b/src/Controller/WebhookController.php
index f13961277..0b710ff50 100644
--- a/src/Controller/WebhookController.php
+++ b/src/Controller/WebhookController.php
@@ -1,83 +1,97 @@
* @author Sami Tikka
* @author Alex Russell
* @author Guillaume Perréal
- *
+ * @author Dmitry Khomutov
*/
class WebhookController extends Controller
{
- /**
- * @var BuildStore
- */
- protected $buildStore;
+ protected BuildStore $buildStore;
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ protected ProjectStore $projectStore;
- /**
- * @var BuildService
- */
- protected $buildService;
+ protected WebhookRequestStore $webhookRequestStore;
+
+ protected BuildService $buildService;
+
+ protected BuildFactory $buildFactory;
+
+ private bool $logRequests = false;
/**
* Initialise the controller, set up stores and services.
*/
- public function init()
+ public function init(): void
{
- $this->buildStore = Factory::getStore('Build');
- $this->projectStore = Factory::getStore('Project');
+ $this->buildStore = $this->storeRegistry->get('Build');
+ $this->projectStore = $this->storeRegistry->get('Project');
+ $this->webhookRequestStore = $this->storeRegistry->get('WebhookRequest');
+
+ $this->buildFactory = new BuildFactory(
+ $this->configuration,
+ $this->storeRegistry
+ );
+
+ $this->buildService = new BuildService(
+ $this->configuration,
+ $this->storeRegistry,
+ $this->buildFactory,
+ $this->buildStore,
+ $this->projectStore
+ );
- $this->buildService = new BuildService($this->buildStore, $this->projectStore);
+ $this->logRequests = (bool)$this->configuration->get('php-censor.webhook.log_requests', false);
}
/**
* Handle the action, Ensuring to return a JsonResponse.
- *
- * @param string $action
- * @param array $actionParams
- *
- * @return Response
*/
- public function handleAction($action, $actionParams)
+ public function handleAction(string $action, array $actionParams): Response
{
- $response = new Response\JsonResponse();
+ $response = new JsonResponse();
try {
$data = parent::handleAction($action, $actionParams);
if (isset($data['responseCode'])) {
- $response->setResponseCode($data['responseCode']);
+ $response->setStatusCode($data['responseCode']);
unset($data['responseCode']);
}
- $response->setContent($data);
- } catch (Exception $ex) {
- $response->setResponseCode(500);
- $response->setContent(['status' => 'failed', 'error' => $ex->getMessage()]);
+ $response->setData($data);
+ } catch (\Throwable $ex) {
+ $response->setStatusCode(500);
+ $response->setData(['status' => 'failed', 'error' => $ex->getMessage()]);
}
return $response;
@@ -86,27 +100,23 @@ public function handleAction($action, $actionParams)
/**
* Wrapper for creating a new build.
*
- * @param int $source
- * @param string $commitId
- * @param string $branch
- * @param string $tag
- * @param string $committer
- * @param string $commitMessage
- *
- * @return array
+ * @return string[]
*
- * @throws Exception
+ * @throws NotFoundException
+ * @throws RuntimeException
+ * @throws \PHPCensor\Exception\HttpException
*/
protected function createBuild(
- $source,
+ int $source,
Project $project,
- $commitId,
- $branch,
- $tag,
- $committer,
- $commitMessage,
- array $extra = null
- ) {
+ string $commitId,
+ string $branch,
+ ?string $tag,
+ string $committer,
+ string $commitMessage,
+ ?array $extra = null,
+ ?string $environment = null
+ ): array {
if ($project->getArchived()) {
throw new NotFoundException(Lang::get('project_x_not_found', $project->getId()));
}
@@ -134,36 +144,38 @@ protected function createBuild(
$environments = $project->getEnvironmentsObjects();
if ($environments['count']) {
- $createdBuilds = [];
- $environmentIds = $project->getEnvironmentsNamesByBranch($branch);
- // use base branch from project
- if (!empty($environmentIds)) {
- $duplicates = [];
- foreach ($environmentIds as $environmentId) {
- if (!in_array($environmentId, $ignoreEnvironments, true) ||
- ($tag && !in_array($tag, $ignoreTags, true))) {
- // If not, create a new build job for it:
- $build = $this->buildService->createBuild(
- $project,
- $environmentId,
- $commitId,
- $project->getDefaultBranch(),
- $tag,
- $committer,
- $commitMessage,
- (int)$source,
- null,
- $extra
- );
-
- $createdBuilds[] = [
- 'id' => $build->getID(),
- 'environment' => $environmentId,
- ];
- } else {
- $duplicates[] = \array_search($environmentId, $ignoreEnvironments, true);
- }
+ $createdBuilds = [];
+
+ /** @var EnvironmentStore $environmentStore */
+ $environmentStore = $this->storeRegistry->get('Environment');
+ $environmentObject = $environmentStore->getByNameAndProjectId($environment, $project->getId());
+ if ($environment && $environmentObject) {
+ if (
+ !\in_array($environmentObject->getId(), $ignoreEnvironments, true) ||
+ ($tag && !\in_array($tag, $ignoreTags, true))
+ ) {
+ // If not, create a new build job for it:
+ $build = $this->buildService->createBuild(
+ $project,
+ $environmentObject->getId(),
+ $commitId,
+ $project->getDefaultBranch(),
+ $tag,
+ $committer,
+ $commitMessage,
+ (int)$source,
+ null,
+ $extra
+ );
+
+ $createdBuilds[] = [
+ 'id' => $build->getID(),
+ 'environment' => $environmentObject->getId(),
+ ];
+ } else {
+ $duplicates[] = \array_search($environmentObject->getId(), $ignoreEnvironments, true);
}
+
if (!empty($createdBuilds)) {
if (empty($duplicates)) {
return ['status' => 'ok', 'builds' => $createdBuilds];
@@ -171,28 +183,84 @@ protected function createBuild(
return [
'status' => 'ok',
'builds' => $createdBuilds,
- 'message' => sprintf(
+ 'message' => \sprintf(
'For this commit some builds already exists (%s)',
- implode(', ', $duplicates)
+ \implode(', ', $duplicates)
)
];
}
} else {
return [
'status' => 'ignored',
- 'message' => sprintf(
+ 'message' => \sprintf(
'For this commit already created builds (%s)',
- implode(', ', $duplicates)
+ \implode(', ', $duplicates)
)
];
}
} else {
- return ['status' => 'ignored', 'message' => 'Branch not assigned to any environment'];
+ $environmentIds = $project->getEnvironmentsNamesByBranch($branch);
+ // use base branch from project
+ if (!empty($environmentIds)) {
+ $duplicates = [];
+ foreach ($environmentIds as $environmentId) {
+ if (
+ !\in_array($environmentId, $ignoreEnvironments, true) ||
+ ($tag && !\in_array($tag, $ignoreTags, true))
+ ) {
+ // If not, create a new build job for it:
+ $build = $this->buildService->createBuild(
+ $project,
+ (int)$environmentId,
+ $commitId,
+ $project->getDefaultBranch(),
+ $tag,
+ $committer,
+ $commitMessage,
+ $source,
+ null,
+ $extra
+ );
+
+ $createdBuilds[] = [
+ 'id' => $build->getID(),
+ 'environment' => $environmentId,
+ ];
+ } else {
+ $duplicates[] = \array_search($environmentId, $ignoreEnvironments, true);
+ }
+ }
+
+ if (!empty($createdBuilds)) {
+ if (empty($duplicates)) {
+ return ['status' => 'ok', 'builds' => $createdBuilds];
+ } else {
+ return [
+ 'status' => 'ok',
+ 'builds' => $createdBuilds,
+ 'message' => \sprintf(
+ 'For this commit some builds already exists (%s)',
+ \implode(', ', $duplicates)
+ )
+ ];
+ }
+ } else {
+ return [
+ 'status' => 'ignored',
+ 'message' => \sprintf(
+ 'For this commit already created builds (%s)',
+ \implode(', ', $duplicates)
+ )
+ ];
+ }
+ } else {
+ return ['status' => 'ignored', 'message' => 'Branch not assigned to any environment'];
+ }
}
} else {
$environmentId = null;
- if (!in_array($environmentId, $ignoreEnvironments, true) ||
- ($tag && !in_array($tag, $ignoreTags, true))) {
+ if (!\in_array($environmentId, $ignoreEnvironments, true) ||
+ ($tag && !\in_array($tag, $ignoreTags, true))) {
$build = $this->buildService->createBuild(
$project,
null,
@@ -210,9 +278,9 @@ protected function createBuild(
} else {
return [
'status' => 'ignored',
- 'message' => sprintf(
+ 'message' => \sprintf(
'Duplicate of build #%d',
- array_search($environmentId, $ignoreEnvironments, true)
+ \array_search($environmentId, $ignoreEnvironments, true)
),
];
}
@@ -222,97 +290,122 @@ protected function createBuild(
/**
* Fetch a project and check its type.
*
- * @param int $projectId id or title of project
- *
- * @return Project
- *
* @throws Exception If the project does not exist or is not of the expected type.
*/
- protected function fetchProject($projectId, array $expectedType)
+ protected function fetchProject(int $projectId, array $expectedType): Project
{
- if (empty($projectId)) {
- throw new Exception('Project does not exist: ' . $projectId);
+ if (!$projectId) {
+ throw new NotFoundException('Project does not exist: ' . $projectId);
}
- if (is_numeric($projectId)) {
- $project = $this->projectStore->getById((int)$projectId);
- } else {
- $projects = $this->projectStore->getByTitle($projectId, 2);
- if ($projects['count'] < 1) {
- throw new Exception('Project does not found: ' . $projectId);
- }
- if ($projects['count'] > 1) {
- throw new Exception('Project id is ambiguous: ' . $projectId);
- }
- $project = reset($projects['items']);
- }
+ /** @var Project $project */
+ $project = $this->projectStore->getById($projectId);
- if (!in_array($project->getType(), $expectedType, true)) {
- throw new Exception('Wrong project type: ' . $project->getType());
+ if (!\in_array($project->getType(), $expectedType, true)) {
+ throw new NotFoundException('Wrong project type: ' . $project->getType());
}
return $project;
}
+ protected function logWebhookRequest(
+ int $projectId,
+ string $webhookType,
+ string $payload
+ ): void {
+ try {
+ if ($this->logRequests) {
+ $webhookRequest = new WebhookRequest($this->storeRegistry);
+
+ $webhookRequest->setProjectId($projectId);
+ $webhookRequest->setWebhookType($webhookType);
+ $webhookRequest->setPayload($payload);
+ $webhookRequest->setCreateDate(new \DateTime());
+
+ $this->webhookRequestStore->save($webhookRequest);
+ }
+ } catch (\Throwable $e) {
+ }
+ }
+
/**
* Called by POSTing to /webhook/git/?branch=&commit=
*
- * @param int $projectId
- *
- * @return array
- *
* @throws Exception
*/
- public function git($projectId)
+ public function git(int $projectId): array
{
$project = $this->fetchProject($projectId, [
Project::TYPE_LOCAL,
Project::TYPE_GIT,
+ Project::TYPE_GITHUB,
]);
- $branch = $this->getParam('branch', $project->getDefaultBranch());
- $commit = $this->getParam('commit');
- $commitMessage = $this->getParam('message');
- $committer = $this->getParam('committer');
+
+ $payload = [
+ 'branch' => $this->getParam('branch', $project->getDefaultBranch()),
+ 'environment' => $this->getParam('environment'),
+ 'commit' => (string)$this->getParam('commit', ''),
+ 'commit_message' => (string)$this->getParam('message', ''),
+ 'committer' => (string)$this->getParam('committer', ''),
+ ];
+ $payloadJson = \json_encode($payload);
+
+ $this->logWebhookRequest(
+ $project->getId(),
+ WebhookRequest::WEBHOOK_TYPE_GIT,
+ $payloadJson
+ );
return $this->createBuild(
Build::SOURCE_WEBHOOK_PUSH,
$project,
- $commit,
- $branch,
+ $payload['commit'],
+ $payload['branch'],
null,
- $committer,
- $commitMessage
+ $payload['committer'],
+ $payload['commit_message'],
+ null,
+ $payload['environment']
);
}
/**
* Called by POSTing to /webhook/hg/?branch=&commit=
*
- * @param int $projectId
- *
- * @return array
- *
* @throws Exception
*/
- public function hg($projectId)
+ public function hg(int $projectId): array
{
$project = $this->fetchProject($projectId, [
Project::TYPE_LOCAL,
Project::TYPE_HG,
]);
- $branch = $this->getParam('branch', $project->getDefaultBranch());
- $commit = $this->getParam('commit');
- $commitMessage = $this->getParam('message');
- $committer = $this->getParam('committer');
+
+ $payload = [
+ 'branch' => $this->getParam('branch', $project->getDefaultBranch()),
+ 'environment' => $this->getParam('environment'),
+ 'commit' => (string)$this->getParam('commit', ''),
+ 'commit_message' => (string)$this->getParam('message', ''),
+ 'committer' => (string)$this->getParam('committer', ''),
+ ];
+ $payloadJson = \json_encode($payload);
+
+ $this->logWebhookRequest(
+ $project->getId(),
+ WebhookRequest::WEBHOOK_TYPE_HG,
+ $payloadJson
+ );
return $this->createBuild(
Build::SOURCE_WEBHOOK_PUSH,
$project,
- $commit,
- $branch,
+ $payload['commit'],
+ $payload['branch'],
null,
- $committer,
- $commitMessage
+ $payload['committer'],
+ $payload['commit_message'],
+ null,
+ $payload['environment']
);
}
@@ -321,43 +414,48 @@ public function hg($projectId)
*
* @author Sylvain Lévesque
*
- * @param int $projectId
- *
- * @return array
- *
* @throws Exception
*/
- public function svn($projectId)
+ public function svn(int $projectId): array
{
- $project = $this->fetchProject($projectId, [
+ $project = $this->fetchProject($projectId, [
Project::TYPE_SVN
]);
- $branch = $this->getParam('branch', $project->getDefaultBranch());
- $commit = $this->getParam('commit');
- $commitMessage = $this->getParam('message');
- $committer = $this->getParam('committer');
+
+ $payload = [
+ 'branch' => $this->getParam('branch', $project->getDefaultBranch()),
+ 'environment' => $this->getParam('environment'),
+ 'commit' => (string)$this->getParam('commit', ''),
+ 'commit_message' => (string)$this->getParam('message', ''),
+ 'committer' => (string)$this->getParam('committer', ''),
+ ];
+ $payloadJson = \json_encode($payload);
+
+ $this->logWebhookRequest(
+ $project->getId(),
+ WebhookRequest::WEBHOOK_TYPE_SVN,
+ $payloadJson
+ );
return $this->createBuild(
Build::SOURCE_WEBHOOK_PUSH,
$project,
- $commit,
- $branch,
+ $payload['commit'],
+ $payload['branch'],
+ null,
+ $payload['committer'],
+ $payload['commit_message'],
null,
- $committer,
- $commitMessage
+ $payload['environment']
);
}
/**
* Called by Bitbucket.
*
- * @param int $projectId
- *
- * @return array
- *
* @throws Exception
*/
- public function bitbucket($projectId)
+ public function bitbucket(int $projectId): array
{
$project = $this->fetchProject($projectId, [
Project::TYPE_BITBUCKET,
@@ -368,11 +466,26 @@ public function bitbucket($projectId)
]);
// Support both old services and new webhooks
- if ($payload = $this->getParam('payload')) {
- return $this->bitbucketService(json_decode($payload, true), $project);
+ if ($payloadJson = $this->getParam('payload')) {
+ $this->logWebhookRequest(
+ $project->getId(),
+ WebhookRequest::WEBHOOK_TYPE_BITBUCKET,
+ $payloadJson
+ );
+
+ return $this->bitbucketService(\json_decode($payloadJson, true), $project);
}
- $payload = json_decode(file_get_contents("php://input"), true);
+ $payloadJson = \file_get_contents("php://input");
+ $payload = \json_decode($payloadJson, true);
+
+ if ($payloadJson) {
+ $this->logWebhookRequest(
+ $project->getId(),
+ WebhookRequest::WEBHOOK_TYPE_BITBUCKET,
+ $payloadJson
+ );
+ }
// Handle Pull Request webhooks:
if (!empty($payload['pullrequest'])) {
@@ -398,10 +511,8 @@ public function bitbucket($projectId)
/**
* Handle the payload when Bitbucket sends a commit webhook.
- *
- * @return array
*/
- protected function bitbucketCommitRequest(Project $project, array $payload)
+ protected function bitbucketCommitRequest(Project $project, array $payload): array
{
$results = [];
$status = 'failed';
@@ -409,10 +520,10 @@ protected function bitbucketCommitRequest(Project $project, array $payload)
if (!empty($commit['new'])) {
try {
$email = $commit['new']['target']['author']['raw'];
- if (strpos($email, '>') !== false) {
- // In order not to loose email if it is RAW, w/o "<>" symbols
- $email = substr($email, 0, strpos($email, '>'));
- $email = substr($email, strpos($email, '<') + 1);
+ if (\strpos($email, '>') !== false) {
+ // In order not to lose email if it is RAW, w/o "<>" symbols
+ $email = \substr($email, 0, \strpos($email, '>'));
+ $email = \substr($email, \strpos($email, '<') + 1);
}
$results[$commit['new']['target']['hash']] = $this->createBuild(
@@ -425,7 +536,7 @@ protected function bitbucketCommitRequest(Project $project, array $payload)
$commit['new']['target']['message']
);
$status = 'ok';
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$results[$commit['new']['target']['hash']] = ['status' => 'failed', 'error' => $ex->getMessage()];
}
}
@@ -437,15 +548,13 @@ protected function bitbucketCommitRequest(Project $project, array $payload)
/**
* Handle the payload when Bitbucket sends a Pull Request webhook.
*
- * @return array
- *
* @throws Exception
*/
- protected function bitbucketPullRequest(Project $project, array $payload)
+ protected function bitbucketPullRequest(Project $project, array $payload): array
{
- $triggerType = trim($_SERVER['HTTP_X_EVENT_KEY']);
+ $triggerType = \trim($_SERVER['HTTP_X_EVENT_KEY']);
- if (!array_key_exists(
+ if (!\array_key_exists(
$triggerType,
BitbucketBuild::$pullrequestTriggersToSources
)) {
@@ -455,11 +564,11 @@ protected function bitbucketPullRequest(Project $project, array $payload)
];
}
- $username = Config::getInstance()->get('php-censor.bitbucket.username');
- $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password');
+ $username = $this->configuration->get('php-censor.bitbucket.username');
+ $appPassword = $this->configuration->get('php-censor.bitbucket.app_password');
if (empty($username) || empty($appPassword)) {
- throw new Exception('Please provide Username and App Password of your Bitbucket account.');
+ throw new ForbiddenException('Please provide Username and App Password of your Bitbucket account.');
}
$commitsUrl = $payload['pullrequest']['links']['commits']['href'];
@@ -472,16 +581,16 @@ protected function bitbucketPullRequest(Project $project, array $payload)
// Check we got a success response:
if ($httpStatus < 200 || $httpStatus >= 300) {
- throw new Exception('Could not get commits, failed API request.');
+ throw new RuntimeException('Could not get commits, failed API request.');
}
$results = [];
$status = 'failed';
- $commits = json_decode($commitsResponse->getBody(), true)['values'];
+ $commits = \json_decode((string)$commitsResponse->getBody(), true)['values'];
foreach ($commits as $commit) {
// Skip all but the current HEAD commit ID:
$id = $commit['hash'];
- if (strpos($id, $payload['pullrequest']['source']['commit']['hash']) !== 0) {
+ if (\strpos($id, $payload['pullrequest']['source']['commit']['hash']) !== 0) {
$results[$id] = ['status' => 'ignored', 'message' => 'not branch head'];
continue;
@@ -490,10 +599,10 @@ protected function bitbucketPullRequest(Project $project, array $payload)
try {
$branch = $payload['pullrequest']['destination']['branch']['name'];
$committer = $commit['author']['raw'];
- if (strpos($committer, '>') !== false) {
- // In order not to loose email if it is RAW, w/o "<>" symbols
- $committer = substr($committer, 0, strpos($committer, '>'));
- $committer = substr($committer, strpos($committer, '<') + 1);
+ if (\strpos($committer, '>') !== false) {
+ // In order not to lose email if it is RAW, w/o "<>" symbols
+ $committer = \substr($committer, 0, \strpos($committer, '>'));
+ $committer = \substr($committer, \strpos($committer, '<') + 1);
}
$message = $commit['message'];
@@ -514,7 +623,7 @@ protected function bitbucketPullRequest(Project $project, array $payload)
$extra
);
$status = 'ok';
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$results[$id] = ['status' => 'failed', 'error' => $ex->getMessage()];
}
}
@@ -525,15 +634,13 @@ protected function bitbucketPullRequest(Project $project, array $payload)
/**
* Handle the payload when Bitbucket Server sends a Pull Request webhook.
*
- * @return array
- *
* @throws Exception
*/
- protected function bitbucketSvrPullRequest(Project $project, array $payload)
+ protected function bitbucketSvrPullRequest(Project $project, array $payload): array
{
- $triggerType = trim($_SERVER['HTTP_X_EVENT_KEY']);
+ $triggerType = \trim($_SERVER['HTTP_X_EVENT_KEY']);
- if (!array_key_exists(
+ if (!\array_key_exists(
$triggerType,
BitbucketServerBuild::$pullrequestTriggersToSources
)) {
@@ -568,7 +675,7 @@ protected function bitbucketSvrPullRequest(Project $project, array $payload)
$extra
);
$status = 'ok';
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$results[$id] = ['status' => 'failed', 'error' => $ex->getMessage()];
}
@@ -577,18 +684,16 @@ protected function bitbucketSvrPullRequest(Project $project, array $payload)
/**
* Bitbucket POST service.
- *
- * @return array
*/
- protected function bitbucketService(array $payload, Project $project)
+ protected function bitbucketService(array $payload, Project $project): array
{
$results = [];
$status = 'failed';
foreach ($payload['commits'] as $commit) {
try {
$email = $commit['raw_author'];
- $email = substr($email, 0, strpos($email, '>'));
- $email = substr($email, strpos($email, '<') + 1);
+ $email = \substr($email, 0, \strpos($email, '>'));
+ $email = \substr($email, \strpos($email, '<') + 1);
$results[$commit['raw_node']] = $this->createBuild(
Build::SOURCE_WEBHOOK_PUSH,
@@ -600,7 +705,7 @@ protected function bitbucketService(array $payload, Project $project)
$commit['message']
);
$status = 'ok';
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$results[$commit['raw_node']] = ['status' => 'failed', 'error' => $ex->getMessage()];
}
}
@@ -609,13 +714,9 @@ protected function bitbucketService(array $payload, Project $project)
}
/**
- * @param int $projectId
- *
- * @return array
- *
* @throws Exception
*/
- public function github($projectId)
+ public function github(int $projectId): array
{
$project = $this->fetchProject($projectId, [
Project::TYPE_GITHUB,
@@ -624,10 +725,12 @@ public function github($projectId)
switch ($_SERVER['CONTENT_TYPE']) {
case 'application/json':
- $payload = json_decode(file_get_contents('php://input'), true);
+ $payloadJson = \file_get_contents('php://input');
+
break;
case 'application/x-www-form-urlencoded':
- $payload = json_decode($this->getParam('payload'), true);
+ $payloadJson = $this->getParam('payload');
+
break;
default:
return [
@@ -637,13 +740,23 @@ public function github($projectId)
];
}
+ if ($payloadJson) {
+ $this->logWebhookRequest(
+ $project->getId(),
+ WebhookRequest::WEBHOOK_TYPE_GITHUB,
+ $payloadJson
+ );
+ }
+
+ $payload = \json_decode($payloadJson, true);
+
// Handle Pull Request webhooks:
- if (array_key_exists('pull_request', $payload)) {
+ if (\array_key_exists('pull_request', $payload)) {
return $this->githubPullRequest($project, $payload);
}
// Handle Push (and Tag) webhooks:
- if (array_key_exists('head_commit', $payload)) {
+ if (\array_key_exists('head_commit', $payload)) {
return $this->githubCommitRequest($project, $payload);
}
@@ -652,19 +765,17 @@ public function github($projectId)
/**
* Handle the payload when Github sends a commit webhook.
- *
- * @return array
*/
- protected function githubCommitRequest(Project $project, array $payload)
+ protected function githubCommitRequest(Project $project, array $payload): array
{
// Github sends a payload when you close a pull request with a non-existent commit. We don't want this.
- if (array_key_exists('after', $payload) &&
+ if (\array_key_exists('after', $payload) &&
$payload['after'] === '0000000000000000000000000000000000000000') {
return ['status' => 'ignored'];
}
if (isset($payload['head_commit']) && $payload['head_commit']) {
- $isTag = (substr($payload['ref'], 0, 10) == 'refs/tags/') ? true : false;
+ $isTag = (\substr($payload['ref'], 0, 10) === 'refs/tags/') ? true : false;
$commit = $payload['head_commit'];
$results = [];
$status = 'failed';
@@ -675,11 +786,11 @@ protected function githubCommitRequest(Project $project, array $payload)
try {
$tag = null;
if ($isTag) {
- $tag = str_replace('refs/tags/', '', $payload['ref']);
- $branch = str_replace('refs/heads/', '', $payload['base_ref']);
+ $tag = \str_replace('refs/tags/', '', $payload['ref']);
+ $branch = \str_replace('refs/heads/', '', $payload['base_ref']);
$committer = $payload['pusher']['email'];
} else {
- $branch = str_replace('refs/heads/', '', $payload['ref']);
+ $branch = \str_replace('refs/heads/', '', $payload['ref']);
$committer = $commit['committer']['email'];
}
@@ -694,7 +805,7 @@ protected function githubCommitRequest(Project $project, array $payload)
);
$status = 'ok';
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$results[$commit['id']] = ['status' => 'failed', 'error' => $ex->getMessage()];
}
}
@@ -708,15 +819,13 @@ protected function githubCommitRequest(Project $project, array $payload)
/**
* Handle the payload when Github sends a Pull Request webhook.
*
- * @return array
- *
* @throws Exception
*/
- protected function githubPullRequest(Project $project, array $payload)
+ protected function githubPullRequest(Project $project, array $payload): array
{
- $triggerType = trim($payload['action']);
+ $triggerType = \trim($payload['action']);
- if (!array_key_exists(
+ if (!\array_key_exists(
$triggerType,
GithubBuild::$pullrequestTriggersToSources
)) {
@@ -727,7 +836,7 @@ protected function githubPullRequest(Project $project, array $payload)
}
$headers = [];
- $token = Config::getInstance()->get('php-censor.github.token');
+ $token = $this->configuration->get('php-censor.github.token');
if (!empty($token)) {
$headers['Authorization'] = 'token ' . $token;
@@ -736,7 +845,7 @@ protected function githubPullRequest(Project $project, array $payload)
$url = $payload['pull_request']['commits_url'];
//for large pull requests, allow grabbing more then the default number of commits
- $customPerPage = Config::getInstance()->get('php-censor.github.per_page');
+ $customPerPage = $this->configuration->get('php-censor.github.per_page');
$params = [];
if ($customPerPage) {
$params['per_page'] = $customPerPage;
@@ -747,16 +856,16 @@ protected function githubPullRequest(Project $project, array $payload)
'headers' => $headers,
'query' => $params,
]);
- $status = (int)$response->getStatusCode();
+ $status = $response->getStatusCode();
// Check we got a success response:
if ($status < 200 || $status >= 300) {
- throw new Exception('Could not get commits, failed API request.');
+ throw new RuntimeException('Could not get commits, failed API request.');
}
$results = [];
$status = 'failed';
- $commits = json_decode($response->getBody(), true);
+ $commits = \json_decode((string)$response->getBody(), true);
foreach ($commits as $commit) {
// Skip all but the current HEAD commit ID:
$id = $commit['sha'];
@@ -767,7 +876,7 @@ protected function githubPullRequest(Project $project, array $payload)
}
try {
- $branch = str_replace('refs/heads/', '', $payload['pull_request']['base']['ref']);
+ $branch = \str_replace('refs/heads/', '', $payload['pull_request']['base']['ref']);
$committer = $commit['commit']['author']['email'];
$message = $commit['commit']['message'];
@@ -788,7 +897,7 @@ protected function githubPullRequest(Project $project, array $payload)
$extra
);
$status = 'ok';
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$results[$id] = ['status' => 'failed', 'error' => $ex->getMessage()];
}
}
@@ -799,24 +908,29 @@ protected function githubPullRequest(Project $project, array $payload)
/**
* Called by Gitlab Webhooks:
*
- * @param int $projectId
- *
- * @return array
- *
* @throws Exception
*/
- public function gitlab($projectId)
+ public function gitlab(int $projectId): array
{
$project = $this->fetchProject($projectId, [
Project::TYPE_GITLAB,
Project::TYPE_GIT,
]);
- $payloadString = file_get_contents("php://input");
- $payload = json_decode($payloadString, true);
+ $payloadJson = \file_get_contents("php://input");
+
+ if ($payloadJson) {
+ $this->logWebhookRequest(
+ $project->getId(),
+ WebhookRequest::WEBHOOK_TYPE_GITLAB,
+ $payloadJson
+ );
+ }
+
+ $payload = \json_decode($payloadJson, true);
// build on merge request events
- if (isset($payload['object_kind']) && $payload['object_kind'] == 'merge_request') {
+ if (isset($payload['object_kind']) && $payload['object_kind'] === 'merge_request') {
$attributes = $payload['object_attributes'];
if ($attributes['state'] === 'opened' || $attributes['state'] === 'reopened') {
$branch = $attributes['source_branch'];
@@ -836,15 +950,15 @@ public function gitlab($projectId)
}
// build on push events
- if (isset($payload['commits']) && is_array($payload['commits'])) {
+ if (isset($payload['commits']) && \is_array($payload['commits'])) {
// If we have a list of commits, then add them all as builds to be tested:
$results = [];
$status = 'failed';
- $commit = end($payload['commits']);
+ $commit = \end($payload['commits']);
try {
- $branch = str_replace('refs/heads/', '', $payload['ref']);
+ $branch = \str_replace('refs/heads/', '', $payload['ref']);
$committer = $commit['author']['email'];
$results[$commit['id']] = $this->createBuild(
Build::SOURCE_WEBHOOK_PUSH,
@@ -856,7 +970,7 @@ public function gitlab($projectId)
$commit['message']
);
$status = 'ok';
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$results[$commit['id']] = ['status' => 'failed', 'error' => $ex->getMessage()];
}
@@ -869,11 +983,9 @@ public function gitlab($projectId)
/**
* @param string $projectId
*
- * @return array
- *
* @throws Exception
*/
- public function gogs($projectId)
+ public function gogs(int $projectId): array
{
$project = $this->fetchProject($projectId, [
Project::TYPE_GOGS,
@@ -886,19 +998,30 @@ public function gogs($projectId)
switch ($contentType) {
case 'application/x-www-form-urlencoded':
- $payload = json_decode($this->getParam('payload'), true);
+ $payloadJson = $this->getParam('payload');
+
break;
case 'application/json':
default:
- $payload = json_decode(file_get_contents('php://input'), true);
+ $payloadJson = \file_get_contents('php://input');
}
+ if ($payloadJson) {
+ $this->logWebhookRequest(
+ $project->getId(),
+ WebhookRequest::WEBHOOK_TYPE_GOGS,
+ $payloadJson
+ );
+ }
+
+ $payload = \json_decode($payloadJson, true);
+
// Handle Push web hooks:
- if (array_key_exists('commits', $payload)) {
+ if (\array_key_exists('commits', $payload)) {
return $this->gogsCommitRequest($project, $payload);
}
- if (array_key_exists('pull_request', $payload)) {
+ if (\array_key_exists('pull_request', $payload)) {
return $this->gogsPullRequest($project, $payload);
}
@@ -907,18 +1030,16 @@ public function gogs($projectId)
/**
* Handle the payload when Gogs sends a commit webhook.
- *
- * @return array
*/
- protected function gogsCommitRequest(Project $project, array $payload)
+ protected function gogsCommitRequest(Project $project, array $payload): array
{
- if (isset($payload['commits']) && is_array($payload['commits'])) {
+ if (isset($payload['commits']) && \is_array($payload['commits'])) {
// If we have a list of commits, then add them all as builds to be tested:
$results = [];
$status = 'failed';
foreach ($payload['commits'] as $commit) {
try {
- $branch = str_replace('refs/heads/', '', $payload['ref']);
+ $branch = \str_replace('refs/heads/', '', $payload['ref']);
$committer = $commit['author']['email'];
$results[$commit['id']] = $this->createBuild(
Build::SOURCE_WEBHOOK_PUSH,
@@ -930,7 +1051,7 @@ protected function gogsCommitRequest(Project $project, array $payload)
$commit['message']
);
$status = 'ok';
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$results[$commit['id']] = ['status' => 'failed', 'error' => $ex->getMessage()];
}
}
@@ -944,11 +1065,9 @@ protected function gogsCommitRequest(Project $project, array $payload)
/**
* Handle the payload when Gogs sends a pull request webhook.
*
- * @return array
- *
* @throws InvalidArgumentException
*/
- protected function gogsPullRequest(Project $project, array $payload)
+ protected function gogsPullRequest(Project $project, array $payload): array
{
$pullRequest = $payload['pull_request'];
$headBranch = $pullRequest['head_branch'];
@@ -961,21 +1080,21 @@ protected function gogsPullRequest(Project $project, array $payload)
$activeStates = ['open'];
$inactiveStates = ['closed'];
- if (!in_array($action, $activeActions, true) && !in_array($action, $inactiveActions, true)) {
+ if (!\in_array($action, $activeActions, true) && !\in_array($action, $inactiveActions, true)) {
return ['status' => 'ignored', 'message' => 'Action ' . $action . ' ignored'];
}
- if (!in_array($state, $activeStates, true) && !in_array($state, $inactiveStates, true)) {
+ if (!\in_array($state, $activeStates, true) && !\in_array($state, $inactiveStates, true)) {
return ['status' => 'ignored', 'message' => 'State ' . $state . ' ignored'];
}
$envs = [];
// Get environment form labels
- if (in_array($action, $activeActions, true) && in_array($state, $activeStates, true)) {
- if (isset($pullRequest['labels']) && is_array($pullRequest['labels'])) {
+ if (\in_array($action, $activeActions, true) && \in_array($state, $activeStates, true)) {
+ if (isset($pullRequest['labels']) && \is_array($pullRequest['labels'])) {
foreach ($pullRequest['labels'] as $label) {
- if (strpos($label['name'], 'env:') === 0) {
- $envs[] = substr($label['name'], 4);
+ if (\strpos($label['name'], 'env:') === 0) {
+ $envs[] = \substr($label['name'], 4);
}
}
}
@@ -983,11 +1102,11 @@ protected function gogsPullRequest(Project $project, array $payload)
$envsUpdated = [];
$envObjects = $project->getEnvironmentsObjects();
- $store = Factory::getStore('Environment');
+ $store = $this->storeRegistry->get('Environment');
foreach ($envObjects['items'] as $environment) {
$branches = $environment->getBranches();
- if (in_array($environment->getName(), $envs, true)) {
- if (!in_array($headBranch, $branches, true)) {
+ if (\in_array($environment->getName(), $envs, true)) {
+ if (!\in_array($headBranch, $branches, true)) {
// Add branch to environment
$branches[] = $headBranch;
$environment->setBranches($branches);
@@ -995,9 +1114,9 @@ protected function gogsPullRequest(Project $project, array $payload)
$envsUpdated[] = $environment->getId();
}
} else {
- if (in_array($headBranch, $branches, true)) {
+ if (\in_array($headBranch, $branches, true)) {
// Remove branch from environment
- $branches = array_diff($branches, [$headBranch]);
+ $branches = \array_diff($branches, [$headBranch]);
$environment->setBranches($branches);
$store->save($environment);
$envsUpdated[] = $environment->getId();
diff --git a/src/Controller/WidgetAllProjectsController.php b/src/Controller/WidgetAllProjectsController.php
index b805fb5f3..72e4c2128 100644
--- a/src/Controller/WidgetAllProjectsController.php
+++ b/src/Controller/WidgetAllProjectsController.php
@@ -1,57 +1,50 @@
*/
class WidgetAllProjectsController extends WebController
{
- /**
- * @var BuildStore
- */
- protected $buildStore;
+ protected BuildStore $buildStore;
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ protected ProjectStore $projectStore;
- /**
- * @var ProjectGroupStore
- */
- protected $groupStore;
+ protected ProjectGroupStore $groupStore;
/**
* Initialise the controller, set up stores and services.
*/
- public function init()
+ public function init(): void
{
parent::init();
- $this->buildStore = Factory::getStore('Build');
- $this->projectStore = Factory::getStore('Project');
- $this->groupStore = Factory::getStore('ProjectGroup');
+ $this->buildStore = $this->storeRegistry->get('Build');
+ $this->projectStore = $this->storeRegistry->get('Project');
+ $this->groupStore = $this->storeRegistry->get('ProjectGroup');
}
/**
- * @return Response
- *
* @throws Exception
*/
- public function index()
+ public function index(): Response
{
$this->view->groups = $this->getGroupInfo();
@@ -66,11 +59,9 @@ public function index()
*
* @param Project[] $projects
*
- * @return string
- *
* @throws Exception
*/
- protected function getSummaryHtml($projects)
+ protected function getSummaryHtml(array $projects): string
{
$summaryBuilds = [];
$successes = [];
@@ -109,11 +100,9 @@ protected function getSummaryHtml($projects)
/**
* Get a summary of the project groups we have, and what projects they have in them.
*
- * @return array
- *
* @throws Exception
*/
- protected function getGroupInfo()
+ protected function getGroupInfo(): array
{
$rtn = [];
$groups = $this->groupStore->getWhere([], 100, 0, ['title' => 'ASC']);
@@ -132,13 +121,9 @@ protected function getGroupInfo()
}
/**
- * @param int $projectId
- *
- * @return Response
- *
* @throws HttpException
*/
- public function update($projectId)
+ public function update(int $projectId): Response
{
$count = $this->buildStore->getWhere(
['project_id' => $projectId],
diff --git a/src/Controller/WidgetBuildErrorsController.php b/src/Controller/WidgetBuildErrorsController.php
index c3edc7bd6..184c7d664 100644
--- a/src/Controller/WidgetBuildErrorsController.php
+++ b/src/Controller/WidgetBuildErrorsController.php
@@ -1,45 +1,43 @@
*/
class WidgetBuildErrorsController extends WebController
{
- /**
- * @var BuildStore
- */
- protected $buildStore;
+ protected BuildStore $buildStore;
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ protected ProjectStore $projectStore;
/**
* Initialise the controller, set up stores and services.
*/
- public function init()
+ public function init(): void
{
parent::init();
- $this->buildStore = Factory::getStore('Build');
- $this->projectStore = Factory::getStore('Project');
+ $this->buildStore = $this->storeRegistry->get('Build');
+ $this->projectStore = $this->storeRegistry->get('Project');
}
/**
* Display dashboard.
*/
- public function index()
+ public function index(): Response
{
$view = new View('WidgetBuildErrors/update');
@@ -52,11 +50,9 @@ public function index()
}
/**
- * @return Response
- *
* @throws HttpException
*/
- public function update()
+ public function update(): Response
{
$response = new Response();
$response->setContent($this->renderAllProjectsLatestBuilds($this->view));
@@ -65,19 +61,15 @@ public function update()
}
/**
- * @param View $view
- *
- * @return string
- *
* @throws HttpException
*/
- protected function renderAllProjectsLatestBuilds($view)
+ protected function renderAllProjectsLatestBuilds(View $view): string
{
$builds = $this->buildStore->getAllProjectsLatestBuilds();
if (!empty($builds['projects'])) {
$view->builds = $builds['projects'];
- $projects = $this->projectStore->getByIds(array_keys($builds['projects']));
+ $projects = $this->projectStore->getByIds(\array_keys($builds['projects']));
$viewProjects = [];
foreach ($projects as $id => $project) {
diff --git a/src/Controller/WidgetLastBuildsController.php b/src/Controller/WidgetLastBuildsController.php
index 26efe1470..58814a661 100644
--- a/src/Controller/WidgetLastBuildsController.php
+++ b/src/Controller/WidgetLastBuildsController.php
@@ -1,48 +1,57 @@
*/
class WidgetLastBuildsController extends WebController
{
- /**
- * @var BuildStore
- */
- protected $buildStore;
+ protected BuildStore $buildStore;
+
+ protected BuildFactory $buildFactory;
/**
* Initialise the controller, set up stores and services.
*/
- public function init()
+ public function init(): void
{
parent::init();
- $this->buildStore = Factory::getStore('Build');
+ $this->buildStore = $this->storeRegistry->get('Build');
+
+ $this->buildFactory = new BuildFactory(
+ $this->configuration,
+ $this->storeRegistry
+ );
}
/**
* Display dashboard.
*/
- public function index()
+ public function index(): Response
{
$builds = $this->buildStore->getLatestBuilds(null, 10);
foreach ($builds as &$build) {
- $build = BuildFactory::getBuild($build);
+ $build = $this->buildFactory->getBuild($build);
}
$view = new View('WidgetLastBuilds/update');
$view->builds = $builds;
+ $view->environmentStore = $this->storeRegistry->get('Environment');
$this->view->timeline = $view->render();
$response = new Response();
@@ -51,18 +60,16 @@ public function index()
return $response;
}
- /**
- * @return Response
- */
- public function update()
+ public function update(): Response
{
$builds = $this->buildStore->getLatestBuilds(null, 10);
foreach ($builds as &$build) {
- $build = BuildFactory::getBuild($build);
+ $build = $this->buildFactory->getBuild($build);
}
- $this->view->builds = $builds;
+ $this->view->builds = $builds;
+ $this->view->environmentStore = $this->storeRegistry->get('Environment');
$response = new Response();
$response->setContent($this->view->render());
diff --git a/src/Database.php b/src/Database.php
deleted file mode 100644
index 85d1fbd89..000000000
--- a/src/Database.php
+++ /dev/null
@@ -1,218 +0,0 @@
- [],
- 'write' => []
- ];
-
- /**
- * @var array
- */
- protected static $connections = [
- 'read' => null,
- 'write' => null
- ];
-
- /**
- * @var array
- */
- protected static $dsn = [
- 'read' => '',
- 'write' => ''
- ];
-
- protected static $details = [];
-
- /**
- * @param string $table
- *
- * @return string
- */
- public function lastInsertIdExtended($table = null)
- {
- if ($table && self::POSTGRESQL_TYPE === $this->getAttribute(self::ATTR_DRIVER_NAME)) {
- return parent::lastInsertId('"' . $table . '_id_seq"');
- }
-
- return parent::lastInsertId();
- }
-
- protected static function init()
- {
- $config = Config::getInstance();
- $settings = $config->get('php-censor.database', []);
-
- self::$servers['read'] = $settings['servers']['read'];
- self::$servers['write'] = $settings['servers']['write'];
-
- self::$details['driver'] = $settings['type'];
- self::$details['db'] = $settings['name'];
- self::$details['user'] = $settings['username'];
- self::$details['pass'] = $settings['password'];
-
- self::$initialised = true;
- }
-
- /**
- * @param string $type
- *
- * @return Database
- *
- * @throws Exception
- */
- public static function getConnection($type = 'read')
- {
- if (!self::$initialised) {
- self::init();
- }
-
- if (is_null(self::$connections[$type])) {
- // Shuffle, so we pick a random server:
- $servers = self::$servers[$type];
- shuffle($servers);
-
- $connection = null;
-
- // Loop until we get a working connection:
- while (count($servers)) {
- // Pull the next server:
- $server = array_shift($servers);
-
- self::$dsn[$type] = self::$details['driver'] . ':host=' . $server['host'];
-
- if (self::$details['driver'] === 'pgsql') {
- if (!array_key_exists('pgsql-sslmode', $server)) {
- $server['pgsql-sslmode'] = 'prefer';
- }
-
- self::$dsn[$type] .= ';sslmode=' . $server['pgsql-sslmode'];
- }
-
- if (isset($server['port'])) {
- self::$dsn[$type] .= ';port=' . (int)$server['port'];
- }
-
- self::$dsn[$type] .= ';dbname=' . self::$details['db'];
-
- $pdoOptions = [
- PDO::ATTR_PERSISTENT => false,
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
- PDO::ATTR_TIMEOUT => 2,
- ];
-
- if (self::MYSQL_TYPE === self::$details['driver']) {
- $pdoOptions[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'";
- }
-
- // Try to connect:
- try {
- $connection = new self(
- self::$dsn[$type],
- self::$details['user'],
- self::$details['pass'],
- $pdoOptions
- );
- $connection->setType($type);
- } catch (PDOException $ex) {
- $connection = false;
- }
-
- // Opened a connection? Break the loop:
- if ($connection) {
- break;
- }
- }
-
- // No connection? Oh dear.
- if (!$connection && $type === 'read') {
- throw new Exception('Could not connect to any ' . $type . ' servers.');
- }
-
- self::$connections[$type] = $connection;
- }
-
- return self::$connections[$type];
- }
-
- /**
- * @return array
- */
- public function getDetails()
- {
- return self::$details;
- }
-
- /**
- * @return string
- */
- public function getDsn()
- {
- return self::$dsn[$this->type];
- }
-
- /**
- * @param string $type
- */
- public function setType($type)
- {
- $this->type = $type;
- }
-
- public static function reset()
- {
- self::$connections = ['read' => null, 'write' => null];
- self::$initialised = false;
- }
-
- /**
- * @param string $statement
- *
- * @return string
- */
- protected function quoteNames($statement)
- {
- $quote = '';
- if (self::MYSQL_TYPE === self::$details['driver']) {
- $quote = '`';
- } elseif (self::POSTGRESQL_TYPE === self::$details['driver']) {
- $quote = '"';
- }
-
- return preg_replace('/{{(.*?)}}/', ($quote . '\1' . $quote), $statement);
- }
-
- /**
- * @param string $statement
- *
- * @return PDOStatement
- */
- public function prepareCommon($statement, array $driverOptions = [])
- {
- return parent::prepare($this->quoteNames($statement), $driverOptions);
- }
-}
diff --git a/src/DatabaseConnection.php b/src/DatabaseConnection.php
new file mode 100644
index 000000000..4ae6fd821
--- /dev/null
+++ b/src/DatabaseConnection.php
@@ -0,0 +1,123 @@
+
+ */
+class DatabaseConnection
+{
+ private ?\PDO $pdoConnection = null;
+
+ private string $dsn;
+
+ private ?string $username;
+
+ private ?string $password;
+
+ private ?array $options;
+
+ private string $sequencePattern;
+
+ public function __construct(
+ string $dsn,
+ ?string $username = null,
+ ?string $password = null,
+ ?array $options = null,
+ string $sequencePattern = '%s_id_seq'
+ ) {
+ $this->sequencePattern = $sequencePattern;
+
+ $this->dsn = $dsn;
+ $this->username = $username;
+ $this->password = $password;
+ $this->options = $options;
+ }
+
+ public function getPdo(): \PDO
+ {
+ if (null === $this->pdoConnection) {
+ $this->pdoConnection = new \PDO($this->dsn, $this->username, $this->password, $this->options);
+ }
+
+ return $this->pdoConnection;
+ }
+
+ public function setPdo(\PDO $pdoConnection): self
+ {
+ $this->pdoConnection = $pdoConnection;
+
+ return $this;
+ }
+
+ public function quoteNames(string $query): string
+ {
+ $driver = $this->getPdo()->getAttribute(\PDO::ATTR_DRIVER_NAME);
+ $pattern = '\1';
+ if (DatabaseManager::MYSQL_TYPE === $driver) {
+ $pattern = '`\1`';
+ } elseif (DatabaseManager::POSTGRESQL_TYPE === $driver) {
+ $pattern = '"\1"';
+ }
+
+ return \preg_replace('#{{(.*?)}}#m', $pattern, $query);
+ }
+
+ public function lastInsertId(string $tableName): int
+ {
+ if (DatabaseManager::POSTGRESQL_TYPE === $this->getPdo()->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
+ return (int)$this->getPdo()->lastInsertId(\sprintf("\"{$this->sequencePattern}\"", $tableName));
+ }
+
+ return (int)$this->getPdo()->lastInsertId();
+ }
+
+ /**
+ * @return false|\PDOStatement
+ */
+ public function prepare(string $query, array $options = [])
+ {
+ return $this->getPdo()->prepare($this->quoteNames($query), $options);
+ }
+
+ /**
+ * @return false|int
+ */
+ public function exec(string $statement)
+ {
+ return $this->getPdo()->exec($this->quoteNames($statement));
+ }
+
+ /**
+ * @return false|\PDOStatement
+ */
+ public function query(string $statement)
+ {
+ return $this->getPdo()->query($this->quoteNames($statement));
+ }
+
+ public function beginTransaction(): bool
+ {
+ return $this->getPdo()->beginTransaction();
+ }
+
+ public function commit(): bool
+ {
+ return $this->getPdo()->commit();
+ }
+
+ public function rollBack(): bool
+ {
+ return $this->getPdo()->rollBack();
+ }
+
+ public function inTransaction(): bool
+ {
+ return $this->getPdo()->inTransaction();
+ }
+}
diff --git a/src/DatabaseManager.php b/src/DatabaseManager.php
new file mode 100644
index 000000000..5a74b770a
--- /dev/null
+++ b/src/DatabaseManager.php
@@ -0,0 +1,98 @@
+
+ */
+class DatabaseManager
+{
+ public const MYSQL_TYPE = 'mysql';
+ public const POSTGRESQL_TYPE = 'pgsql';
+
+ private ConfigurationInterface $configuration;
+
+ private array $connections = [
+ 'read' => null,
+ 'write' => null
+ ];
+
+ public function __construct(ConfigurationInterface $configuration)
+ {
+ $this->configuration = $configuration;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function getConnection(string $type = 'read'): DatabaseConnection
+ {
+ if (null === $this->connections[$type]) {
+ $servers = (array)$this->configuration->get("php-censor.database.servers.{$type}", []);
+ \shuffle($servers);
+
+ $connection = null;
+ while (\count($servers)) {
+ $server = \array_shift($servers);
+ $driver = $this->configuration->get('php-censor.database.type', self::POSTGRESQL_TYPE);
+ $dsn = $driver . ':host=' . $server['host'];
+
+ if (self::POSTGRESQL_TYPE === $driver) {
+ if (!\array_key_exists('pgsql-sslmode', $server)) {
+ $server['pgsql-sslmode'] = 'prefer';
+ }
+
+ $dsn .= ';sslmode=' . $server['pgsql-sslmode'];
+ }
+
+ if (isset($server['port'])) {
+ $dsn .= ';port=' . (int)$server['port'];
+ }
+
+ $dsn .= ';dbname=' . $this->configuration->get('php-censor.database.name', '');
+
+ $pdoOptions = [
+ \PDO::ATTR_PERSISTENT => false,
+ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
+ \PDO::ATTR_TIMEOUT => 2,
+ ];
+
+ if (self::MYSQL_TYPE === $driver) {
+ $pdoOptions[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'";
+ }
+
+ try {
+ $connection = new DatabaseConnection(
+ $dsn,
+ $this->configuration->get('php-censor.database.username', ''),
+ $this->configuration->get('php-censor.database.password', ''),
+ $pdoOptions
+ );
+ } catch (\PDOException $ex) {
+ $connection = false;
+ }
+
+ if ($connection) {
+ break;
+ }
+ }
+
+ if (!$connection) {
+ throw new RuntimeException('Could not connect to any ' . $type . ' servers.');
+ }
+
+ $this->connections[$type] = $connection;
+ }
+
+ return $this->connections[$type];
+ }
+}
diff --git a/src/Exception/Exception.php b/src/Exception/Exception.php
deleted file mode 100644
index 7de397015..000000000
--- a/src/Exception/Exception.php
+++ /dev/null
@@ -1,7 +0,0 @@
-
+ */
class HttpException extends Exception
{
- /**
- * @var int
- */
- protected $errorCode = 500;
-
- /**
- * @var string
- */
- protected $statusMessage = 'Internal Server Error';
-
- /**
- * @return int
- */
- public function getErrorCode()
+ protected int $errorCode = 500;
+
+ protected string $statusMessage = 'Internal Server Error';
+
+ public function getErrorCode(): int
{
return $this->errorCode;
}
- /**
- * @return string
- */
- public function getStatusMessage()
+ public function getStatusMessage(): string
{
return $this->statusMessage;
}
- /**
- * @return string
- */
- public function getHttpHeader()
+ public function getHttpHeader(): string
{
return 'HTTP/1.1 ' . $this->errorCode . ' ' . $this->statusMessage;
}
diff --git a/src/Exception/HttpException/BadRequestException.php b/src/Exception/HttpException/BadRequestException.php
index 27b01eee3..a8964f119 100644
--- a/src/Exception/HttpException/BadRequestException.php
+++ b/src/Exception/HttpException/BadRequestException.php
@@ -1,18 +1,20 @@
+ */
class BadRequestException extends HttpException
{
- /**
- * @var int
- */
- protected $errorCode = 400;
+ protected int $errorCode = 400;
- /**
- * @var string
- */
- protected $statusMessage = 'Bad Request';
+ protected string $statusMessage = 'Bad Request';
}
diff --git a/src/Exception/HttpException/ForbiddenException.php b/src/Exception/HttpException/ForbiddenException.php
index bca61f0b7..748b9b0d2 100644
--- a/src/Exception/HttpException/ForbiddenException.php
+++ b/src/Exception/HttpException/ForbiddenException.php
@@ -1,18 +1,20 @@
+ */
class ForbiddenException extends HttpException
{
- /**
- * @var int
- */
- protected $errorCode = 403;
+ protected int $errorCode = 403;
- /**
- * @var string
- */
- protected $statusMessage = 'Forbidden';
+ protected string $statusMessage = 'Forbidden';
}
diff --git a/src/Exception/HttpException/NotAuthorizedException.php b/src/Exception/HttpException/NotAuthorizedException.php
index 67f88f3c5..d41d09a87 100644
--- a/src/Exception/HttpException/NotAuthorizedException.php
+++ b/src/Exception/HttpException/NotAuthorizedException.php
@@ -1,18 +1,20 @@
+ */
class NotAuthorizedException extends HttpException
{
- /**
- * @var int
- */
- protected $errorCode = 401;
+ protected int $errorCode = 401;
- /**
- * @var string
- */
- protected $statusMessage = 'Not Authorized';
+ protected string $statusMessage = 'Not Authorized';
}
diff --git a/src/Exception/HttpException/NotFoundException.php b/src/Exception/HttpException/NotFoundException.php
index 4766cffda..4c3ea537b 100644
--- a/src/Exception/HttpException/NotFoundException.php
+++ b/src/Exception/HttpException/NotFoundException.php
@@ -1,18 +1,20 @@
+ */
class NotFoundException extends HttpException
{
- /**
- * @var int
- */
- protected $errorCode = 404;
+ protected int $errorCode = 404;
- /**
- * @var string
- */
- protected $statusMessage = 'Not Found';
+ protected string $statusMessage = 'Not Found';
}
diff --git a/src/Exception/HttpException/ServerErrorException.php b/src/Exception/HttpException/ServerErrorException.php
index 7568b4b7f..c5cdeee55 100644
--- a/src/Exception/HttpException/ServerErrorException.php
+++ b/src/Exception/HttpException/ServerErrorException.php
@@ -1,9 +1,17 @@
+ */
class ServerErrorException extends HttpException
{
}
diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php
deleted file mode 100644
index 17e85a0f4..000000000
--- a/src/Exception/InvalidArgumentException.php
+++ /dev/null
@@ -1,7 +0,0 @@
-
+ * @author Dmitry Khomutov
+ */
class Form extends FieldSet
{
- /**
- * @var string
- */
- protected $action = '';
+ protected string $action = '';
- /**
- * @var string
- */
- protected $method = 'POST';
+ protected string $method = 'POST';
- /**
- * @return string
- */
- public function getAction()
+ public function getAction(): string
{
return $this->action;
}
- /**
- * @param string $action
- */
- public function setAction($action)
+ public function setAction(string $action): void
{
$this->action = $action;
}
- /**
- * @return string
- */
- public function getMethod()
+ public function getMethod(): string
{
return $this->method;
}
- /**
- * @param string $method
- */
- public function setMethod($method)
+ public function setMethod(string $method): void
{
$this->method = $method;
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
$view->action = $this->getAction();
$view->method = $this->getMethod();
@@ -56,10 +47,7 @@ protected function onPreRender(View &$view)
parent::onPreRender($view);
}
- /**
- * @return string
- */
- public function __toString()
+ public function __toString(): string
{
return $this->render();
}
diff --git a/src/Form/ControlGroup.php b/src/Form/ControlGroup.php
index 37afe8e6f..9ec0bbc74 100644
--- a/src/Form/ControlGroup.php
+++ b/src/Form/ControlGroup.php
@@ -1,7 +1,16 @@
+ * @author Dmitry Khomutov
+ */
class ControlGroup extends FieldSet
{
}
diff --git a/src/Form/DataTransformer/DataTransformerInterface.php b/src/Form/DataTransformer/DataTransformerInterface.php
index bb54dd0ee..a8bccaeba 100644
--- a/src/Form/DataTransformer/DataTransformerInterface.php
+++ b/src/Form/DataTransformer/DataTransformerInterface.php
@@ -1,12 +1,20 @@
+ */
interface DataTransformerInterface
{
/** transform when putting the data into a form */
- public function transform($value);
+ public function transform(string $value): string;
/** reversen when getting the data from a form */
- public function reverseTransform($value);
+ public function reverseTransform(string $value): string;
}
diff --git a/src/Form/DataTransformer/Yaml.php b/src/Form/DataTransformer/Yaml.php
index 7a17d60d2..33413e265 100644
--- a/src/Form/DataTransformer/Yaml.php
+++ b/src/Form/DataTransformer/Yaml.php
@@ -1,17 +1,25 @@
+ */
class Yaml implements DataTransformerInterface
{
- public function transform($value)
+ public function transform(string $value): string
{
/* nothing to do here - only called before displaying values on FE */
return $value;
}
- public function reverseTransform($value)
+ public function reverseTransform(string $value): string
{
- return str_replace("\t", " ", $value);
+ return \str_replace("\t", " ", $value);
}
}
diff --git a/src/Form/Element.php b/src/Form/Element.php
index 5617ba573..c1f1dbc51 100644
--- a/src/Form/Element.php
+++ b/src/Form/Element.php
@@ -1,173 +1,113 @@
+ * @author Dmitry Khomutov
+ */
abstract class Element
{
- /**
- * @var string
- */
- protected $name;
-
- /**
- * @var string
- */
- protected $id;
-
- /**
- * @var string
- */
- protected $label;
-
- /**
- * @var string
- */
- protected $class;
-
- /**
- * @var string
- */
- protected $containerClass;
-
- /**
- * @var Element
- */
- protected $parent;
-
- /**
- * @param string|null $name
- */
- public function __construct($name = null)
+ protected string $name = '';
+
+ protected string $id = '';
+
+ protected string $label = '';
+
+ protected string $class = '';
+
+ protected string $containerClass = '';
+
+ protected ?Element $parent = null;
+
+ public function __construct(?string $name = null)
{
- if (!is_null($name)) {
+ if (!\is_null($name)) {
$this->setName($name);
}
}
- /**
- * @return string
- */
- public function getName()
+ public function getName(): string
{
return $this->name;
}
- /**
- * @param string $name
- *
- * @return $this
- */
- public function setName($name)
+ public function setName(string $name): self
{
- $this->name = strtolower(preg_replace('/([^a-zA-Z0-9_\-%])/', '', $name));
+ $this->name = \strtolower(\preg_replace('/([^a-zA-Z0-9_\-%])/', '', $name));
return $this;
}
- /**
- * @return string
- */
- public function getId()
+ public function getId(): string
{
return !$this->id
? ('element-' . $this->name)
: $this->id;
}
- /**
- * @param string $id
- *
- * @return $this
- */
- public function setId($id)
+ public function setId(string $id): self
{
$this->id = $id;
return $this;
}
- /**
- * @return string
- */
- public function getLabel()
+ public function getLabel(): string
{
return $this->label;
}
- /**
- * @param string $label
- *
- * @return $this
- */
- public function setLabel($label)
+ public function setLabel(string $label): self
{
$this->label = $label;
return $this;
}
- /**
- * @return string
- */
- public function getClass()
+ public function getClass(): string
{
return $this->class;
}
- /**
- * @param string $class
- *
- * @return $this
- */
- public function setClass($class)
+ public function setClass(string $class): self
{
$this->class = $class;
return $this;
}
- /**
- * @return string
- */
- public function getContainerClass()
+ public function getContainerClass(): string
{
return $this->containerClass;
}
- /**
- * @param string $class
- *
- * @return $this
- */
- public function setContainerClass($class)
+ public function setContainerClass(string $class): self
{
$this->containerClass = $class;
return $this;
}
- /**
- * @return $this
- */
- public function setParent(Element $parent)
+ public function setParent(Element $parent): self
{
$this->parent = $parent;
return $this;
}
- /**
- * @param string $viewFile
- *
- * @return string
- */
- public function render($viewFile = null)
+ public function render(?string $viewFile = null): string
{
- if (is_null($viewFile)) {
- $class = explode('\\', get_called_class());
- $viewFile = end($class);
+ if (\is_null($viewFile)) {
+ $class = \explode('\\', \get_called_class());
+ $viewFile = \end($class);
}
$view = new View('Form/' . $viewFile);
@@ -184,5 +124,5 @@ public function render($viewFile = null)
return $view->render();
}
- abstract protected function onPreRender(View &$view);
+ abstract protected function onPreRender(View &$view): void;
}
diff --git a/src/Form/Element/Button.php b/src/Form/Element/Button.php
index 1e45c0ce3..8bbed1900 100644
--- a/src/Form/Element/Button.php
+++ b/src/Form/Element/Button.php
@@ -1,21 +1,27 @@
+ * @author Dmitry Khomutov
+ */
class Button extends Input
{
- /**
- * @return bool
- */
- public function validate()
+ public function validate(): bool
{
return true;
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/Element/Checkbox.php b/src/Form/Element/Checkbox.php
index 7a96921be..f6b432029 100644
--- a/src/Form/Element/Checkbox.php
+++ b/src/Form/Element/Checkbox.php
@@ -1,16 +1,22 @@
+ * @author Dmitry Khomutov
+ */
class Checkbox extends Input
{
- /**
- * @var bool
- */
- protected $checked;
+ protected bool $checked = false;
/**
* @var mixed
@@ -28,35 +34,39 @@ public function getCheckedValue()
/**
* @param mixed $value
*/
- public function setCheckedValue($value)
+ public function setCheckedValue($value): self
{
$this->checkedValue = $value;
+
+ return $this;
}
/**
* @param mixed $value
*/
- public function setValue($value)
+ public function setValue($value): self
{
- if (is_bool($value) && $value === true) {
+ if (\is_bool($value) && $value === true) {
$this->value = $this->getCheckedValue();
$this->checked = true;
- return;
+ return $this;
}
- if ($value == $this->getCheckedValue()) {
+ if ($value === $this->getCheckedValue()) {
$this->value = $this->getCheckedValue();
$this->checked = true;
- return;
+ return $this;
}
$this->value = $value;
$this->checked = false;
+
+ return $this;
}
- public function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/Element/CheckboxGroup.php b/src/Form/Element/CheckboxGroup.php
index 272bfbac2..3e9d4be39 100644
--- a/src/Form/Element/CheckboxGroup.php
+++ b/src/Form/Element/CheckboxGroup.php
@@ -1,9 +1,18 @@
+ * @author Dmitry Khomutov
+ */
class CheckboxGroup extends FieldSet
{
}
diff --git a/src/Form/Element/Csrf.php b/src/Form/Element/Csrf.php
index cf9a78c78..8e02e1c11 100644
--- a/src/Form/Element/Csrf.php
+++ b/src/Form/Element/Csrf.php
@@ -1,19 +1,34 @@
+ * @author Dmitry Khomutov
+ */
class Csrf extends Hidden
{
- /**
- * @return bool
- */
- public function validate()
+ private Session $session;
+
+ public function __construct(Session $session, ?string $name = null)
+ {
+ parent::__construct($name);
+
+ $this->session = $session;
+ }
+
+ public function validate(): bool
{
- $sessionToken = isset($_SESSION['csrf_tokens'][$this->getName()])
- ? $_SESSION['csrf_tokens'][$this->getName()]
- : null;
+ $tokens = $this->session->get('csrf_tokens');
+ $sessionToken = isset($tokens[$this->getName()]) ? $tokens[$this->getName()] : null;
if ($this->value !== $sessionToken) {
return false;
@@ -22,16 +37,19 @@ public function validate()
return true;
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
$this->setValue(
- rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=')
+ \rtrim(\strtr(\base64_encode(\random_bytes(32)), '+/', '-_'), '=')
);
$view->value = $this->getValue();
- $_SESSION['csrf_tokens'][$this->getName()] = $this->getValue();
+ $tokens = $this->session->get('csrf_tokens');
+ $tokens[$this->getName()] = $this->getValue();
+
+ $this->session->set('csrf_tokens', $tokens);
}
}
diff --git a/src/Form/Element/Email.php b/src/Form/Element/Email.php
index 4f8dcaff7..f054b84c4 100644
--- a/src/Form/Element/Email.php
+++ b/src/Form/Element/Email.php
@@ -1,22 +1,26 @@
+ * @author Dmitry Khomutov
+ */
class Email extends Text
{
- /**
- * @param string $viewFile
- *
- * @return string
- */
- public function render($viewFile = null)
+ public function render(?string $viewFile = null): string
{
return parent::render(($viewFile ? $viewFile : 'Text'));
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/Element/Hidden.php b/src/Form/Element/Hidden.php
index 086042c14..1644c6ec4 100644
--- a/src/Form/Element/Hidden.php
+++ b/src/Form/Element/Hidden.php
@@ -1,9 +1,18 @@
+ * @author Dmitry Khomutov
+ */
class Hidden extends Input
{
}
diff --git a/src/Form/Element/Password.php b/src/Form/Element/Password.php
index 9135aea13..356f23ec6 100644
--- a/src/Form/Element/Password.php
+++ b/src/Form/Element/Password.php
@@ -1,22 +1,26 @@
+ * @author Dmitry Khomutov
+ */
class Password extends Text
{
- /**
- * @param string $viewFile
- *
- * @return string
- */
- public function render($viewFile = null)
+ public function render(?string $viewFile = null): string
{
return parent::render(($viewFile ? $viewFile : 'Text'));
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/Element/Radio.php b/src/Form/Element/Radio.php
index 6c1e386b5..bd6f1b9a4 100644
--- a/src/Form/Element/Radio.php
+++ b/src/Form/Element/Radio.php
@@ -1,7 +1,16 @@
+ * @author Dmitry Khomutov
+ */
class Radio extends Select
{
}
diff --git a/src/Form/Element/Select.php b/src/Form/Element/Select.php
index 7e0c6c530..a7a1b51fb 100644
--- a/src/Form/Element/Select.php
+++ b/src/Form/Element/Select.php
@@ -1,23 +1,31 @@
+ * @author Dmitry Khomutov
+ */
class Select extends Input
{
- /**
- * @var array
- */
- protected $options = [];
+ protected array $options = [];
- public function setOptions(array $options)
+ public function setOptions(array $options): self
{
$this->options = $options;
+
+ return $this;
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/Element/Submit.php b/src/Form/Element/Submit.php
index 38efbaffe..5375acb40 100644
--- a/src/Form/Element/Submit.php
+++ b/src/Form/Element/Submit.php
@@ -1,9 +1,18 @@
+ * @author Dmitry Khomutov
+ */
class Submit extends Button
{
/**
@@ -11,17 +20,12 @@ class Submit extends Button
*/
protected $value = 'Submit';
- /**
- * @param string $viewFile
- *
- * @return string
- */
- public function render($viewFile = null)
+ public function render(?string $viewFile = null): string
{
return parent::render(($viewFile ? $viewFile : 'Button'));
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/Element/Text.php b/src/Form/Element/Text.php
index 14ca6bc38..ccc2bbc28 100644
--- a/src/Form/Element/Text.php
+++ b/src/Form/Element/Text.php
@@ -1,13 +1,22 @@
+ * @author Dmitry Khomutov
+ */
class Text extends Input
{
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/Element/TextArea.php b/src/Form/Element/TextArea.php
index 3ebff2a2d..b603e4fc7 100644
--- a/src/Form/Element/TextArea.php
+++ b/src/Form/Element/TextArea.php
@@ -1,33 +1,35 @@
+ * @author Dmitry Khomutov
+ */
class TextArea extends Text
{
- /**
- * @var int
- */
- protected $rows = 4;
-
- /**
- * @return int
- */
- public function getRows()
+ protected int $rows = 4;
+
+ public function getRows(): int
{
return $this->rows;
}
- /**
- * @param int $rows
- */
- public function setRows($rows)
+ public function setRows(int $rows): self
{
$this->rows = $rows;
+
+ return $this;
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/Element/Url.php b/src/Form/Element/Url.php
index 6f192f127..d7e104f01 100644
--- a/src/Form/Element/Url.php
+++ b/src/Form/Element/Url.php
@@ -1,22 +1,29 @@
+ * @author Dmitry Khomutov
+ */
class Url extends Text
{
/**
* @param string $viewFile
- *
- * @return string
*/
- public function render($viewFile = null)
+ public function render(?string $viewFile = null): string
{
return parent::render(($viewFile ? $viewFile : 'Text'));
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
parent::onPreRender($view);
diff --git a/src/Form/FieldSet.php b/src/Form/FieldSet.php
index 40f08adbd..c9951a71a 100644
--- a/src/Form/FieldSet.php
+++ b/src/Form/FieldSet.php
@@ -1,20 +1,26 @@
+ * @author Dmitry Khomutov
+ */
class FieldSet extends Element
{
/**
* @var Element[]
*/
- protected $children = [];
+ protected array $children = [];
- /**
- * @return array
- */
- public function getValues()
+ public function getValues(): array
{
$rtn = [];
foreach ($this->children as $field) {
@@ -22,7 +28,7 @@ public function getValues()
$fieldName = $field->getName();
if (empty($fieldName)) {
- $rtn = array_merge($rtn, $field->getValues());
+ $rtn = \array_merge($rtn, $field->getValues());
} else {
$rtn[$fieldName] = $field->getValues();
}
@@ -36,7 +42,7 @@ public function getValues()
return $rtn;
}
- public function setValues(array $values)
+ public function setValues(array $values): self
{
foreach ($this->children as $field) {
if ($field instanceof FieldSet) {
@@ -55,18 +61,19 @@ public function setValues(array $values)
}
}
}
+
+ return $this;
}
- public function addField(Element $field)
+ public function addField(Element $field): self
{
$this->children[$field->getName()] = $field;
$field->setParent($this);
+
+ return $this;
}
- /**
- * @return bool
- */
- public function validate()
+ public function validate(): bool
{
$rtn = true;
@@ -79,7 +86,7 @@ public function validate()
return $rtn;
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
$rendered = [];
foreach ($this->children as $child) {
@@ -89,20 +96,12 @@ protected function onPreRender(View &$view)
$view->children = $rendered;
}
- /**
- * @return Element[]
- */
- public function getChildren()
+ public function getChildren(): array
{
return $this->children;
}
- /**
- * @param string $fieldName
- *
- * @return Element
- */
- public function getChild($fieldName)
+ public function getChild(string $fieldName): Element
{
return $this->children[$fieldName];
}
diff --git a/src/Form/Input.php b/src/Form/Input.php
index ddba1558a..1cd182217 100644
--- a/src/Form/Input.php
+++ b/src/Form/Input.php
@@ -1,5 +1,7 @@
+ * @author Dmitry Khomutov
+ */
class Input extends Element
{
- /**
- * @var bool
- */
- protected $required = false;
+ protected bool $required = false;
- /**
- * @var string
- */
- protected $pattern;
+ protected string $pattern = '';
/**
* @var callable
@@ -29,29 +32,19 @@ class Input extends Element
*/
protected $value;
- /**
- * @var string
- */
- protected $error;
+ protected string $error = '';
- /**
- * @var bool
- */
- protected $customError = false;
+ protected bool $customError = false;
- /** @var DataTransformerInterface */
- protected $dataTransformator;
+ protected ?DataTransformerInterface $dataTransformer = null;
/**
- * @param string $name
- * @param string $label
- * @param bool $required
- *
* @return static
*/
- public static function create($name, $label, $required = false)
+ public static function create(string $name, string $label, bool $required = false): self
{
$el = new static();
+
$el->setName($name);
$el->setLabel($label);
$el->setRequired($required);
@@ -64,8 +57,8 @@ public static function create($name, $label, $required = false)
*/
public function getValue()
{
- if (!empty($this->getDataTransformator())) {
- return $this->getDataTransformator()->reverseTransform($this->value);
+ if (!empty($this->getDataTransformer())) {
+ return $this->getDataTransformer()->reverseTransform((string)$this->value);
}
return $this->value;
@@ -76,10 +69,10 @@ public function getValue()
*
* @return $this
*/
- public function setValue($value)
+ public function setValue($value): self
{
- if (!empty($this->getDataTransformator())) {
- $this->value = $this->getDataTransformator()->transform($value);
+ if (!empty($this->getDataTransformer())) {
+ $this->value = $this->getDataTransformer()->transform($value);
} else {
$this->value = $value;
}
@@ -87,22 +80,14 @@ public function setValue($value)
return $this;
}
- /**
- * @return bool
- */
- public function getRequired()
+ public function getRequired(): bool
{
return $this->required;
}
- /**
- * @param bool $required
- *
- * @return $this
- */
- public function setRequired($required)
+ public function setRequired(bool $required): self
{
- $this->required = (bool)$required;
+ $this->required = $required;
return $this;
}
@@ -115,44 +100,28 @@ public function getValidator()
return $this->validator;
}
- /**
- * @param callable $validator
- *
- * @return $this
- */
- public function setValidator($validator)
+ public function setValidator($validator): self
{
- if (is_callable($validator) || $validator instanceof Closure) {
+ if (\is_callable($validator) || $validator instanceof Closure) {
$this->validator = $validator;
}
return $this;
}
- /**
- * @return string
- */
- public function getPattern()
+ public function getPattern(): string
{
return $this->pattern;
}
- /**
- * @param string $pattern
- *
- * @return $this
- */
- public function setPattern($pattern)
+ public function setPattern(string $pattern): self
{
$this->pattern = $pattern;
return $this;
}
- /**
- * @return bool
- */
- public function validate()
+ public function validate(): bool
{
if ($this->getRequired() && empty($this->getValue())) {
$this->error = $this->getLabel() . ' is required.';
@@ -160,7 +129,7 @@ public function validate()
return false;
}
- if ($this->getPattern() && !preg_match('/' . $this->getPattern() . '/', $this->getValue())) {
+ if ($this->getPattern() && !\preg_match('#' . $this->getPattern() . '#', (string)$this->getValue())) {
$this->error = 'Invalid value entered.';
return false;
@@ -168,10 +137,10 @@ public function validate()
$validator = $this->getValidator();
- if (is_callable($validator)) {
+ if (\is_callable($validator)) {
try {
- call_user_func_array($validator, [$this->getValue()]);
- } catch (Exception $ex) {
+ \call_user_func_array($validator, [$this->getValue()]);
+ } catch (\Throwable $ex) {
$this->error = $ex->getMessage();
return false;
@@ -185,12 +154,7 @@ public function validate()
return true;
}
- /**
- * @param string $message
- *
- * @return $this
- */
- public function setError($message)
+ public function setError(string $message): self
{
$this->customError = true;
$this->error = $message;
@@ -198,7 +162,7 @@ public function setError($message)
return $this;
}
- protected function onPreRender(View &$view)
+ protected function onPreRender(View &$view): void
{
$view->value = $this->getValue();
$view->error = $this->error;
@@ -206,16 +170,15 @@ protected function onPreRender(View &$view)
$view->required = $this->required;
}
- /**
- * @return DataTransformerInterface
- */
- public function getDataTransformator()
+ public function getDataTransformer(): ?DataTransformerInterface
{
- return $this->dataTransformator;
+ return $this->dataTransformer;
}
- public function setDataTransformator(DataTransformerInterface $dataTransformator)
+ public function setDataTransformer(DataTransformerInterface $dataTransformer): self
{
- $this->dataTransformator = $dataTransformator;
+ $this->dataTransformer = $dataTransformer;
+
+ return $this;
}
}
diff --git a/src/Form/Validator/ValidatorInterface.php b/src/Form/Validator/ValidatorInterface.php
index 6e10c277f..270a4247e 100644
--- a/src/Form/Validator/ValidatorInterface.php
+++ b/src/Form/Validator/ValidatorInterface.php
@@ -1,8 +1,16 @@
+ */
interface ValidatorInterface
{
- public function __invoke($value);
+ public function __invoke($value): bool;
}
diff --git a/src/Form/Validator/Yaml.php b/src/Form/Validator/Yaml.php
index 469b24554..c60eca074 100644
--- a/src/Form/Validator/Yaml.php
+++ b/src/Form/Validator/Yaml.php
@@ -1,28 +1,35 @@
+ */
class Yaml implements ValidatorInterface
{
- /** @var Parser */
- protected $parser;
+ protected ?Parser $parser = null;
- public function __invoke($value)
+ public function __invoke($value): bool
{
try {
$this->getParser()->parse($value);
} catch (ParseException $e) {
- throw new Exception($e->getMessage());
+ throw new RuntimeException($e->getMessage());
}
return true;
}
- public function getParser()
+ public function getParser(): Parser
{
if (!$this->parser) {
$this->parser = new Parser();
diff --git a/src/Helper/AnsiConverter.php b/src/Helper/AnsiConverter.php
deleted file mode 100644
index 850a7aa01..000000000
--- a/src/Helper/AnsiConverter.php
+++ /dev/null
@@ -1,46 +0,0 @@
-convert($text);
- }
-
- /**
- * Do not instantiate this class.
- */
- private function __construct()
- {
- }
-}
diff --git a/src/Helper/Bitbucket.php b/src/Helper/Bitbucket.php
index c20f7192f..2f8467ed6 100644
--- a/src/Helper/Bitbucket.php
+++ b/src/Helper/Bitbucket.php
@@ -3,13 +3,26 @@
namespace PHPCensor\Helper;
use GuzzleHttp\Client;
-use PHPCensor\Config;
+use PHPCensor\Common\Application\ConfigurationInterface;
+use PHPCensor\Model\Build;
/**
* The Bitbucket Helper class provides some Bitbucket API call functionality.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Bitbucket
{
+ private ConfigurationInterface $configuration;
+
+ public function __construct(ConfigurationInterface $configuration)
+ {
+ $this->configuration = $configuration;
+ }
+
/**
* Create a comment on a specific file (and commit) in a Bitbucket Pull Request.
*
@@ -24,8 +37,8 @@ class Bitbucket
*/
public function createPullRequestComment($repo, $pullId, $commitId, $file, $line, $comment)
{
- $username = Config::getInstance()->get('php-censor.bitbucket.username');
- $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password');
+ $username = $this->configuration->get('php-censor.bitbucket.username');
+ $appPassword = $this->configuration->get('php-censor.bitbucket.app_password');
if (empty($username) || empty($appPassword)) {
return;
@@ -35,7 +48,7 @@ public function createPullRequestComment($repo, $pullId, $commitId, $file, $line
$data = [
'content' => $comment,
- 'anchor' => substr($commitId, 0, 12),
+ 'anchor' => \substr($commitId, 0, 12),
'filename' => $file,
];
if ($line > 0) {
@@ -60,8 +73,8 @@ public function createPullRequestComment($repo, $pullId, $commitId, $file, $line
*/
public function createCommitComment($repo, $commitId, $file, $line, $comment)
{
- $username = Config::getInstance()->get('php-censor.bitbucket.username');
- $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password');
+ $username = $this->configuration->get('php-censor.bitbucket.username');
+ $appPassword = $this->configuration->get('php-censor.bitbucket.app_password');
if (empty($username) || empty($appPassword)) {
return;
@@ -97,8 +110,8 @@ public function createCommitComment($repo, $commitId, $file, $line, $comment)
*/
public function getPullRequestDiff($repo, $pullRequestId)
{
- $username = Config::getInstance()->get('php-censor.bitbucket.username');
- $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password');
+ $username = $this->configuration->get('php-censor.bitbucket.username');
+ $appPassword = $this->configuration->get('php-censor.bitbucket.app_password');
if (empty($username) || empty($appPassword)) {
return;
@@ -112,4 +125,20 @@ public function getPullRequestDiff($repo, $pullRequestId)
return (string)$response->getBody();
}
+
+ public function getFileLinkTemplate(Build $build): string
+ {
+ $reference = $build->getProject()->getReference();
+ if (\in_array($build->getSource(), Build::$pullRequestSources, true)) {
+ $reference = $build->getExtra('remote_reference');
+ }
+
+ $link = 'https://bitbucket.org/' . $reference . '/';
+
+ $link .= 'src/' . $build->getCommitId() . '/';
+ $link .= '{FILE}';
+ $link .= '#{BASEFILE}-{LINE}';
+
+ return $link;
+ }
}
diff --git a/src/Helper/Branch.php b/src/Helper/Branch.php
index 3c988f95b..78ed8b2fb 100644
--- a/src/Helper/Branch.php
+++ b/src/Helper/Branch.php
@@ -1,12 +1,20 @@
+ */
class Branch
{
- public static function getDefaultBranchName($projectType)
+ public static function getDefaultBranchName(string $projectType): string
{
switch ($projectType) {
case Project::TYPE_HG:
diff --git a/src/Helper/BuildInterpolator.php b/src/Helper/BuildInterpolator.php
index ff2889d1c..ef8db63e4 100644
--- a/src/Helper/BuildInterpolator.php
+++ b/src/Helper/BuildInterpolator.php
@@ -1,14 +1,21 @@
*/
class BuildInterpolator
{
@@ -20,22 +27,30 @@ class BuildInterpolator
*
* @see setupInterpolationVars()
*/
- protected $interpolationVars = [];
+ private array $interpolationVars = [];
+
+ private EnvironmentStore $environmentStore;
+ private SecretStore $secretStore;
+
+ public function __construct(
+ EnvironmentStore $environmentStore,
+ SecretStore $secretStore
+ ) {
+ $this->environmentStore = $environmentStore;
+ $this->secretStore = $secretStore;
+ }
/**
* Sets the variables that will be used for interpolation.
*
- * @param string $url
- * @param string $applicationVersion
- *
* @throws Exception
*/
- public function setupInterpolationVars(BaseBuild $build, $url, $applicationVersion)
+ public function setupInterpolationVars(Build $build, string $url, string $applicationVersion): void
{
$this->interpolationVars = [];
$this->interpolationVars['%COMMIT_ID%'] = $build->getCommitId();
- $this->interpolationVars['%SHORT_COMMIT_ID%'] = substr($build->getCommitId(), 0, 7);
+ $this->interpolationVars['%SHORT_COMMIT_ID%'] = \substr((string)$build->getCommitId(), 0, 7);
$this->interpolationVars['%PROJECT_ID%'] = $build->getProjectId();
$this->interpolationVars['%BUILD_ID%'] = $build->getId();
$this->interpolationVars['%COMMITTER_EMAIL%'] = $build->getCommitterEmail();
@@ -51,9 +66,7 @@ public function setupInterpolationVars(BaseBuild $build, $url, $applicationVersi
$environmentId = $build->getEnvironmentId();
$environment = null;
if ($environmentId) {
- /** @var EnvironmentStore $environmentStore */
- $environmentStore = Factory::getStore('Environment');
- $environmentObject = $environmentStore->getById($environmentId);
+ $environmentObject = $this->environmentStore->getById($environmentId);
if ($environmentObject) {
$environment = $environmentObject->getName();
}
@@ -62,34 +75,45 @@ public function setupInterpolationVars(BaseBuild $build, $url, $applicationVersi
$this->interpolationVars['%ENVIRONMENT%'] = $environment;
$this->interpolationVars['%SYSTEM_VERSION%'] = $applicationVersion;
- putenv('PHP_CENSOR=1');
- putenv('PHP_CENSOR_COMMIT_ID=' . $this->interpolationVars['%COMMIT_ID%']);
- putenv('PHP_CENSOR_SHORT_COMMIT_ID=' . $this->interpolationVars['%SHORT_COMMIT_ID%']);
- putenv('PHP_CENSOR_COMMITTER_EMAIL=' . $this->interpolationVars['%COMMITTER_EMAIL%']);
- putenv('PHP_CENSOR_COMMIT_MESSAGE=' . $this->interpolationVars['%COMMIT_MESSAGE%']);
- putenv('PHP_CENSOR_COMMIT_LINK=' . $this->interpolationVars['%COMMIT_LINK%']);
- putenv('PHP_CENSOR_PROJECT_ID=' . $this->interpolationVars['%PROJECT_ID%']);
- putenv('PHP_CENSOR_PROJECT_TITLE=' . $this->interpolationVars['%PROJECT_TITLE%']);
- putenv('PHP_CENSOR_PROJECT_LINK=' . $this->interpolationVars['%PROJECT_LINK%']);
- putenv('PHP_CENSOR_BUILD_ID=' . $this->interpolationVars['%BUILD_ID%']);
- putenv('PHP_CENSOR_BUILD_PATH=' . $this->interpolationVars['%BUILD_PATH%']);
- putenv('PHP_CENSOR_BUILD_LINK=' . $this->interpolationVars['%BUILD_LINK%']);
- putenv('PHP_CENSOR_BRANCH=' . $this->interpolationVars['%BRANCH%']);
- putenv('PHP_CENSOR_BRANCH_LINK=' . $this->interpolationVars['%BRANCH_LINK%']);
- putenv('PHP_CENSOR_ENVIRONMENT=' . $this->interpolationVars['%ENVIRONMENT%']);
- putenv('PHP_CENSOR_SYSTEM_VERSION=' . $this->interpolationVars['%SYSTEM_VERSION%']);
+ \putenv('PHP_CENSOR=1');
+ \putenv('PHP_CENSOR_COMMIT_ID=' . $this->interpolationVars['%COMMIT_ID%']);
+ \putenv('PHP_CENSOR_SHORT_COMMIT_ID=' . $this->interpolationVars['%SHORT_COMMIT_ID%']);
+ \putenv('PHP_CENSOR_COMMITTER_EMAIL=' . $this->interpolationVars['%COMMITTER_EMAIL%']);
+ \putenv('PHP_CENSOR_COMMIT_MESSAGE=' . $this->interpolationVars['%COMMIT_MESSAGE%']);
+ \putenv('PHP_CENSOR_COMMIT_LINK=' . $this->interpolationVars['%COMMIT_LINK%']);
+ \putenv('PHP_CENSOR_PROJECT_ID=' . $this->interpolationVars['%PROJECT_ID%']);
+ \putenv('PHP_CENSOR_PROJECT_TITLE=' . $this->interpolationVars['%PROJECT_TITLE%']);
+ \putenv('PHP_CENSOR_PROJECT_LINK=' . $this->interpolationVars['%PROJECT_LINK%']);
+ \putenv('PHP_CENSOR_BUILD_ID=' . $this->interpolationVars['%BUILD_ID%']);
+ \putenv('PHP_CENSOR_BUILD_PATH=' . $this->interpolationVars['%BUILD_PATH%']);
+ \putenv('PHP_CENSOR_BUILD_LINK=' . $this->interpolationVars['%BUILD_LINK%']);
+ \putenv('PHP_CENSOR_BRANCH=' . $this->interpolationVars['%BRANCH%']);
+ \putenv('PHP_CENSOR_BRANCH_LINK=' . $this->interpolationVars['%BRANCH_LINK%']);
+ \putenv('PHP_CENSOR_ENVIRONMENT=' . $this->interpolationVars['%ENVIRONMENT%']);
+ \putenv('PHP_CENSOR_SYSTEM_VERSION=' . $this->interpolationVars['%SYSTEM_VERSION%']);
}
- /**
- * @param string $input
- *
- * @return string
- */
- private function realtimeInterpolate($input)
+ private function realtimeInterpolate(string $input): string
{
- $input = str_replace('%CURRENT_DATE%', \date('Y-m-d'), $input);
- $input = str_replace('%CURRENT_TIME%', \date('H-i-s'), $input);
- $input = str_replace('%CURRENT_DATETIME%', \date('Y-m-d_H-i-s'), $input);
+ $input = \str_replace('%CURRENT_DATE%', \date('Y-m-d'), $input);
+ $input = \str_replace('%CURRENT_TIME%', \date('H-i-s'), $input);
+
+ return \str_replace('%CURRENT_DATETIME%', \date('Y-m-d_H-i-s'), $input);
+ }
+
+ private function secretInterpolate(string $input): string
+ {
+ \preg_match_all('#%SECRET:([-_\w\d]+)?%#', $input, $matches);
+ if (!empty($matches[0])) {
+ $secrets = $this->secretStore->getByNames($matches[1]);
+ $finalSecrets = [];
+
+ foreach ($matches[0] as $index => $match) {
+ $finalSecrets[$index] = $secrets[$matches[1][$index]]->getValue();
+ }
+
+ $input = \str_replace($matches[0], $finalSecrets, $input);
+ }
return $input;
}
@@ -97,18 +121,17 @@ private function realtimeInterpolate($input)
/**
* Replace every occurrence of the interpolation vars in the given string
* Example: "This is build %BUILD_ID%" => "This is build 182"
- *
- * @param string $input
- *
- * @return string
*/
- public function interpolate($input)
+ public function interpolate(string $input, bool $useSecrets = false): string
{
+ if ($useSecrets) {
+ $input = $this->secretInterpolate($input);
+ }
$input = $this->realtimeInterpolate($input);
- $keys = array_keys($this->interpolationVars);
- $values = array_values($this->interpolationVars);
+ $keys = \array_keys($this->interpolationVars);
+ $values = \array_values($this->interpolationVars);
- return str_replace($keys, $values, $input);
+ return \str_replace($keys, $values, $input);
}
}
diff --git a/src/Helper/CommandExecutor.php b/src/Helper/CommandExecutor.php
index fd1f3b031..b240a27ef 100644
--- a/src/Helper/CommandExecutor.php
+++ b/src/Helper/CommandExecutor.php
@@ -2,12 +2,17 @@
namespace PHPCensor\Helper;
-use Exception;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Logging\BuildLogger;
use Symfony\Component\Process\Process;
/**
* Handles running system commands with variables.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class CommandExecutor implements CommandExecutorInterface
{
@@ -24,7 +29,7 @@ class CommandExecutor implements CommandExecutorInterface
/**
* @var array
*/
- protected $lastOutput;
+ protected $lastOutput = [];
/**
* @var string
@@ -52,19 +57,15 @@ class CommandExecutor implements CommandExecutorInterface
/**
* Commands with no proper exit mechanism
- *
- * @var array
*/
- private static $noExitCommands = [
+ private static array $noExitCommands = [
'codecept',
];
/**
* Environment variables that should not be inherited
- *
- * @var array
*/
- private static $blacklistEnvVars = [
+ private static array $blacklistEnvVars = [
'PHP_SELF',
'SCRIPT_NAME',
'SCRIPT_FILENAME',
@@ -81,7 +82,6 @@ public function __construct(BuildLogger $logger, $rootDir, $verbose = false)
{
$this->logger = $logger;
$this->verbose = $verbose;
- $this->lastOutput = [];
$this->rootDir = $rootDir;
}
@@ -96,7 +96,7 @@ public function executeCommand($args = [])
{
$this->lastOutput = [];
- $this->logger->logDebug('Args: ' . json_encode($args));
+ $this->logger->logDebug('Args: ' . \json_encode($args));
$command = \call_user_func_array('sprintf', $args);
@@ -104,14 +104,15 @@ public function executeCommand($args = [])
$withNoExit = '';
foreach (self::$noExitCommands as $nec) {
- if (preg_match("/\b{$nec}\b/", $command)) {
+ if (\preg_match("/\b{$nec}\b/", $command)) {
$withNoExit = $nec;
+
break;
}
}
$cwd = RUNTIME_DIR . 'builds';
- if ($this->buildPath && file_exists($this->buildPath)) {
+ if ($this->buildPath && \file_exists($this->buildPath)) {
$cwd = $this->buildPath;
}
@@ -125,14 +126,12 @@ public function executeCommand($args = [])
$this->logger->logDebug("Assuming command '{$withNoExit}' does not exit properly");
do {
- sleep(15);
+ \sleep(15);
$response = [];
- exec("ps auxww | grep '{$withNoExit}' | grep -v grep", $response);
- $response = array_filter(
+ \exec("ps auxww | grep '{$withNoExit}' | grep -v grep", $response);
+ $response = \array_filter(
$response,
- function ($a) {
- return strpos($a, $this->buildPath) !== false;
- }
+ fn ($a) => \strpos($a, $this->buildPath) !== false
);
} while (!empty($response));
$process->stop();
@@ -146,7 +145,7 @@ function ($a) {
$lastOutput = $this->replaceIllegalCharacters($process->getOutput());
$lastError = $this->replaceIllegalCharacters($process->getErrorOutput());
- $this->lastOutput = array_filter(explode(PHP_EOL, $lastOutput));
+ $this->lastOutput = \array_filter(\explode(PHP_EOL, $lastOutput));
$this->lastError = $lastError;
$shouldOutput = ($this->logExecOutput && ($this->verbose || 0 !== $status));
@@ -176,12 +175,12 @@ function ($a) {
*/
public function replaceIllegalCharacters($utf8String)
{
- mb_substitute_character(0xFFFD); // is '�'
- $legalUtf8String = mb_convert_encoding($utf8String, 'utf8', 'utf8');
+ \mb_substitute_character(0xFFFD); // is '�'
+ $legalUtf8String = \mb_convert_encoding($utf8String, 'utf8', 'utf8');
$regexp = '/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]' .
'|[^\x{0}-\x{ffff}]/u'; // more than 3 byte UTF-8 sequences (unsupported in mysql)
- return preg_replace($regexp, '�', $legalUtf8String);
+ return \preg_replace($regexp, '�', $legalUtf8String);
}
/**
@@ -191,7 +190,7 @@ public function replaceIllegalCharacters($utf8String)
*/
public function getLastOutput()
{
- return implode(PHP_EOL, $this->lastOutput);
+ return \implode(PHP_EOL, $this->lastOutput);
}
/**
@@ -212,8 +211,8 @@ public function getLastError()
*/
protected function findBinaryByPath($binaryPath, $binary)
{
- if (is_dir($binaryPath) && is_file($binaryPath . '/' . $binary)) {
- $this->logger->logDebug(sprintf('Found in %s (binary_path): %s', $binaryPath, $binary));
+ if (\is_dir($binaryPath) && \is_file($binaryPath . '/' . $binary)) {
+ $this->logger->logDebug(\sprintf('Found in %s (binary_path): %s', $binaryPath, $binary));
return $binaryPath . '/' . $binary;
}
@@ -229,8 +228,8 @@ protected function findBinaryByPath($binaryPath, $binary)
*/
protected function findBinaryLocal($composerBin, $binary)
{
- if (is_dir($composerBin) && is_file($composerBin . '/' . $binary)) {
- $this->logger->logDebug(sprintf('Found in %s (local): %s', $composerBin, $binary));
+ if (\is_dir($composerBin) && \is_file($composerBin . '/' . $binary)) {
+ $this->logger->logDebug(\sprintf('Found in %s (local): %s', $composerBin, $binary));
return $composerBin . '/' . $binary;
}
@@ -245,8 +244,8 @@ protected function findBinaryLocal($composerBin, $binary)
*/
protected function findBinaryGlobal($binary)
{
- if (is_file($this->rootDir . 'vendor/bin/' . $binary)) {
- $this->logger->logDebug(sprintf('Found in %s (global): %s', 'vendor/bin', $binary));
+ if (\is_file($this->rootDir . 'vendor/bin/' . $binary)) {
+ $this->logger->logDebug(\sprintf('Found in %s (global): %s', 'vendor/bin', $binary));
return $this->rootDir . 'vendor/bin/' . $binary;
}
@@ -263,9 +262,9 @@ protected function findBinaryGlobal($binary)
*/
protected function findBinarySystem($binary)
{
- $tempBinary = trim(shell_exec('which ' . $binary));
- if (is_file($tempBinary)) {
- $this->logger->logDebug(sprintf('Found in %s (system): %s', '', $binary));
+ $tempBinary = \trim(\shell_exec('which ' . $binary));
+ if (\is_file($tempBinary)) {
+ $this->logger->logDebug(\sprintf('Found in %s (system): %s', '', $binary));
return $tempBinary;
}
@@ -280,16 +279,16 @@ public function findBinary($binary, $priorityPath = 'local', $binaryPath = '', $
{
$composerBin = $this->getComposerBinDir($this->buildPath);
- if (is_string($binary)) {
+ if (\is_string($binary)) {
$binary = [$binary];
}
if ($binaryName) {
- array_unshift($binary, ...$binaryName);
+ \array_unshift($binary, ...$binaryName);
}
foreach ($binary as $bin) {
- $this->logger->logDebug(sprintf('Looking for binary: %s, priority = %s', $bin, $priorityPath));
+ $this->logger->logDebug(\sprintf('Looking for binary: %s, priority = %s', $bin, $priorityPath));
if ('binary_path' === $priorityPath) {
if ($existedBinary = $this->findBinaryByPath($binaryPath, $bin)) {
@@ -358,7 +357,7 @@ public function findBinary($binary, $priorityPath = 'local', $binaryPath = '', $
}
}
- throw new Exception(sprintf('Could not find %s', implode('/', $binary)));
+ throw new RuntimeException(\sprintf('Could not find %s', \implode('/', $binary)));
}
/**
@@ -371,14 +370,14 @@ public function findBinary($binary, $priorityPath = 'local', $binaryPath = '', $
*/
public function getComposerBinDir($path)
{
- if (is_dir($path)) {
+ if (\is_dir($path)) {
$composer = $path . '/composer.json';
- if (is_file($composer)) {
- $json = json_decode(file_get_contents($composer));
+ if (\is_file($composer)) {
+ $json = \json_decode(\file_get_contents($composer));
if (isset($json->config->{"bin-dir"})) {
return $path . '/' . $json->config->{"bin-dir"};
- } elseif (is_dir($path . '/vendor/bin')) {
+ } elseif (\is_dir($path . '/vendor/bin')) {
return $path . '/vendor/bin';
}
}
@@ -405,41 +404,41 @@ private function getDefaultEnv()
$env = [];
foreach ($_SERVER as $k => $v) {
- if (in_array($k, self::$blacklistEnvVars, true)) {
+ if (\in_array($k, self::$blacklistEnvVars, true)) {
continue;
}
- if (is_string($v) && false !== $v = getenv($k)) {
+ if (\is_string($v) && false !== $v = \getenv($k)) {
$env[$k] = $v;
}
}
foreach ($_ENV as $k => $v) {
- if (in_array($k, self::$blacklistEnvVars, true)) {
+ if (\in_array($k, self::$blacklistEnvVars, true)) {
continue;
}
- if (is_string($v)) {
+ if (\is_string($v)) {
$env[$k] = $v;
}
}
if (PHP_MAJOR_VERSION >= 7 && PHP_MINOR_VERSION >= 1) {
- foreach (getenv() as $k => $v) {
- if (in_array($k, self::$blacklistEnvVars, true)) {
+ foreach (\getenv() as $k => $v) {
+ if (\in_array($k, self::$blacklistEnvVars, true)) {
continue;
}
- if (is_string($v)) {
+ if (\is_string($v)) {
$env[$k] = $v;
}
}
} else {
$output = [];
- exec('env', $output);
+ \exec('env', $output);
foreach ($output as $o) {
- $keyval = explode('=', $o, 2);
- if (count($keyval) < 2 || empty($keyval[1])) {
+ $keyval = \explode('=', $o, 2);
+ if (\count($keyval) < 2 || empty($keyval[1])) {
continue;
}
- if (in_array($keyval[0], self::$blacklistEnvVars, true)) {
+ if (\in_array($keyval[0], self::$blacklistEnvVars, true)) {
continue;
}
$env[$keyval[0]] = $keyval[1];
diff --git a/src/Helper/CommandExecutorInterface.php b/src/Helper/CommandExecutorInterface.php
index 379b21b33..3f72078cf 100644
--- a/src/Helper/CommandExecutorInterface.php
+++ b/src/Helper/CommandExecutorInterface.php
@@ -4,6 +4,12 @@
use Exception;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
interface CommandExecutorInterface
{
/**
diff --git a/src/Helper/Diff.php b/src/Helper/Diff.php
deleted file mode 100644
index 97e393ae9..000000000
--- a/src/Helper/Diff.php
+++ /dev/null
@@ -1,50 +0,0 @@
-
*/
class Email
{
@@ -20,7 +25,7 @@ class Email
protected $isHtml = false;
protected $config;
- public function __construct(Config $config)
+ public function __construct(ConfigurationInterface $config)
{
$this->config = $config;
}
@@ -99,13 +104,13 @@ public function getFrom()
self::DEFAULT_FROM
);
- if (strpos($from, '<') === false) {
- return [(string)trim($from) => 'PHP Censor'];
+ if (\strpos($from, '<') === false) {
+ return [(string)\trim($from) => 'PHP Censor'];
}
- preg_match('#^(.*?)<(.*?)>$#ui', $from, $fromParts);
+ \preg_match('#^(.*?)<(.*?)>$#ui', $from, $fromParts);
- return [trim($fromParts[2]) => trim($fromParts[1])];
+ return [\trim($fromParts[2]) => \trim($fromParts[1])];
}
/**
@@ -118,7 +123,7 @@ public function send(Builder $builder = null)
{
$smtpServer = $this->config->get('php-censor.email_settings.smtp_address');
if (null !== $builder) {
- $builder->logDebug(sprintf("SMTP: '%s'", !empty($smtpServer) ? 'true' : 'false'));
+ $builder->logDebug(\sprintf("SMTP: '%s'", !empty($smtpServer) ? 'true' : 'false'));
}
$factory = new MailerFactory($this->config->get('php-censor'));
@@ -134,15 +139,15 @@ public function send(Builder $builder = null)
$message->setContentType('text/html');
}
- if (is_array($this->emailCc) && count($this->emailCc)) {
+ if (\is_array($this->emailCc) && \count($this->emailCc)) {
$message->setCc($this->emailCc);
}
- ob_start();
+ \ob_start();
$result = $mailer->send($message);
- $rawOutput = ob_get_clean();
+ $rawOutput = \ob_get_clean();
if ($rawOutput) {
$builder->getBuildLogger()->logWarning($rawOutput);
diff --git a/src/Helper/Github.php b/src/Helper/Github.php
index b1f09108d..e163e1be9 100644
--- a/src/Helper/Github.php
+++ b/src/Helper/Github.php
@@ -3,26 +3,38 @@
namespace PHPCensor\Helper;
use GuzzleHttp\Client;
-use PHPCensor\Config;
+use PHPCensor\Common\Application\ConfigurationInterface;
/**
* The Github Helper class provides some Github API call functionality.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Github
{
+ private ConfigurationInterface $configuration;
+
+ public function __construct(ConfigurationInterface $configuration)
+ {
+ $this->configuration = $configuration;
+ }
+
/**
* Create a comment on a specific file (and commit) in a Github Pull Request.
* @return null
*/
public function createPullRequestComment($repo, $pullId, $commitId, $file, $line, $comment)
{
- $token = Config::getInstance()->get('php-censor.github.token');
+ $token = $this->configuration->get('php-censor.github.token');
if (!$token) {
return null;
}
- $url = '/repos/' . strtolower($repo) . '/pulls/' . $pullId . '/comments';
+ $url = '/repos/' . \strtolower($repo) . '/pulls/' . $pullId . '/comments';
$params = [
'body' => $comment,
@@ -34,7 +46,7 @@ public function createPullRequestComment($repo, $pullId, $commitId, $file, $line
$client = new Client();
$client->post(('https://api.github.com' . $url), [
'headers' => [
- 'Authorization' => 'Basic ' . base64_encode($token . ':x-oauth-basic'),
+ 'Authorization' => 'Basic ' . \base64_encode($token . ':x-oauth-basic'),
'Content-Type' => 'application/x-www-form-urlencoded'
],
'json' => $params,
@@ -47,13 +59,13 @@ public function createPullRequestComment($repo, $pullId, $commitId, $file, $line
*/
public function createCommitComment($repo, $commitId, $file, $line, $comment)
{
- $token = Config::getInstance()->get('php-censor.github.token');
+ $token = $this->configuration->get('php-censor.github.token');
if (!$token) {
return null;
}
- $url = '/repos/' . strtolower($repo) . '/commits/' . $commitId . '/comments';
+ $url = '/repos/' . \strtolower($repo) . '/commits/' . $commitId . '/comments';
$params = [
'body' => $comment,
@@ -64,7 +76,7 @@ public function createCommitComment($repo, $commitId, $file, $line, $comment)
$client = new Client();
$client->post(('https://api.github.com' . $url), [
'headers' => [
- 'Authorization' => 'Basic ' . base64_encode($token . ':x-oauth-basic'),
+ 'Authorization' => 'Basic ' . \base64_encode($token . ':x-oauth-basic'),
'Content-Type' => 'application/x-www-form-urlencoded'
],
'json' => $params,
diff --git a/src/Helper/Lang.php b/src/Helper/Lang.php
index 64526670a..6dde2631a 100644
--- a/src/Helper/Lang.php
+++ b/src/Helper/Lang.php
@@ -2,12 +2,17 @@
namespace PHPCensor\Helper;
-use PHPCensor\Config;
-use PHPCensor\Store\Factory;
+use PHPCensor\Common\Application\ConfigurationInterface;
use PHPCensor\Store\UserStore;
+use PHPCensor\StoreRegistry;
/**
* Languages Helper Class - Handles loading strings files and the strings within them.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Lang
{
@@ -43,14 +48,14 @@ class Lang
public static function get(...$params)
{
$string = $params[0];
- if (array_key_exists($string, self::$strings)) {
+ if (\array_key_exists($string, self::$strings)) {
$params[0] = self::$strings[$string];
- return call_user_func_array('sprintf', $params);
- } elseif (self::DEFAULT_LANGUAGE !== self::$language && array_key_exists($string, self::$defaultStrings)) {
+ return \call_user_func_array('sprintf', $params);
+ } elseif (self::DEFAULT_LANGUAGE !== self::$language && \array_key_exists($string, self::$defaultStrings)) {
$params[0] = self::$defaultStrings[$string];
- return call_user_func_array('sprintf', $params);
+ return \call_user_func_array('sprintf', $params);
}
return $string;
@@ -74,7 +79,7 @@ public static function getLanguage()
*/
public static function setLanguage($language)
{
- if (in_array($language, self::$languages, true)) {
+ if (\in_array($language, self::$languages, true)) {
self::$language = $language;
self::$strings = self::loadLanguage();
@@ -114,11 +119,13 @@ public static function getStrings()
/**
* Initialise the Language helper, try load the language file for the user's browser or the configured default.
- *
- * @param string $languageForce
*/
- public static function init(Config $config, $languageForce = null)
- {
+ public static function init(
+ ConfigurationInterface $config,
+ StoreRegistry $storeRegistry,
+ ?string $languageForce = null,
+ ?int $sessionUserId = null
+ ) {
self::$defaultStrings = self::loadLanguage(self::DEFAULT_LANGUAGE);
self::loadAvailableLanguages();
@@ -127,10 +134,10 @@ public static function init(Config $config, $languageForce = null)
}
$user = null;
- if (!empty($_SESSION['php-censor-user-id'])) {
+ if (!empty($sessionUserId)) {
/** @var UserStore $userStore */
- $userStore = Factory::getStore('User');
- $user = $userStore->getById($_SESSION['php-censor-user-id']);
+ $userStore = $storeRegistry->get('User');
+ $user = $userStore->getById($sessionUserId);
}
if ($user) {
@@ -162,12 +169,12 @@ protected static function loadLanguage($language = null)
$langFile = SRC_DIR . 'Languages/lang.' . $language . '.php';
- if (!file_exists($langFile)) {
+ if (!\file_exists($langFile)) {
return null;
}
$strings = include($langFile);
- if (is_null($strings) || !is_array($strings) || !count($strings)) {
+ if (\is_null($strings) || !\is_array($strings) || !\count($strings)) {
return null;
}
@@ -180,8 +187,8 @@ protected static function loadLanguage($language = null)
protected static function loadAvailableLanguages()
{
$matches = [];
- foreach (glob(SRC_DIR . 'Languages/lang.*.php') as $file) {
- if (preg_match('/lang\.([a-z]{2}\-?[a-z]*)\.php/', $file, $matches)) {
+ foreach (\glob(SRC_DIR . 'Languages/lang.*.php') as $file) {
+ if (\preg_match('/lang\.([a-z]{2}\-?[a-z]*)\.php/', $file, $matches)) {
self::$languages[] = $matches[1];
}
}
diff --git a/src/Helper/MailerFactory.php b/src/Helper/MailerFactory.php
index 661c0e37d..fdff20a43 100644
--- a/src/Helper/MailerFactory.php
+++ b/src/Helper/MailerFactory.php
@@ -8,6 +8,11 @@
/**
* Class MailerFactory helps to set up and configure a SwiftMailer object.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class MailerFactory
{
@@ -22,7 +27,7 @@ class MailerFactory
*/
public function __construct($config = [])
{
- if (!is_array($config)) {
+ if (!\is_array($config)) {
$config = [];
}
@@ -69,14 +74,12 @@ public function getMailConfig($configName)
return $this->emailConfig[$configName];
} else {
switch ($configName) {
- case 'smtp_address':
- return '';
case 'default_mailto_address':
+ case 'smtp_encryption':
return null;
case 'smtp_port':
return '25';
- case 'smtp_encryption':
- return null;
+ case 'smtp_address':
default:
return '';
}
diff --git a/src/Helper/SshKey.php b/src/Helper/SshKey.php
index ef74f9ee5..82c812ad4 100644
--- a/src/Helper/SshKey.php
+++ b/src/Helper/SshKey.php
@@ -2,13 +2,25 @@
namespace PHPCensor\Helper;
-use PHPCensor\Config;
+use PHPCensor\Common\Application\ConfigurationInterface;
/**
* Helper class for dealing with SSH keys.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class SshKey
{
+ protected ConfigurationInterface $configuration;
+
+ public function __construct(ConfigurationInterface $configuration)
+ {
+ $this->configuration = $configuration;
+ }
+
/**
* Uses ssh-keygen to generate a public/private key pair.
*
@@ -28,8 +40,8 @@ public function generate()
'ssh_public_key' => ''
];
- $sshStrength = Config::getInstance()->get('php-censor.ssh.strength', 2048);
- $sshComment = Config::getInstance()->get('php-censor.ssh.comment', 'admin@php-censor');
+ $sshStrength = $this->configuration->get('php-censor.ssh.strength', 2048);
+ $sshComment = $this->configuration->get('php-censor.ssh.comment', 'admin@php-censor');
$output = @\shell_exec(
\sprintf(
diff --git a/src/Helper/Template.php b/src/Helper/Template.php
index e1c9e8c0f..1f8c8eba0 100644
--- a/src/Helper/Template.php
+++ b/src/Helper/Template.php
@@ -4,6 +4,12 @@
use voku\helper\AntiXSS;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class Template
{
/**
diff --git a/src/Helper/Xml.php b/src/Helper/Xml.php
index 20c5a9d38..307a3d388 100644
--- a/src/Helper/Xml.php
+++ b/src/Helper/Xml.php
@@ -5,8 +5,15 @@
use DOMDocument;
use Exception;
use LibXMLError;
+use PHPCensor\Helper\Xml\Utf8CleanFilter;
use SimpleXMLElement;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class Xml
{
/**
@@ -15,21 +22,19 @@ class Xml
*/
public static function loadFromFile($filePath)
{
- stream_filter_register('xml_utf8_clean', 'PHPCensor\Helper\Xml\Utf8CleanFilter');
+ \stream_filter_register('xml_utf8_clean', Utf8CleanFilter::class);
try {
- $xml = simplexml_load_file('php://filter/read=xml_utf8_clean/resource=' . $filePath);
- } catch (Exception $ex) {
- $xml = null;
- } catch (\Throwable $ex) { // since php7
+ $xml = \simplexml_load_file('php://filter/read=xml_utf8_clean/resource=' . $filePath);
+ } catch (\Throwable $ex) {
$xml = null;
}
if (!$xml) {
// from https://stackoverflow.com/questions/7766455/how-to-handle-invalid-unicode-with-simplexml/8092672#8092672
- $oldUse = libxml_use_internal_errors(true);
+ $oldUse = \libxml_use_internal_errors(true);
- libxml_clear_errors();
+ \libxml_clear_errors();
$dom = new DOMDocument("1.0", "UTF-8");
@@ -37,15 +42,15 @@ public static function loadFromFile($filePath)
$dom->validateOnParse = false;
$dom->recover = true;
- $dom->loadXML(strtr(
- file_get_contents($filePath),
+ $dom->loadXML(\strtr(
+ \file_get_contents($filePath),
['"' => "'"] // " in attribute names may mislead the parser
));
/** @var LibXMLError $xmlError */
- $xmlError = libxml_get_last_error();
+ $xmlError = \libxml_get_last_error();
if ($xmlError) {
- $warning = sprintf('L%s C%s: %s', $xmlError->line, $xmlError->column, $xmlError->message);
+ $warning = \sprintf('L%s C%s: %s', $xmlError->line, $xmlError->column, $xmlError->message);
print 'WARNING: ignored errors while reading phpunit result, '.$warning."\n";
}
@@ -53,10 +58,10 @@ public static function loadFromFile($filePath)
new SimpleXMLElement('');
}
- $xml = simplexml_import_dom($dom);
+ $xml = \simplexml_import_dom($dom);
- libxml_clear_errors();
- libxml_use_internal_errors($oldUse);
+ \libxml_clear_errors();
+ \libxml_use_internal_errors($oldUse);
}
return $xml;
diff --git a/src/Helper/Xml/Utf8CleanFilter.php b/src/Helper/Xml/Utf8CleanFilter.php
index 5014581ce..e3daafea5 100644
--- a/src/Helper/Xml/Utf8CleanFilter.php
+++ b/src/Helper/Xml/Utf8CleanFilter.php
@@ -4,6 +4,12 @@
use php_user_filter;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class Utf8CleanFilter extends php_user_filter
{
public const PATTERN = '/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u';
@@ -17,11 +23,11 @@ class Utf8CleanFilter extends php_user_filter
*/
public function filter($in, $out, &$consumed, $closing): int
{
- while ($bucket = stream_bucket_make_writeable($in)) {
- $bucket->data = preg_replace(self::PATTERN, '', $bucket->data);
+ while ($bucket = \stream_bucket_make_writeable($in)) {
+ $bucket->data = \preg_replace(self::PATTERN, '', $bucket->data);
$consumed += $bucket->datalen;
- stream_bucket_append($out, $bucket);
+ \stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
diff --git a/src/Http/Request.php b/src/Http/Request.php
deleted file mode 100644
index 92de8f27c..000000000
--- a/src/Http/Request.php
+++ /dev/null
@@ -1,147 +0,0 @@
-parseInput();
-
- $this->data['path'] = $this->getRequestPath();
- $this->data['parts'] = array_values(array_filter(explode('/', $this->data['path'])));
- }
-
- protected function getRequestPath()
- {
- $path = '';
-
- // Start out with the REQUEST_URI:
- if (!empty($_SERVER['REQUEST_URI'])) {
- $path = $_SERVER['REQUEST_URI'];
- }
-
- if ($_SERVER['SCRIPT_NAME'] != $_SERVER['REQUEST_URI']) {
- $scriptPath = str_replace('/index.php', '', $_SERVER['SCRIPT_NAME']);
- $path = str_replace($scriptPath, '', $path);
- }
-
- // Remove index.php from the URL if it is present:
- $path = str_replace(['/index.php', 'index.php'], '', $path);
-
- // Also cut out the query string:
- $path = explode('?', $path);
- $path = array_shift($path);
-
- return $path;
- }
-
- /**
- * Parse incoming variables, incl. $_GET, $_POST and also reads php://input for PUT/DELETE.
- */
- protected function parseInput()
- {
- $params = $_REQUEST;
-
- if (!isset($_SERVER['REQUEST_METHOD']) || in_array($_SERVER['REQUEST_METHOD'], ['PUT', 'DELETE'], true)) {
- $vars = file_get_contents('php://input');
-
- if (!is_string($vars) || strlen(trim($vars)) === 0) {
- $vars = '';
- }
-
- $inputData = [];
- parse_str($vars, $inputData);
-
- $params = array_merge($params, $inputData);
- }
-
- $this->setParams($params);
- }
-
- /**
- * Returns all request parameters.
- * @return array
- */
- public function getParams()
- {
- return $this->params;
- }
-
- /**
- * Return a specific request parameter, or a default value if not set.
- */
- public function getParam($key, $default = null)
- {
- if (isset($this->params[$key])) {
- return $this->params[$key];
- } else {
- return $default;
- }
- }
-
- /**
- * Set or override a request parameter.
- */
- public function setParam($key, $value = null)
- {
- $this->params[$key] = $value;
- }
-
- /**
- * Set an array of request parameters.
- */
- public function setParams(array $params)
- {
- $this->params = array_merge($this->params, $params);
- }
-
- /**
- * Un-set a specific parameter.
- */
- public function unsetParam($key)
- {
- unset($this->params[$key]);
- }
-
- public function getMethod()
- {
- return strtoupper($_SERVER['REQUEST_METHOD']);
- }
-
- public function getPath()
- {
- return $this->data['path'];
- }
-
- public function getPathParts()
- {
- return $this->data['parts'];
- }
-
- public function isAjax()
- {
- if (!isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
- return false;
- }
-
- if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
- return true;
- }
-
- return false;
- }
-}
diff --git a/src/Http/Response.php b/src/Http/Response.php
deleted file mode 100644
index a22c2390a..000000000
--- a/src/Http/Response.php
+++ /dev/null
@@ -1,116 +0,0 @@
-data = $createFrom->getData();
- }
- }
-
- public function getData()
- {
- return $this->data;
- }
-
- public function setResponseCode($code)
- {
- $this->data['code'] = (int)$code;
- }
-
- public function setHeader($key, $val)
- {
- $this->data['headers'][$key] = $val;
- }
-
- public function clearHeaders()
- {
- $this->data['headers'] = [];
- }
-
- public function setContent($content)
- {
- $this->data['body'] = $content;
- }
-
- public function getContent()
- {
- return $this->data['body'];
- }
-
- public function flush()
- {
- $this->sendResponseCode();
-
- if (isset($this->data['headers'])) {
- foreach ($this->data['headers'] as $header => $val) {
- header($header . ': ' . $val, true);
- }
- }
-
- return $this->flushBody();
- }
-
- protected function sendResponseCode()
- {
- if (!isset($this->data['code'])) {
- $this->data['code'] = 200;
- }
-
- switch ($this->data['code']) {
- // 300 class
- case 301:
- $text = 'Moved Permanently';
- break;
- case 302:
- $text = 'Moved Temporarily';
- break;
-
- // 400 class errors
- case 400:
- $text = 'Bad Request';
- break;
- case 401:
- $text = 'Not Authorized';
- break;
- case 403:
- $text = 'Forbidden';
- break;
- case 404:
- $text = 'Not Found';
- break;
-
- // 500 class errors
- case 500:
- $text = 'Internal Server Error';
- break;
-
- // OK
- case 200:
- default:
- $text = 'OK';
- break;
- }
-
- header('HTTP/1.1 ' . $this->data['code'] . ' ' . $text, true, $this->data['code']);
- }
-
- protected function flushBody()
- {
- if (isset($this->data['body'])) {
- return $this->data['body'];
- }
-
- return '';
- }
-
- public function __toString()
- {
- return $this->flush();
- }
-}
diff --git a/src/Http/Response/JsonResponse.php b/src/Http/Response/JsonResponse.php
deleted file mode 100644
index 7310710ac..000000000
--- a/src/Http/Response/JsonResponse.php
+++ /dev/null
@@ -1,25 +0,0 @@
-setContent([]);
- $this->setHeader('Content-Type', 'application/json');
- }
-
- protected function flushBody()
- {
- if (isset($this->data['body'])) {
- return json_encode($this->data['body']);
- }
-
- return json_encode(null);
- }
-}
diff --git a/src/Http/Response/RedirectResponse.php b/src/Http/Response/RedirectResponse.php
deleted file mode 100644
index b4c8f3d5b..000000000
--- a/src/Http/Response/RedirectResponse.php
+++ /dev/null
@@ -1,22 +0,0 @@
-setContent(null);
- $this->setResponseCode(302);
- }
-
- public function flush()
- {
- parent::flush();
- exit(1);
- }
-}
diff --git a/src/Http/Router.php b/src/Http/Router.php
index da0427f16..84b8a2884 100644
--- a/src/Http/Router.php
+++ b/src/Http/Router.php
@@ -3,36 +3,30 @@
namespace PHPCensor\Http;
use PHPCensor\Application;
-use PHPCensor\Config;
-use PHPCensor\Exception\InvalidArgumentException;
-
+use PHPCensor\Common\Exception\InvalidArgumentException;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dan Cryer
+ * @author Dmitry Khomutov
+ */
class Router
{
- /**
- * @var Request;
- */
- protected $request;
+ protected Request $request;
- /**
- * @var Config;
- */
- protected $config;
+ protected Application $application;
- /**
- * @var Application
- */
- protected $application;
+ protected array $routes = [
+ ['route' => '/:controller/:action', 'callback' => null, 'defaults' => []]
+ ];
- /**
- * @var array
- */
- protected $routes = [['route' => '/:controller/:action', 'callback' => null, 'defaults' => []]];
-
- public function __construct(Application $application, Request $request, Config $config)
+ public function __construct(Application $application, Request $request)
{
$this->application = $application;
$this->request = $request;
- $this->config = $config;
}
public function clearRoutes()
@@ -49,73 +43,69 @@ public function clearRoutes()
*/
public function register($route, $options = [], $callback = null)
{
- if (!is_callable($callback)) {
+ if (!\is_callable($callback)) {
throw new InvalidArgumentException('$callback must be callable.');
}
- array_unshift($this->routes, ['route' => $route, 'callback' => $callback, 'defaults' => $options]);
+ \array_unshift($this->routes, ['route' => $route, 'callback' => $callback, 'defaults' => $options]);
}
public function dispatch()
{
foreach ($this->routes as $route) {
- $pathParts = $this->request->getPathParts();
+ $pathParts = $this->request->getPathInfo();
+ $pathParts = \array_values(\array_filter(\explode('/', $pathParts)));
- //-------
- // Set up default values for everything:
- //-------
- $thisNamespace = 'Controller';
$thisController = null;
$thisAction = null;
- if (array_key_exists('namespace', $route['defaults'])) {
- $thisNamespace = $route['defaults']['namespace'];
- }
-
- if (array_key_exists('controller', $route['defaults'])) {
+ if (\array_key_exists('controller', $route['defaults'])) {
$thisController = $route['defaults']['controller'];
}
- if (array_key_exists('action', $route['defaults'])) {
+ if (\array_key_exists('action', $route['defaults'])) {
$thisAction = $route['defaults']['action'];
}
- $routeParts = array_filter(explode('/', $route['route']));
+ $routeParts = \array_filter(\explode('/', $route['route']));
$routeMatches = true;
- while (count($routeParts)) {
- $routePart = array_shift($routeParts);
- $pathPart = array_shift($pathParts);
+ while (\count($routeParts)) {
+ $routePart = \array_shift($routeParts);
+ $pathPart = \array_shift($pathParts);
switch ($routePart) {
- case ':namespace':
- $thisNamespace = !is_null($pathPart) ? $pathPart : $thisNamespace;
- break;
case ':controller':
- $thisController = !is_null($pathPart) ? $pathPart : $thisController;
+ $thisController = !\is_null($pathPart) ? $pathPart : $thisController;
+
break;
case ':action':
- $thisAction = !is_null($pathPart) ? $pathPart : $thisAction;
+ $thisAction = !\is_null($pathPart) ? $pathPart : $thisAction;
+
break;
default:
- if ($routePart != $pathPart) {
+ if ($routePart !== $pathPart) {
$routeMatches = false;
}
}
- if (!$routeMatches || !count($pathParts)) {
+ if (!$routeMatches || !\count($pathParts)) {
break;
}
}
- $thisArgs = $pathParts;
+ foreach ($pathParts as &$pathPart) {
+ if (\is_numeric($pathPart)) {
+ $pathPart = (int)$pathPart;
+ }
+ }
+ unset($pathPart);
if ($routeMatches) {
$route = [
- 'namespace' => $thisNamespace,
'controller' => $thisController,
'action' => $thisAction,
- 'args' => $thisArgs,
+ 'args' => $pathParts,
'callback' => $route['callback']
];
diff --git a/src/Languages/lang.en.php b/src/Languages/lang.en.php
index af7d89ee1..dd7677855 100644
--- a/src/Languages/lang.en.php
+++ b/src/Languages/lang.en.php
@@ -64,6 +64,7 @@
'build_now' => 'Build now',
'build_now_debug' => 'Build now with debug',
'edit_project' => 'Edit Project',
+ 'clone_project' => 'Clone Project',
'delete_project' => 'Delete Project',
'delete_old_builds' => 'Delete old builds',
'delete_all_builds' => 'Delete all builds',
@@ -178,6 +179,17 @@
Services section of your Bitbucket repository.',
+ // Secrets
+ 'secrets' => 'Secrets',
+ 'secret' => 'Secret',
+ 'secret_edit' => 'Edit',
+ 'secret_delete' => 'Delete',
+ 'secret_add' => 'Add Secret',
+ 'secret_add_edit' => 'Add / Edit Secret',
+ 'secret_name' => 'Secret Name',
+ 'secret_value' => 'Secret Value',
+ 'secret_save' => 'Save Secret',
+
// Project Groups
'group_projects' => 'Project groups',
'project_group' => 'Project group',
@@ -199,11 +211,12 @@
'rebuild_now' => 'Rebuild now',
'rebuild_now_debug' => 'Rebuild now with debug',
- 'all_errors' => 'All errors',
- 'only_new' => 'Only new errors',
- 'only_old' => 'Only old errors',
- 'new_errors' => 'New errors',
- 'total_errors' => 'Errors',
+ 'all_errors' => 'All errors',
+ 'only_new' => 'Only new errors',
+ 'only_old' => 'Only old errors',
+ 'new_errors' => 'New errors',
+ 'total_errors' => 'Errors',
+ 'test_coverage' => 'Test coverage',
'committed_by_x' => 'Committed by %s',
'commit_id_x' => 'Commit: %s',
@@ -347,6 +360,7 @@
// Summary plugin
'build-summary' => 'Summary',
'stage' => 'Stage',
+ 'step' => 'Step',
'duration' => 'Duration',
'seconds' => 'sec.',
'plugin' => 'Plugin',
@@ -417,7 +431,6 @@
'deployer' => 'Deployer',
'env' => 'Env',
'grunt' => 'Grunt',
- 'hipchat_notify' => 'Hipchat Notify',
'irc_notify' => 'IRC Notify',
'lint' => 'Lint',
'mysql' => 'MySQL',
diff --git a/src/Languages/lang.es.php b/src/Languages/lang.es.php
index abba6e063..e982c42c0 100644
--- a/src/Languages/lang.es.php
+++ b/src/Languages/lang.es.php
@@ -415,7 +415,6 @@
'deployer' => 'Deployer',
'env' => 'Env',
'grunt' => 'Grunt',
- 'hipchat_notify' => 'Hipchat Notify',
'irc' => 'IRC',
'lint' => 'Lint',
'mysql' => 'MySQL',
diff --git a/src/Languages/lang.fr.php b/src/Languages/lang.fr.php
index dd1fedb69..d0e23ee79 100644
--- a/src/Languages/lang.fr.php
+++ b/src/Languages/lang.fr.php
@@ -405,7 +405,6 @@
'deployer' => 'Deployer',
'env' => 'Env',
'grunt' => 'Grunt',
- 'hipchat_notify' => 'Hipchat Notify',
'irc_notify' => 'IRC Notify',
'lint' => 'Lint',
'mysql' => 'MySQL',
diff --git a/src/Languages/lang.id.php b/src/Languages/lang.id.php
index 7da0b3395..e871d51ce 100644
--- a/src/Languages/lang.id.php
+++ b/src/Languages/lang.id.php
@@ -412,7 +412,6 @@
'deployer' => 'Deployer',
'env' => 'Env',
'grunt' => 'Grunt',
- 'hipchat_notify' => 'Hipchat Notify',
'irc' => 'IRC',
'lint' => 'Lint',
'mysql' => 'MySQL',
diff --git a/src/Languages/lang.my.php b/src/Languages/lang.my.php
index 2d8205437..29099f2d2 100644
--- a/src/Languages/lang.my.php
+++ b/src/Languages/lang.my.php
@@ -86,7 +86,6 @@
'success' => 'Success',
'failed' => 'gagal',
'failed_allowed' => 'Gagal (Dibolehkan)',
- 'error' => 'Error',
'skipped' => 'Dilangkau',
'trace' => 'Stack trace',
'manual_build' => 'Build Manual',
@@ -414,7 +413,6 @@
'deployer' => 'Deployer',
'env' => 'Env',
'grunt' => 'Grunt',
- 'hipchat_notify' => 'Hipchat Notify',
'irc' => 'IRC',
'lint' => 'Lint',
'mysql' => 'MySQL',
diff --git a/src/Languages/lang.pt-br.php b/src/Languages/lang.pt-br.php
index 6f20fad51..b482ff238 100644
--- a/src/Languages/lang.pt-br.php
+++ b/src/Languages/lang.pt-br.php
@@ -423,7 +423,6 @@
'deployer' => 'Deployer',
'env' => 'Env',
'grunt' => 'Grunt',
- 'hipchat_notify' => 'Hipchat Notify',
'irc' => 'IRC',
'lint' => 'Lint',
'mysql' => 'MySQL',
diff --git a/src/Languages/lang.ru.php b/src/Languages/lang.ru.php
index b6448ea2b..80a90a529 100644
--- a/src/Languages/lang.ru.php
+++ b/src/Languages/lang.ru.php
@@ -62,6 +62,7 @@
'build_now' => 'Собрать',
'build_now_debug' => 'Собрать в режиме отладки',
'edit_project' => 'Редактировать проект',
+ 'clone_project' => 'Клонировать проект',
'delete_project' => 'Удалить проект',
'delete_old_builds' => 'Удалить старые сборки',
'delete_all_builds' => 'Удалить все сборки',
@@ -172,6 +173,17 @@
'webhooks_help_bitbucket' => 'Чтобы Автоматически собирать этот проект при публикации новых коммитов, добавьте URL ниже как "POST" сервис в разделе
Services вашего Bitbucket репозитория.',
+ // Secrets
+ 'secrets' => 'Секреты',
+ 'secret' => 'Секрет',
+ 'secret_edit' => 'Редактировать',
+ 'secret_delete' => 'Удалить',
+ 'secret_add' => 'Добавить секрет',
+ 'secret_add_edit' => 'Добавить / изменить секрет',
+ 'secret_name' => 'Название секрета',
+ 'secret_value' => 'Значение секрета',
+ 'secret_save' => 'Сохранить секрет',
+
// Project Groups
'group_projects' => 'Группы проектов',
'project_group' => 'Группа проекта',
@@ -193,11 +205,12 @@
'rebuild_now' => 'Пересобрать',
'rebuild_now_debug' => 'Пересобрать в режиме отладки',
- 'all_errors' => 'Все ошибки',
- 'only_new' => 'Только новые',
- 'only_old' => 'Только старые',
- 'new_errors' => 'Новых ошибок',
- 'total_errors' => 'Ошибок',
+ 'all_errors' => 'Все ошибки',
+ 'only_new' => 'Только новые',
+ 'only_old' => 'Только старые',
+ 'new_errors' => 'Новых ошибок',
+ 'total_errors' => 'Ошибок',
+ 'test_coverage' => 'Покрытие тестами',
'committed_by_x' => 'Отправил %s',
'commit_id_x' => 'Коммит: %s',
@@ -406,7 +419,6 @@
'deployer' => 'Deployer',
'env' => 'Env',
'grunt' => 'Grunt',
- 'hipchat_notify' => 'Hipchat Notify',
'irc_notify' => 'IRC Notify',
'lint' => 'Lint',
'mysql' => 'MySQL',
diff --git a/src/Languages/lang.uk.php b/src/Languages/lang.uk.php
index 35c9d4a38..bd90a8fce 100644
--- a/src/Languages/lang.uk.php
+++ b/src/Languages/lang.uk.php
@@ -3,6 +3,8 @@
return [
'language_name' => 'Українська',
'language' => 'Мова',
+ 'per_page' => 'Кількість елементів на сторінці',
+ 'default' => 'За замовчуванням',
// Log in:
'log_in_to_app' => 'Увійти до PHP Censor',
@@ -34,6 +36,7 @@
'email_address' => 'Email адреса',
'login' => 'Логин / Email адреса',
'password' => 'Пароль',
+ 'remember_me' => 'Запам\'ятати мене',
'log_in' => 'Увійти',
@@ -46,19 +49,24 @@
'branch_x' => 'Гілка: %s',
'created_x' => 'Створено: %s',
'started_x' => 'Розпочато: %s',
+ 'environment_x' => 'Cередовище: %s',
// Sidebar
'hello_name' => 'Привіт, %s',
'dashboard' => 'Панель управління',
'admin_options' => 'Меню адміністратора',
'add_project' => 'Додати проект',
+ 'project_groups' => 'Групи проектів',
'settings' => 'Налаштування',
'manage_users' => 'Управління користувачами',
'plugins' => 'Плагіни',
'view' => 'Переглянути',
'build_now' => 'Зібрати',
+ 'build_now_debug' => 'Зібрати в режимі налагодження',
'edit_project' => 'Редагувати проект',
'delete_project' => 'Видалити проект',
+ 'delete_old_builds' => 'Видалити старі збірки',
+ 'delete_all_builds' => 'Видалити всі збірки',
// Project Summary:
'no_builds_yet' => 'Немає збірок!',
@@ -69,6 +77,8 @@
'last_failed_build' => 'Останньою проваленою збіркою була %s.',
'never_failed_build' => 'У цього проекта ніколи не було провалених збірок.',
'view_project' => 'Переглянути проект',
+ 'projects_with_build_errors' => 'Проекті з помилками збірки',
+ 'no_build_errors' => 'Немає помилок збірки',
// Timeline:
'latest_builds' => 'Останні збірки',
@@ -76,7 +86,11 @@
'running' => 'Виконується',
'success' => 'Успіх',
'failed' => 'Провалена',
+ 'failed_allowed' => 'Припустимий провал',
'manual_build' => 'Ручна збірка',
+ 'error' => 'Помилка',
+ 'skipped' => 'Пропустили',
+ 'trace' => 'Стек виклику',
// Add/Edit Project:
'new_project' => 'Новий проект',
@@ -90,7 +104,8 @@
'gitlab' => 'GitLab',
'git' => 'Git',
'local' => 'Локальний шлях',
- 'hg' => 'Mercurial',
+ 'hg' => 'Mercurial',
+ 'svn' => 'Subversion',
'where_hosted' => 'Де зберігається ваш проект?',
'choose_github' => 'Оберіть GitHub репозиторій:',
@@ -102,6 +117,7 @@
'build_config' => 'Конфігурація збірки цього проекта для PHP Censor
(якщо ви не додали файл .php-censor.yml до репозиторію вашого проекту)',
'default_branch' => 'Назва гілки за замовчуванням',
+ 'default_branch_only' => 'Тільки гілку за замовчуванням',
'allow_public_status' => 'Увімкнути публічну сторінку статусу та зображення для цього проекта?',
'archived' => 'Архівний',
'archived_menu' => 'Архів',
@@ -289,4 +305,100 @@
'passing_build' => 'Успішно збірка',
'failing_build' => 'Невдала збірка',
'log_output' => 'Вивід лога:',
+
+ 'overwrite_build_config' => 'Перезаписати конфігурацію файлу в сховищі конфігурацією в базі даних? Якщо прапорець
+не встановлено, конфігурація в базі даних буде об’єднана з файлом config.',
+ 'environments_label' => 'Середовище (yaml)',
+ 'all' => 'Всі',
+ 'environment' => 'Середовище',
+ 'build_source' => 'Джерело збірки',
+ 'source_unknown' => 'Джерело невідомо',
+ 'source_manual_web' => 'Вручну (з Інтернету)',
+ 'source_manual_console' => 'Вручну (з CLI)',
+ 'source_periodical' => 'Періодичний',
+ 'source_webhook_push' => 'Webhook (Push)',
+ 'source_webhook_pull_request_created' => 'Webhook (створено pull request)',
+ 'source_webhook_pull_request_updated' => 'Webhook (оновлено pull request) ',
+ 'source_webhook_pull_request_approved' => 'Webhook (схвалено pull request) ',
+ 'source_webhook_pull_request_merged' => 'Webhook (об\'єднано pull request) ',
+ 'group_projects' => 'Групи проектів',
+ 'project_group' => 'Група проекту',
+ 'group_count' => 'Кількість проектів',
+ 'group_edit' => 'Редагувати групу',
+ 'group_delete' => 'Видалити групу',
+ 'group_add' => 'Додати групу',
+ 'group_add_edit' => 'Додати / редагувати групу',
+ 'group_title' => 'Назва групи',
+ 'group_save' => 'Зберігти групу',
+ 'errors' => 'Помилки',
+ 'information' => 'Інформаця',
+ 'is_new' => 'Нова?',
+ 'new' => 'Нова',
+ 'rebuild_now_debug' => 'Перезібраті в режимі налагодження',
+ 'all_errors' => 'Всі помилки',
+ 'only_new' => 'Тільки нові',
+ 'only_old' => 'Тількі старі',
+ 'new_errors' => 'Нові помилки',
+ 'total_errors' => 'Всього помилок',
+ 'classes' => 'Класів',
+ 'methods' => 'Методів',
+ 'coverage' => 'Покриття коду тестами PHPUnit',
+ 'phan_warnings' => 'Попередження phan',
+ 'php_cs_fixer_warnings' => 'Попередження PHP CS Fixer',
+ 'php_cpd_warnings' => 'Попередження PHP Copy/Paste Detector',
+ 'php_tal_lint_warnings' => 'Попередження PHP Tal Lint',
+ 'php_tal_lint_errors' => 'Помилки PHP Tal Lint',
+ 'behat_warnings' => 'Попередження Behat',
+ 'sensiolabs_insight_warnings' => 'Попередження Sensiolabs Insight',
+ 'technical_debt_warnings' => 'Попередження Technical Debt',
+ 'merged_branches' => 'Гілки, що об’єднуються',
+ 'codeception_feature' => 'Властивість',
+ 'codeception_suite' => 'Набір',
+ 'codeception_time' => 'Час',
+ 'codeception_synopsis' => 'Тестов виконано: %1$d (за %2$f сек.).
+Невдач : %3$d.',
+ 'suite' => 'Набір',
+ 'test' => 'Тест',
+ 'build-summary' => 'Зведення',
+ 'stage' => 'Етап',
+ 'duration' => 'Тривалість',
+ 'seconds' => 'сек.',
+ 'plugin' => 'Плагін',
+ 'stage_setup' => 'Встановлення',
+ 'stage_test' => 'Тестування',
+ 'stage_deploy' => 'Розгортання',
+ 'stage_complete' => 'Завершення',
+ 'stage_success' => 'Успішне завершення',
+ 'stage_failure' => 'Невдача',
+ 'stage_broken' => 'Поломка',
+ 'stage_fixed' => 'Виправлення',
+ 'severity' => 'Рівень',
+ 'all_plugins' => 'Всі плагіни',
+ 'all_severities' => 'Всі рівні',
+ 'filters' => 'Фільтри',
+ 'errors_selected' => 'Помилок вибрано',
+ 'build_details' => 'Інформація про збірку',
+ 'commit_details' => 'Інформація про комміт',
+ 'committer' => 'Автор комміту',
+ 'commit_message' => 'Повідомлення в комміті',
+ 'timing' => 'Таймінг',
+ 'created' => 'Створено',
+ 'started' => 'Почалося',
+ 'finished' => 'Закінчено',
+ 'add_to_queue_failed' => 'Збірка успішно створена, але виникла проблема при додаванні збірки в чергу.
+Зазвичай таке відбувається, коли PHP Censor намагається працювати з неіснуючим або зупиненим
+сервером черг Beanstalkd.',
+ 'critical' => 'Критичний',
+ 'high' => 'Високий',
+ 'normal' => 'Нормальний',
+ 'low' => 'Низький',
+ 'confirm_message' => 'Елемент буде видалений назавжди. Ви впевнені?',
+ 'confirm_title' => 'Підтвердження видалення',
+ 'confirm_ok' => 'Видалити',
+ 'confirm_cancel' => 'Відміна',
+ 'confirm_success' => 'Елемент успішно видалений.',
+ 'confirm_failed' => 'Видалення провалилося! Відповідь сервера: ',
+ 'public_status_title' => 'Публічний статус',
+ 'public_status_image' => 'Іконка статусу',
+ 'public_status_page' => 'Сторінка публічного статусу',
];
diff --git a/src/Logging/AnsiFormatter.php b/src/Logging/AnsiFormatter.php
index c53eee86d..de95098c2 100644
--- a/src/Logging/AnsiFormatter.php
+++ b/src/Logging/AnsiFormatter.php
@@ -1,9 +1,17 @@
+ */
class AnsiFormatter extends LineFormatter
{
/**
@@ -11,7 +19,7 @@ class AnsiFormatter extends LineFormatter
*/
public function format(array $record): string
{
- return str_replace(
+ return \str_replace(
["\033[0;31m", "\033[0m", "\033[0;32m", "\033[0;36m"],
'',
parent::format($record)
diff --git a/src/Logging/BuildDBLogHandler.php b/src/Logging/BuildDBLogHandler.php
index 7e3706d83..a0cfbd9a9 100644
--- a/src/Logging/BuildDBLogHandler.php
+++ b/src/Logging/BuildDBLogHandler.php
@@ -1,52 +1,59 @@
*/
class BuildDBLogHandler extends AbstractProcessingHandler
{
- /**
- * @var Build
- */
- protected $build;
+ protected Build $build;
+ protected BuildStore $buildStore;
+ private SecretStore $secretStore;
- protected $logValue;
+ protected string $logValue;
/**
* @var int last flush timestamp
*/
- protected $flushTimestamp = 0;
+ protected int $flushTimestamp = 0;
/**
* @var int flush delay, seconds
*/
- protected $flushDelay = 1;
+ protected int $flushDelay = 1;
- /**
- * @param bool $level
- * @param bool $bubble
- */
public function __construct(
+ SecretStore $secretStore,
+ BuildStore $buildStore,
Build $build,
- $level = LogLevel::INFO,
- $bubble = true
+ int $level = Logger::INFO,
+ bool $bubble = true
) {
parent::__construct($level, $bubble);
- $this->build = $build;
+
+ $this->secretStore = $secretStore;
+ $this->build = $build;
+ $this->buildStore = $buildStore;
+
// We want to add to any existing saved log information.
- $this->logValue = $build->getLog();
+ $this->logValue = (string)$build->getLog();
}
- /**
- * Destructor
- */
public function __destruct()
{
$this->flushData();
@@ -55,11 +62,45 @@ public function __destruct()
/**
* Flush buffered data
*/
- protected function flushData()
+ protected function flushData(): void
{
$this->build->setLog($this->logValue);
- Factory::getStore('Build')->save($this->build);
- $this->flushTimestamp = time();
+ $this->buildStore->save($this->build);
+
+ $this->flushTimestamp = \time();
+ }
+
+ private function sanitize(string $message): string
+ {
+ return \str_replace([
+ '\/',
+ '//',
+ $this->build->getBuildPath(),
+ ROOT_DIR,
+ ], [
+ '/',
+ '//',
+ '/',
+ '/',
+ ], $message);
+ }
+
+ private function sanitizeSecrets(string $message): string
+ {
+ $replace = [];
+ $secrets = $this->secretStore->getAll();
+ if (\count($secrets['items']) > 0) {
+ /** @var Secret $secret */
+ foreach ($secrets['items'] as $secret) {
+ $value = $secret->getValue();
+ $name = '%' . \sprintf('SECRET:%s', $secret->getName()) . '%';
+ if (\trim($value)) {
+ $replace[$name] = $secret->getValue();
+ }
+ }
+ }
+
+ return \str_replace($replace, \array_keys($replace), $message);
}
/**
@@ -67,14 +108,13 @@ protected function flushData()
*/
protected function write(array $record): void
{
- $message = (string)$record['message'];
- $message = str_replace(['\/', '//'], '/', $message);
- $message = str_replace($this->build->getBuildPath(), '/', $message);
- $message = str_replace(ROOT_DIR, '/', $message);
-
- $this->logValue .= $message . PHP_EOL;
+ $this->logValue .= $this->sanitize(
+ $this->sanitizeSecrets(
+ (string)$record['message']
+ )
+ ) . PHP_EOL;
- if ($this->flushTimestamp < (time() - $this->flushDelay)) {
+ if ($this->flushTimestamp < (\time() - $this->flushDelay)) {
$this->flushData();
}
}
diff --git a/src/Logging/BuildLogger.php b/src/Logging/BuildLogger.php
index c0e3acef4..521831a78 100644
--- a/src/Logging/BuildLogger.php
+++ b/src/Logging/BuildLogger.php
@@ -1,27 +1,24 @@
*/
-class BuildLogger implements LoggerAwareInterface
+class BuildLogger
{
- /**
- * @var LoggerInterface
- */
- protected $logger;
+ private LoggerInterface $logger;
- /**
- * @var Build
- */
- protected $build;
+ private Build $build;
public function __construct(LoggerInterface $logger, Build $build)
{
@@ -29,26 +26,12 @@ public function __construct(LoggerInterface $logger, Build $build)
$this->build = $build;
}
- /**
- * Add an entry to the build log.
- *
- * @param string|string[] $message
- * @param string $level
- * @param mixed[] $context
- */
- public function log($message, $level = LogLevel::INFO, $context = [])
+ public function log($message, string $level = LogLevel::INFO, array $context = []): void
{
- // Skip if no logger has been loaded.
- if (!$this->logger) {
- return;
- }
-
- if (!is_array($message)) {
+ if (!\is_array($message)) {
$message = [$message];
}
- // The build is added to the context so the logger can use
- // details from it if required.
$context['build'] = $this->build->getId();
foreach ($message as $item) {
@@ -56,39 +39,21 @@ public function log($message, $level = LogLevel::INFO, $context = [])
}
}
- /**
- * Add a warning-coloured message to the log.
- *
- * @param string $message
- */
- public function logWarning($message)
+ public function logWarning(string $message): void
{
$this->log("\033[0;31m" . $message . "\033[0m");
}
- /**
- * Add a success-coloured message to the log.
- *
- * @param string $message
- */
- public function logSuccess($message)
+ public function logSuccess(string $message): void
{
$this->log("\033[0;32m" . $message . "\033[0m");
}
- /**
- * Add a failure-coloured message to the log.
- *
- * @param string $message
- * @param Exception $exception The exception that caused the error.
- */
- public function logFailure($message, Exception $exception = null)
+ public function logFailure(string $message, ?\Throwable $exception = null): void
{
$level = LogLevel::INFO;
$context = [];
- // The psr3 log interface stipulates that exceptions should be passed
- // as the exception key in the context array.
if ($exception) {
$level = LogLevel::ERROR;
@@ -99,23 +64,10 @@ public function logFailure($message, Exception $exception = null)
$this->log("\033[0;31m" . $message . "\033[0m", $level, $context);
}
- /**
- * Add a debug-coloured message to the log.
- *
- * @param string $message
- */
- public function logDebug($message)
+ public function logDebug(string $message): void
{
if ($this->build->isDebug()) {
$this->log("\033[0;36m" . $message . "\033[0m", LogLevel::DEBUG);
}
}
-
- /**
- * Sets a logger instance on the object
- */
- public function setLogger(LoggerInterface $logger)
- {
- $this->logger = $logger;
- }
}
diff --git a/src/Logging/Handler.php b/src/Logging/Handler.php
index 1cd975e3e..5ff2a419a 100644
--- a/src/Logging/Handler.php
+++ b/src/Logging/Handler.php
@@ -1,5 +1,7 @@
*/
class Handler
{
- /**
- * @var array
- */
- protected $levels = [
+ protected array $levels = [
E_WARNING => 'Warning',
E_NOTICE => 'Notice',
E_USER_ERROR => 'User Error',
@@ -26,46 +28,33 @@ class Handler
E_USER_DEPRECATED => 'User Deprecated',
];
- /**
- * @var LoggerInterface
- */
- protected $logger;
+ protected ?LoggerInterface $logger;
- /**
- */
- public function __construct(LoggerInterface $logger = null)
+ public function __construct(?LoggerInterface $logger = null)
{
$this->logger = $logger;
}
- /**
- * Register a new log handler.
- */
- public static function register(LoggerInterface $logger = null)
+ public static function register(?LoggerInterface $logger = null): void
{
$handler = new static($logger);
- set_error_handler([$handler, 'handleError']);
- register_shutdown_function([$handler, 'handleFatalError']);
+ \set_error_handler([$handler, 'handleError']);
+ \register_shutdown_function([$handler, 'handleFatalError']);
- set_exception_handler([$handler, 'handleException']);
+ \set_exception_handler([$handler, 'handleException']);
}
/**
- * @param int $level
- * @param string $message
- * @param string $file
- * @param int $line
- *
* @throws ErrorException
*/
- public function handleError($level, $message, $file, $line)
+ public function handleError(int $level, string $message, string $file, int $line): void
{
- if (error_reporting() & $level) {
- $exceptionLevel = isset($this->levels[$level]) ? $this->levels[$level] : $level;
+ if (\error_reporting() & $level) {
+ $exceptionLevel = $this->levels[$level] ?? $level;
throw new ErrorException(
- sprintf('%s: %s in %s line %d', $exceptionLevel, $message, $file, $line),
+ \sprintf('%s: %s in %s line %d', $exceptionLevel, $message, $file, $line),
0,
$level,
$file,
@@ -74,17 +63,14 @@ public function handleError($level, $message, $file, $line)
}
}
- /**
- * @throws ErrorException
- */
- public function handleFatalError()
+ public function handleFatalError(): void
{
- $fatalError = error_get_last();
+ $fatalError = \error_get_last();
try {
- if (($error = error_get_last()) !== null) {
+ if (\error_get_last() !== null) {
$error = new ErrorException(
- sprintf(
+ \sprintf(
'%s: %s in %s line %d',
$fatalError['type'],
$fatalError['message'],
@@ -98,9 +84,9 @@ public function handleFatalError()
);
$this->log($error);
}
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
$error = new ErrorException(
- sprintf(
+ \sprintf(
'%s: %s in %s line %d',
$fatalError['type'],
$fatalError['message'],
@@ -116,22 +102,17 @@ public function handleFatalError()
}
}
- /**
- */
- public function handleException($exception)
+ public function handleException(\Throwable $exception): void
{
$this->log($exception);
}
- /**
- * Write to the build log.
- */
- protected function log($exception)
+ protected function log(\Throwable $exception): void
{
if (null !== $this->logger) {
- $message = sprintf(
+ $message = \sprintf(
'%s: %s (uncaught exception) at %s line %s',
- get_class($exception),
+ \get_class($exception),
$exception->getMessage(),
$exception->getFile(),
$exception->getLine()
diff --git a/src/Logging/OutputLogHandler.php b/src/Logging/OutputLogHandler.php
index 593d1fdd3..1b4f0a7f4 100644
--- a/src/Logging/OutputLogHandler.php
+++ b/src/Logging/OutputLogHandler.php
@@ -1,5 +1,7 @@
*/
class OutputLogHandler extends AbstractProcessingHandler
{
- /**
- * @var OutputInterface
- */
- protected $output;
+ protected OutputInterface $output;
- /**
- * @param bool|string $level
- * @param bool $bubble
- */
public function __construct(
OutputInterface $output,
- $level = LogLevel::INFO,
- $bubble = true
+ string $level = LogLevel::INFO,
+ bool $bubble = true
) {
parent::__construct($level, $bubble);
diff --git a/src/Migrations/20200505070903_initial_migration_v2.php b/src/Migrations/20200505070903_initial_migration_v2.php
index f4f53efe9..19240c445 100644
--- a/src/Migrations/20200505070903_initial_migration_v2.php
+++ b/src/Migrations/20200505070903_initial_migration_v2.php
@@ -1,10 +1,19 @@
+ */
+final class InitialMigrationV2 extends AbstractMigration
{
private const LATEST_V1_MIGRATION_NAME = 'FixedPhpStanPluginName';
@@ -27,7 +36,7 @@ private function isNewInstallationUp(): bool
}
if ($isIssetBuild || ($isIssetBuilds && !$this->getLatestV1Migration())) {
- throw new \RuntimeException(
+ throw new RuntimeException(
'You should upgrade your PHP Censor to latest 1.3 release before you can upgrade it to release 2.0'
);
}
@@ -149,7 +158,7 @@ public function up()
->save();
$projectGroups
- ->addColumn('title', 'string', ['limit' => 100, 'null' => false])
+ ->addColumn('title', 'string', ['limit' => 100])
->addColumn('create_date', 'datetime')
->addColumn('user_id', 'integer', ['null' => true])
diff --git a/src/Migrations/20220223061912_webhook_requests_new_table.php b/src/Migrations/20220223061912_webhook_requests_new_table.php
new file mode 100644
index 000000000..8c41cca44
--- /dev/null
+++ b/src/Migrations/20220223061912_webhook_requests_new_table.php
@@ -0,0 +1,52 @@
+table('webhook_requests');
+
+ $databaseType = $this->getAdapter()->getAdapterType();
+ $payloadOptions = ['null' => true];
+ if ('mysql' === $databaseType) {
+ $payloadOptions['limit'] = MysqlAdapter::TEXT_LONG;
+ }
+
+ $webhookRequests
+ ->addColumn('project_id', 'integer')
+ ->addColumn('webhook_type', 'string', ['limit' => 50])
+ ->addColumn('payload', 'text', $payloadOptions)
+ ->addColumn('create_date', 'datetime')
+
+ ->addIndex(['project_id'])
+
+ ->save();
+
+ $webhookRequests
+ ->addForeignKey(
+ 'project_id',
+ 'projects',
+ 'id',
+ ['delete' => 'CASCADE', 'update' => 'CASCADE']
+ )
+ ->save();
+ }
+
+ public function down()
+ {
+ $webhookRequests = $this->table('webhook_requests');
+
+ $webhookRequests
+ ->dropForeignKey('project_id')
+ ->save();
+
+ $webhookRequests
+ ->drop()
+ ->save();
+ }
+}
diff --git a/src/Migrations/20220429095102_dashboard_coverage.php b/src/Migrations/20220429095102_dashboard_coverage.php
new file mode 100644
index 000000000..9d0ca0c66
--- /dev/null
+++ b/src/Migrations/20220429095102_dashboard_coverage.php
@@ -0,0 +1,30 @@
+table('builds');
+
+ $builds
+ ->addColumn('test_coverage', 'string', ['limit' => 10, 'null' => true])
+ ->addColumn('test_coverage_previous', 'string', ['limit' => 10, 'null' => true])
+
+ ->save();
+ }
+
+ public function down()
+ {
+ $builds = $this->table('builds');
+
+ $builds
+ ->removeColumn('test_coverage')
+ ->removeColumn('test_coverage_previous')
+
+ ->save();
+ }
+}
diff --git a/src/Migrations/20220604191600_secrets_new_table.php b/src/Migrations/20220604191600_secrets_new_table.php
new file mode 100644
index 000000000..e7e426037
--- /dev/null
+++ b/src/Migrations/20220604191600_secrets_new_table.php
@@ -0,0 +1,48 @@
+table('secrets');
+
+ $databaseType = $this->getAdapter()->getAdapterType();
+ $payloadOptions = [];
+ if ('mysql' === $databaseType) {
+ $payloadOptions['limit'] = MysqlAdapter::TEXT_REGULAR;
+ }
+
+ $secrets
+ ->addColumn('name', 'string', ['limit' => 100])
+ ->addColumn('value', 'text', $payloadOptions)
+ ->addColumn('create_date', 'datetime')
+ ->addColumn('user_id', 'integer', ['null' => true])
+
+ ->addIndex(['name'], ['unique' => true])
+
+ ->save();
+
+ $secrets
+ ->addForeignKey(
+ 'user_id',
+ 'users',
+ 'id',
+ ['delete' => 'SET NULL', 'update' => 'CASCADE']
+ )
+ ->save();
+ }
+
+ public function down()
+ {
+ $secrets = $this->table('secrets');
+
+ $secrets
+ ->drop()
+ ->save();
+ }
+}
diff --git a/src/Model.php b/src/Model.php
index d26e0e102..61afbb94f 100644
--- a/src/Model.php
+++ b/src/Model.php
@@ -4,27 +4,61 @@
namespace PHPCensor;
+use DateTime;
+use Exception;
+
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dan Cryer
+ * @author Dmitry Khomutov
+ */
class Model
{
- /**
- * @var array
- */
- protected $data = [];
+ protected array $data = [];
- /**
- * @var array
- */
- protected $modified = [];
+ protected array $dataTypes = [];
+
+ private array $modified = [];
+
+ protected StoreRegistry $storeRegistry;
+
+ public function __construct(
+ StoreRegistry $storeRegistry,
+ array $initialData = []
+ ) {
+ if (!isset($this->dataTypes['id'])) {
+ $this->dataTypes['id'] = 'integer';
+ }
+
+ foreach ($initialData as $column => $value) {
+ $this->setDataItem($column, $this->castToDataType($this->getDataType($column), $value));
+ }
+
+ $this->storeRegistry = $storeRegistry;
+ }
- public function __construct(array $initialData = [])
+ public function getDataType(string $column): string
{
- if (is_array($initialData)) {
- foreach ($initialData as $index => $item) {
- if (array_key_exists($index, $this->data)) {
- $this->data[$index] = $item;
- }
- }
+ return $this->dataTypes[$column] ?? 'string';
+ }
+
+ protected function getDataItem(string $column, $defaultValue = null)
+ {
+ return $this->castToDataType($this->getDataType($column), $this->data[$column] ?? $defaultValue);
+ }
+
+ protected function setDataItem(string $column, $value): bool
+ {
+ if (!\array_key_exists($column, $this->data) || $this->data[$column] === $value) {
+ return false;
}
+
+ $this->data[$column] = $value;
+ $this->modified[$column] = $column;
+
+ return true;
}
public function getDataArray(): array
@@ -37,10 +71,67 @@ public function getModified(): array
return $this->modified;
}
- protected function setModified(string $column): bool
+ /**
+ * @return mixed
+ */
+ private function castToDataType(string $type, $value)
{
- $this->modified[$column] = $column;
+ if ($value === null) {
+ return null;
+ }
- return true;
+ switch ($type) {
+ case 'int':
+ case 'integer':
+ return \is_integer($value) ? $value : \intval($value);
+
+ case 'bool':
+ case 'boolean':
+ return \is_bool($value) ? $value : \boolval($value);
+
+ case 'float':
+ return \is_float($value) ? $value : \floatval($value);
+
+ case 'array':
+ return \is_array($value) ? $value : \json_decode($value, true);
+
+ case 'datetime':
+ if (\is_a($value, DateTime::class)) {
+ return $value;
+ }
+ try {
+ return new DateTime($value);
+ } catch (\Throwable $e) {
+ return null;
+ }
+
+ case 'newline':
+ if (!\is_string($value)) {
+ return $value;
+ }
+
+ return \array_values(
+ \array_filter(
+ \array_map(
+ 'trim',
+ \explode("\n", $value)
+ )
+ )
+ );
+
+
+ default:
+ return $value;
+ }
+ }
+
+ public function getId(): ?int
+ {
+ return $this->getDataItem('id');
+ }
+
+ public function setId(?int $value): bool
+ {
+ return $this->setDataItem('id', $value);
}
}
diff --git a/src/Model/Base/Build.php b/src/Model/Base/Build.php
index fbe7d5bdf..4eb10dd30 100644
--- a/src/Model/Base/Build.php
+++ b/src/Model/Base/Build.php
@@ -6,13 +6,25 @@
use DateTime;
use Exception;
-use PHPCensor\Exception\InvalidArgumentException;
+use PHPCensor\Common\Exception\InvalidArgumentException;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model;
use PHPCensor\Store\BuildStore;
-use PHPCensor\Store\Factory;
-
+use PHPCensor\Traits\Model\HasCreateDateTrait;
+use PHPCensor\Traits\Model\HasUserIdTrait;
+
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dan Cryer
+ * @author Dmitry Khomutov
+ */
class Build extends Model
{
+ use HasUserIdTrait;
+ use HasCreateDateTrait;
+
public const STATUS_PENDING = 0;
public const STATUS_RUNNING = 1;
public const STATUS_SUCCESS = 2;
@@ -30,46 +42,55 @@ class Build extends Model
public const SOURCE_MANUAL_REBUILD_WEB = 9;
public const SOURCE_MANUAL_REBUILD_CONSOLE = 10;
- /**
- * @var array
- */
- protected $data = [
- 'id' => null,
- 'parent_id' => null,
- 'project_id' => null,
- 'commit_id' => null,
- 'status' => null,
- 'log' => null,
- 'branch' => null,
- 'tag' => null,
- 'create_date' => null,
- 'start_date' => null,
- 'finish_date' => null,
- 'committer_email' => null,
- 'commit_message' => null,
- 'extra' => null,
- 'environment_id' => null,
- 'source' => Build::SOURCE_UNKNOWN,
- 'user_id' => null,
- 'errors_total' => null,
- 'errors_total_previous' => null,
- 'errors_new' => null,
+ protected array $data = [
+ 'id' => null,
+ 'parent_id' => null,
+ 'project_id' => null,
+ 'commit_id' => null,
+ 'status' => null,
+ 'log' => null,
+ 'branch' => null,
+ 'tag' => null,
+ 'create_date' => null,
+ 'start_date' => null,
+ 'finish_date' => null,
+ 'committer_email' => null,
+ 'commit_message' => null,
+ 'extra' => [],
+ 'environment_id' => null,
+ 'source' => Build::SOURCE_UNKNOWN,
+ 'user_id' => null,
+ 'errors_total' => null,
+ 'errors_total_previous' => null,
+ 'errors_new' => null,
+ 'test_coverage' => null,
+ 'test_coverage_previous' => null,
];
- /**
- * @var array
- */
- protected $allowedStatuses = [
+ protected array $dataTypes = [
+ 'project_id' => 'integer',
+ 'status' => 'integer',
+ 'create_date' => 'datetime',
+ 'start_date' => 'datetime',
+ 'finish_date' => 'datetime',
+ 'extra' => 'array',
+ 'environment_id' => 'integer',
+ 'source' => 'integer',
+ 'user_id' => 'integer',
+ 'errors_total' => 'integer',
+ 'errors_total_previous' => 'integer',
+ 'errors_new' => 'integer',
+ 'parent_id' => 'integer',
+ ];
+
+ protected array $allowedStatuses = [
self::STATUS_PENDING,
self::STATUS_RUNNING,
self::STATUS_SUCCESS,
self::STATUS_FAILED,
];
- /**
- * @var array
- */
- protected $allowedSources = [
+ protected array $allowedSources = [
self::SOURCE_UNKNOWN,
self::SOURCE_MANUAL_WEB,
self::SOURCE_MANUAL_CONSOLE,
@@ -83,557 +104,322 @@ class Build extends Model
self::SOURCE_WEBHOOK_PULL_REQUEST_MERGED,
];
- /**
- * @return int
- */
- public function getId()
+ public function getParentId(): ?int
{
- return (int)$this->data['id'];
+ return $this->getDataItem('parent_id');
}
- /**
- * @return bool
- */
- public function setId(int $value)
+ public function setParentId(?int $value): bool
{
- if ($this->data['id'] === $value) {
- return false;
- }
-
- $this->data['id'] = (int)$value;
-
- return $this->setModified('id');
+ return $this->setDataItem('parent_id', $value);
}
- /**
- * @return int|null
- */
- public function getParentId()
+ public function getProjectId(): ?int
{
- return (null !== $this->data['parent_id']) ? (int)$this->data['parent_id'] : null;
+ return $this->getDataItem('project_id');
}
- /**
- * @return bool
- */
- public function setParentId(?int $value)
+ public function setProjectId(int $value): bool
{
- if ($this->data['parent_id'] === $value) {
- return false;
- }
-
- $this->data['parent_id'] = $value;
-
- return $this->setModified('parent_id');
+ return $this->setDataItem('project_id', $value);
}
- /**
- * @return int
- */
- public function getProjectId()
+ public function getCommitId(): ?string
{
- return (int)$this->data['project_id'];
+ return $this->getDataItem('commit_id');
}
- /**
- * @return bool
- */
- public function setProjectId(int $value)
+ public function setCommitId(string $value): bool
{
- if ($this->data['project_id'] === $value) {
- return false;
- }
-
- $this->data['project_id'] = $value;
-
- return $this->setModified('project_id');
+ return $this->setDataItem('commit_id', $value);
}
- /**
- * @return string
- */
- public function getCommitId()
+ public function getStatus(): ?int
{
- return $this->data['commit_id'];
+ return $this->getDataItem('status');
}
/**
- * @return bool
- */
- public function setCommitId(string $value)
- {
- if ($this->data['commit_id'] === $value) {
- return false;
- }
-
- $this->data['commit_id'] = $value;
-
- return $this->setModified('commit_id');
- }
-
- /**
- * @return int
- */
- public function getStatus()
- {
- return (int)$this->data['status'];
- }
-
- /**
- * @return bool
- *
* @throws InvalidArgumentException
*/
- public function setStatus(int $value)
+ public function setStatus(int $value): bool
{
- if (!in_array($value, $this->allowedStatuses, true)) {
+ if (!\in_array($value, $this->allowedStatuses, true)) {
throw new InvalidArgumentException(
- 'Column "status" must be one of: ' . join(', ', $this->allowedStatuses) . '.'
+ 'Column "status" must be one of: ' . \join(', ', $this->allowedStatuses) . '.'
);
}
- if ($this->data['status'] === $value) {
- return false;
- }
-
- $this->data['status'] = $value;
-
- return $this->setModified('status');
+ return $this->setDataItem('status', $value);
}
- public function setStatusPending()
+ public function setStatusPending(): bool
{
- if (self::STATUS_PENDING !== $this->data['status']) {
- $this->setModified('status');
- }
-
- $this->data['status'] = self::STATUS_PENDING;
+ return $this->setDataItem('status', self::STATUS_PENDING);
}
- public function setStatusRunning()
+ public function setStatusRunning(): bool
{
- if (self::STATUS_RUNNING !== $this->data['status']) {
- $this->setModified('status');
- }
-
- $this->data['status'] = self::STATUS_RUNNING;
+ return $this->setDataItem('status', self::STATUS_RUNNING);
}
- public function setStatusSuccess()
+ public function setStatusSuccess(): bool
{
- if (self::STATUS_SUCCESS !== $this->data['status']) {
- $this->setModified('status');
- }
-
- $this->data['status'] = self::STATUS_SUCCESS;
+ return $this->setDataItem('status', self::STATUS_SUCCESS);
}
- public function setStatusFailed()
+ public function setStatusFailed(): bool
{
- if (self::STATUS_FAILED !== $this->data['status']) {
- $this->setModified('status');
- }
-
- $this->data['status'] = self::STATUS_FAILED;
+ return $this->setDataItem('status', self::STATUS_FAILED);
}
- /**
- * @return string
- */
- public function getLog()
+ public function getLog(): ?string
{
- return $this->data['log'];
+ return $this->getDataItem('log');
}
- /**
- * @return bool
- */
- public function setLog(?string $value)
+ public function setLog(?string $value): bool
{
- if ($this->data['log'] === $value) {
- return false;
- }
-
- $this->data['log'] = $value;
-
- return $this->setModified('log');
+ return $this->setDataItem('log', $value);
}
- /**
- * @return string
- */
- public function getBranch()
+ public function getBranch(): ?string
{
- return $this->data['branch'];
+ return $this->getDataItem('branch');
}
- /**
- * @return bool
- */
public function setBranch(string $value)
{
- if ($this->data['branch'] === $value) {
- return false;
- }
-
- $this->data['branch'] = $value;
-
- return $this->setModified('branch');
+ return $this->setDataItem('branch', $value);
}
- /**
- * @return string
- */
- public function getTag()
+ public function getTag(): ?string
{
- return $this->data['tag'];
+ return $this->getDataItem('tag');
}
- /**
- * @return bool
- */
- public function setTag(?string $value)
+ public function setTag(?string $value): bool
{
- if ($this->data['tag'] === $value) {
- return false;
- }
-
- $this->data['tag'] = $value;
-
- return $this->setModified('tag');
+ return $this->setDataItem('tag', $value);
}
- /**
- * @return DateTime|null
- *
- * @throws Exception
- */
- public function getCreateDate()
+ public function getStartDate(): ?DateTime
{
- if ($this->data['create_date']) {
- return new DateTime($this->data['create_date']);
- }
-
- return null;
+ return $this->getDataItem('start_date');
}
- /**
- * @return bool
- */
- public function setCreateDate(DateTime $value)
+ public function setStartDate(DateTime $value): bool
{
- $stringValue = $value->format('Y-m-d H:i:s');
-
- if ($this->data['create_date'] === $stringValue) {
- return false;
- }
-
- $this->data['create_date'] = $stringValue;
-
- return $this->setModified('create_date');
+ return $this->setDataItem('start_date', $value);
}
- /**
- * @return DateTime|null
- *
- * @throws Exception
- */
- public function getStartDate()
+ public function getFinishDate(): ?DateTime
{
- if ($this->data['start_date']) {
- return new DateTime($this->data['start_date']);
- }
-
- return null;
+ return $this->getDataItem('finish_date');
}
- /**
- * @return bool
- */
- public function setStartDate(DateTime $value)
+ public function setFinishDate(DateTime $value): bool
{
- $stringValue = $value->format('Y-m-d H:i:s');
-
- if ($this->data['start_date'] === $stringValue) {
- return false;
- }
-
- $this->data['start_date'] = $stringValue;
-
- return $this->setModified('start_date');
+ return $this->setDataItem('finish_date', $value);
}
- /**
- * @return DateTime|null
- *
- * @throws Exception
- */
- public function getFinishDate()
+ public function getCommitterEmail(): ?string
{
- if ($this->data['finish_date']) {
- return new DateTime($this->data['finish_date']);
- }
-
- return null;
+ return $this->getDataItem('committer_email');
}
- /**
- * @return bool
- */
- public function setFinishDate(DateTime $value)
+ public function setCommitterEmail(?string $value): bool
{
- $stringValue = $value->format('Y-m-d H:i:s');
-
- if ($this->data['finish_date'] === $stringValue) {
- return false;
- }
-
- $this->data['finish_date'] = $stringValue;
+ return $this->setDataItem('committer_email', $value);
+ }
- return $this->setModified('finish_date');
+ public function getCommitMessage(): ?string
+ {
+ return $this->getDataItem('commit_message');
}
- /**
- * @return string
- */
- public function getCommitterEmail()
+ public function setCommitMessage(?string $value): bool
{
- return $this->data['committer_email'];
+ return $this->setDataItem('commit_message', $value);
}
/**
- * @return bool
+ * @return mixed
*/
- public function setCommitterEmail(?string $value)
+ public function getExtra(string $key = null)
{
- if ($this->data['committer_email'] === $value) {
- return false;
+ $data = $this->getDataItem('extra');
+ if ($key === null) {
+ return $data;
}
- $this->data['committer_email'] = $value;
-
- return $this->setModified('committer_email');
+ return $data[$key] ?? null;
}
- /**
- * @return string
- */
- public function getCommitMessage()
+ public function setExtra(array $value): bool
{
- return $this->data['commit_message'];
+ return $this->setDataItem('extra', $value);
}
/**
- * @return bool
+ * @param mixed $value
*/
- public function setCommitMessage(?string $value)
+ public function addExtraValue(string $name, $value): bool
{
- if ($this->data['commit_message'] === $value) {
- return false;
+ $extra = $this->getExtra();
+ if ($extra === null) {
+ $extra = [];
}
+ $extra[$name] = $value;
- $this->data['commit_message'] = $value;
-
- return $this->setModified('commit_message');
+ return $this->setExtra($extra);
}
- /**
- * @param string|null $key
- *
- * @return array|string|null
- */
- public function getExtra($key = null)
- {
- $data = json_decode($this->data['extra'], true);
- $extra = null;
- if (is_null($key)) {
- $extra = $data;
- } elseif (isset($data[$key])) {
- $extra = $data[$key];
- }
-
- return $extra;
- }
-
- /**
- * @return bool
- *
- */
- public function setExtra(array $value)
+ public function removeExtraValue(string $name): bool
{
- $extra = json_encode($value);
- if ($this->data['extra'] === $extra) {
+ $extra = $this->getExtra();
+ if ($extra === null || !\array_key_exists($name, $extra)) {
return false;
}
+ unset($extra[$name]);
- $this->data['extra'] = $extra;
-
- return $this->setModified('extra');
+ return $this->setExtra($extra);
}
- /**
- * @return int|null
- */
- public function getEnvironmentId()
+ public function getEnvironmentId(): ?int
{
- return (null !== $this->data['environment_id']) ? (int)$this->data['environment_id'] : null;
+ return $this->getDataItem('environment_id');
}
- /**
- * @return bool
- *
- * @throws InvalidArgumentException
- */
- public function setEnvironmentId(?int $value)
+ public function setEnvironmentId(?int $value): bool
{
- if ($this->data['environment_id'] === $value) {
- return false;
- }
-
- $this->data['environment_id'] = $value;
-
- return $this->setModified('environment_id');
+ return $this->setDataItem('environment_id', $value);
}
- /**
- * @return int
- */
- public function getSource()
+ public function getSource(): ?int
{
- return (int)$this->data['source'];
+ return $this->getDataItem('source');
}
/**
- * @return bool
- *
* @throws InvalidArgumentException
*/
- public function setSource(?int $value)
+ public function setSource(?int $value): bool
{
- if (!in_array($value, $this->allowedSources, true)) {
+ if (!\in_array($value, $this->allowedSources, true)) {
throw new InvalidArgumentException(
- 'Column "source" must be one of: ' . join(', ', $this->allowedSources) . '.'
+ 'Column "source" must be one of: ' . \join(', ', $this->allowedSources) . '.'
);
}
- if ($this->data['source'] === $value) {
- return false;
- }
-
- $this->data['source'] = $value;
-
- return $this->setModified('source');
+ return $this->setDataItem('source', $value);
}
/**
- * @return int|null
+ * @throws InvalidArgumentException|RuntimeException
*/
- public function getUserId()
+ public function getErrorsTotal(): ?int
{
- return (null !== $this->data['user_id']) ? (int)$this->data['user_id'] : null;
- }
+ if ($this->getDataItem('errors_total') === null &&
+ !\in_array($this->getStatus(), [self::STATUS_PENDING, self::STATUS_RUNNING], true)) {
+ /** @var BuildStore $store */
+ $store = $this->storeRegistry->get('Build');
- /**
- * @return bool
- */
- public function setUserId(?int $value)
- {
- if ($this->data['user_id'] === $value) {
- return false;
+ $this->setErrorsTotal($store->getErrorsCount($this->getId()));
+ $store->save($this);
}
- $this->data['user_id'] = $value;
+ return $this->getDataItem('errors_total');
+ }
- return $this->setModified('user_id');
+ public function setErrorsTotal(int $value): bool
+ {
+ return $this->setDataItem('errors_total', $value);
}
/**
- * @return int
- *
- * @throws InvalidArgumentException
+ * @throws Exception
*/
- public function getErrorsTotal()
+ public function getErrorsTotalPrevious(): ?int
{
- if (null === $this->data['errors_total'] &&
- !in_array($this->getStatus(), [self::STATUS_PENDING, self::STATUS_RUNNING], true)) {
+ if ($this->getDataItem('errors_total_previous') === null) {
/** @var BuildStore $store */
- $store = Factory::getStore('Build');
+ $store = $this->storeRegistry->get('Build');
- $this->setErrorsTotal($store->getErrorsCount($this->getId()));
- $store->save($this);
+ $trend = $store->getBuildErrorsTrend($this->getId(), $this->getProjectId(), $this->getBranch());
+
+ if (isset($trend[0])) {
+ $this->setErrorsTotalPrevious((int)$trend[0]['count']);
+ $store->save($this);
+ }
}
- return $this->data['errors_total'];
+ return $this->getDataItem('errors_total_previous');
+ }
+
+ public function setErrorsTotalPrevious(int $value): bool
+ {
+ return $this->setDataItem('errors_total_previous', $value);
}
/**
- * @return bool
+ * @throws InvalidArgumentException|RuntimeException
*/
- public function setErrorsTotal(int $value)
+ public function getTestCoverage(): ?string
{
- if ($this->data['errors_total'] === $value) {
- return false;
+ if ($this->getDataItem('test_coverage') === null &&
+ !\in_array($this->getStatus(), [self::STATUS_PENDING, self::STATUS_RUNNING], true)) {
+ /** @var BuildStore $store */
+ $store = $this->storeRegistry->get('Build');
+
+ $this->setTestCoverage($store->getTestCoverage($this->getId()));
+ $store->save($this);
}
- $this->data['errors_total'] = $value;
+ return $this->getDataItem('test_coverage');
+ }
- return $this->setModified('errors_total');
+ public function setTestCoverage(string $value): bool
+ {
+ return $this->setDataItem('test_coverage', $value);
}
/**
- * @return int|null
- *
* @throws Exception
*/
- public function getErrorsTotalPrevious()
+ public function getTestCoveragePrevious(): ?string
{
- if (null === $this->data['errors_total_previous']) {
+ if ($this->getDataItem('test_coverage_previous') === null) {
/** @var BuildStore $store */
- $store = Factory::getStore('Build');
+ $store = $this->storeRegistry->get('Build');
- $trend = $store->getBuildErrorsTrend($this->getId(), $this->getProjectId(), $this->getBranch());
+ $trend = $store->getBuildTestCoverageTrend($this->getId(), $this->getProjectId(), $this->getBranch());
- if (isset($trend[1])) {
- $previousBuild = $store->getById($trend[1]['build_id']);
- if ($previousBuild &&
- !in_array(
- $previousBuild->getStatus(),
- [self::STATUS_PENDING, self::STATUS_RUNNING],
- true
- )) {
- $this->setErrorsTotalPrevious((int)$trend[1]['count']);
+ if (!empty($trend[0]) && !empty($trend[0]['coverage'])) {
+ $coverage = \json_decode($trend[0]['coverage'], true);
+ if (isset($coverage['lines'])) {
+ $this->setTestCoveragePrevious($coverage['lines']);
$store->save($this);
}
}
}
- return $this->data['errors_total_previous'];
+ return $this->getDataItem('test_coverage_previous');
}
- /**
- * @return bool
- */
- public function setErrorsTotalPrevious(int $value)
+ public function setTestCoveragePrevious(string $value): bool
{
- if ($this->data['errors_total_previous'] === $value) {
- return false;
- }
-
- $this->data['errors_total_previous'] = $value;
-
- return $this->setModified('errors_total_previous');
+ return $this->setDataItem('test_coverage_previous', $value);
}
/**
- * @return int
- *
- * @throws InvalidArgumentException
+ * @throws InvalidArgumentException|RuntimeException
*/
- public function getErrorsNew()
+ public function getErrorsNew(): ?int
{
- if (null === $this->data['errors_new']) {
+ if ($this->getDataItem('errors_new') === null) {
/** @var BuildStore $errorStore */
- $store = Factory::getStore('Build');
+ $store = $this->storeRegistry->get('Build');
$this->setErrorsNew(
(int)$store->getNewErrorsCount($this->getId())
@@ -642,36 +428,16 @@ public function getErrorsNew()
$store->save($this);
}
- return $this->data['errors_new'];
+ return $this->getDataItem('errors_new');
}
- /**
- * @return bool
- */
- public function setErrorsNew(int $value)
+ public function setErrorsNew(int $value): bool
{
- if ($this->data['errors_new'] === $value) {
- return false;
- }
-
- $this->data['errors_new'] = $value;
-
- return $this->setModified('errors_new');
+ return $this->setDataItem('errors_new', $value);
}
- /**
- * @return bool
- */
- public function isDebug()
+ public function isDebug(): bool
{
- if (defined('DEBUG_MODE') && DEBUG_MODE) {
- return true;
- }
-
- if ($this->getExtra('debug')) {
- return true;
- }
-
- return false;
+ return (\defined('DEBUG_MODE') && DEBUG_MODE) || $this->getExtra('debug');
}
}
diff --git a/src/Model/Base/BuildError.php b/src/Model/Base/BuildError.php
index c4aea954d..f430511e4 100644
--- a/src/Model/Base/BuildError.php
+++ b/src/Model/Base/BuildError.php
@@ -4,22 +4,26 @@
namespace PHPCensor\Model\Base;
-use DateTime;
-use Exception;
-use PHPCensor\Exception\InvalidArgumentException;
use PHPCensor\Model;
-
+use PHPCensor\Traits\Model\HasCreateDateTrait;
+
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dan Cryer
+ * @author Dmitry Khomutov
+ */
class BuildError extends Model
{
+ use HasCreateDateTrait;
+
public const SEVERITY_CRITICAL = 0;
public const SEVERITY_HIGH = 1;
public const SEVERITY_NORMAL = 2;
public const SEVERITY_LOW = 3;
- /**
- * @var array
- */
- protected $data = [
+ protected array $data = [
'id' => null,
'build_id' => null,
'plugin' => null,
@@ -33,253 +37,102 @@ class BuildError extends Model
'is_new' => 0,
];
- /**
- * @return int
- */
- public function getId()
- {
- return (int)$this->data['id'];
- }
-
- /**
- * @return bool
- */
- public function setId(int $value)
- {
- if ($this->data['id'] === $value) {
- return false;
- }
-
- $this->data['id'] = $value;
-
- return $this->setModified('id');
- }
-
- /**
- * @return int
- */
- public function getBuildId()
- {
- return (int)$this->data['build_id'];
- }
-
- /**
- * @return bool
- */
- public function setBuildId(int $value)
- {
- if ($this->data['build_id'] === $value) {
- return false;
- }
-
- $this->data['build_id'] = $value;
-
- return $this->setModified('build_id');
- }
+ protected array $dataTypes = [
+ 'build_id' => 'integer',
+ 'line_start' => 'integer',
+ 'line_end' => 'integer',
+ 'severity' => 'integer',
+ 'create_date' => 'datetime',
+ 'is_new' => 'boolean'
+ ];
- /**
- * @return string
- */
- public function getPlugin()
+ public function getBuildId(): ?int
{
- return $this->data['plugin'];
+ return $this->getDataItem('build_id');
}
- /**
- * @return bool
- */
- public function setPlugin(string $value)
+ public function setBuildId(int $value): bool
{
- if ($this->data['plugin'] === $value) {
- return false;
- }
-
- $this->data['plugin'] = $value;
-
- return $this->setModified('plugin');
+ return $this->setDataItem('build_id', $value);
}
- /**
- * @return string
- */
- public function getFile()
+ public function getPlugin(): ?string
{
- return $this->data['file'];
+ return $this->getDataItem('plugin');
}
- /**
- * @return bool
- */
- public function setFile(?string $value)
+ public function setPlugin(string $value): bool
{
- if ($this->data['file'] === $value) {
- return false;
- }
-
- $this->data['file'] = $value;
-
- return $this->setModified('file');
+ return $this->setDataItem('plugin', $value);
}
- /**
- * @return int
- */
- public function getLineStart()
+ public function getFile(): ?string
{
- return (int)$this->data['line_start'];
+ return $this->getDataItem('file');
}
- /**
- * @return bool
- */
- public function setLineStart(?int $value)
+ public function setFile(?string $value): bool
{
- if ($this->data['line_start'] === $value) {
- return false;
- }
-
- $this->data['line_start'] = $value;
-
- return $this->setModified('line_start');
+ return $this->setDataItem('file', $value);
}
- /**
- * @return int
- */
- public function getLineEnd()
+ public function getLineStart(): ?int
{
- return (int)$this->data['line_end'];
+ return $this->getDataItem('line_start');
}
- /**
- * @return bool
- */
- public function setLineEnd(?int $value)
+ public function setLineStart(?int $value): bool
{
- if ($this->data['line_end'] === $value) {
- return false;
- }
-
- $this->data['line_end'] = $value;
-
- return $this->setModified('line_end');
+ return $this->setDataItem('line_start', $value);
}
- /**
- * @return int
- */
- public function getSeverity()
+ public function getLineEnd(): ?int
{
- return (int)$this->data['severity'];
+ return $this->getDataItem('line_end');
}
- /**
- * @return bool
- */
- public function setSeverity(int $value)
+ public function setLineEnd(?int $value): bool
{
- if ($this->data['severity'] === $value) {
- return false;
- }
-
- $this->data['severity'] = $value;
-
- return $this->setModified('severity');
+ return $this->setDataItem('line_end', $value);
}
- /**
- * @return string
- */
- public function getMessage()
+ public function getSeverity(): ?int
{
- return $this->data['message'];
+ return $this->getDataItem('severity');
}
- /**
- * @return bool
- */
- public function setMessage(string $value)
+ public function setSeverity(int $value): bool
{
- if ($this->data['message'] === $value) {
- return false;
- }
-
- $this->data['message'] = $value;
-
- return $this->setModified('message');
+ return $this->setDataItem('severity', $value);
}
- /**
- * @return DateTime|null
- *
- * @throws Exception
- */
- public function getCreateDate()
+ public function getMessage(): ?string
{
- if ($this->data['create_date']) {
- return new DateTime($this->data['create_date']);
- }
-
- return null;
+ return $this->getDataItem('message');
}
- /**
- * @return bool
- */
- public function setCreateDate(DateTime $value)
+ public function setMessage(string $value): bool
{
- $stringValue = $value->format('Y-m-d H:i:s');
-
- if ($this->data['create_date'] === $stringValue) {
- return false;
- }
-
- $this->data['create_date'] = $stringValue;
-
- return $this->setModified('create_date');
+ return $this->setDataItem('message', $value);
}
- /**
- * @return string
- */
- public function getHash()
+ public function getHash(): ?string
{
- return $this->data['hash'];
+ return $this->getDataItem('hash');
}
- /**
- * @return bool
- */
- public function setHash(string $value)
+ public function setHash(string $value): bool
{
- if ($this->data['hash'] === $value) {
- return false;
- }
-
- $this->data['hash'] = $value;
-
- return $this->setModified('hash');
+ return $this->setDataItem('hash', $value);
}
- /**
- * @return bool
- */
- public function getIsNew()
+ public function getIsNew(): bool
{
- return (bool)$this->data['is_new'];
+ return $this->getDataItem('is_new');
}
- /**
- * @return bool
- */
- public function setIsNew(bool $value)
+ public function setIsNew(bool $value): bool
{
- if ($this->data['is_new'] === (int)$value) {
- return false;
- }
-
- $this->data['is_new'] = (int)$value;
-
- return $this->setModified('is_new');
+ return $this->setDataItem('is_new', $value);
}
}
diff --git a/src/Model/Base/BuildMeta.php b/src/Model/Base/BuildMeta.php
index 4fe8bed56..cc5b43536 100644
--- a/src/Model/Base/BuildMeta.php
+++ b/src/Model/Base/BuildMeta.php
@@ -4,106 +4,55 @@
namespace PHPCensor\Model\Base;
-use PHPCensor\Exception\InvalidArgumentException;
use PHPCensor\Model;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dan Cryer
+ * @author Dmitry Khomutov
+ */
class BuildMeta extends Model
{
- /**
- * @var array
- */
- protected $data = [
+ protected array $data = [
'id' => null,
'build_id' => null,
'meta_key' => null,
'meta_value' => null,
];
- /**
- * @return int
- */
- public function getId()
- {
- return (int)$this->data['id'];
- }
-
- /**
- * @return bool
- */
- public function setId(int $value)
- {
- if ($this->data['id'] === $value) {
- return false;
- }
-
- $this->data['id'] = $value;
-
- return $this->setModified('id');
- }
+ protected array $dataTypes = [
+ 'build_id' => 'integer',
+ ];
- /**
- * @return int
- */
- public function getBuildId()
+ public function getBuildId(): int
{
- return (int)$this->data['build_id'];
+ return $this->getDataItem('build_id');
}
- /**
- * @return bool
- */
- public function setBuildId(int $value)
+ public function setBuildId(int $value): bool
{
- if ($this->data['build_id'] === $value) {
- return false ;
- }
-
- $this->data['build_id'] = $value;
-
- return $this->setModified('build_id');
+ return $this->setDataItem('build_id', $value);
}
- /**
- * @return string
- */
- public function getMetaKey()
+ public function getMetaKey(): ?string
{
- return $this->data['meta_key'];
+ return $this->getDataItem('meta_key');
}
- /**
- * @return bool
- */
- public function setMetaKey(string $value)
+ public function setMetaKey(string $value): bool
{
- if ($this->data['meta_key'] === $value) {
- return false;
- }
-
- $this->data['meta_key'] = $value;
-
- return $this->setModified('meta_key');
+ return $this->setDataItem('meta_key', $value);
}
- /**
- * @return string
- */
- public function getMetaValue()
+ public function getMetaValue(): ?string
{
- return $this->data['meta_value'];
+ return $this->getDataItem('meta_value');
}
- /**
- * @return bool
- */
- public function setMetaValue(string $value)
+ public function setMetaValue(string $value): bool
{
- if ($this->data['meta_value'] === $value) {
- return false;
- }
-
- $this->data['meta_value'] = $value;
-
- return $this->setModified('meta_value');
+ return $this->setDataItem('meta_value', $value);
}
}
diff --git a/src/Model/Base/Environment.php b/src/Model/Base/Environment.php
index 7f7d49480..bbfedaf94 100644
--- a/src/Model/Base/Environment.php
+++ b/src/Model/Base/Environment.php
@@ -4,112 +4,55 @@
namespace PHPCensor\Model\Base;
-use PHPCensor\Exception\InvalidArgumentException;
use PHPCensor\Model;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class Environment extends Model
{
- /**
- * @var array
- */
- protected $data = [
+ protected array $data = [
'id' => null,
'project_id' => null,
'name' => null,
- 'branches' => null,
+ 'branches' => [],
];
- /**
- * @return int
- */
- public function getId()
- {
- return (int)$this->data['id'];
- }
-
- /**
- * @return bool
- */
- public function setId(int $value)
- {
- if ($this->data['id'] === $value) {
- return false;
- }
-
- $this->data['id'] = $value;
-
- return $this->setModified('id');
- }
+ protected array $dataTypes = [
+ 'project_id' => 'integer',
+ 'branches' => 'newline'
+ ];
- /**
- * @return int
- */
- public function getProjectId()
+ public function getProjectId(): ?int
{
- return (int)$this->data['project_id'];
+ return $this->getDataItem('project_id');
}
- /**
- * @return bool
- */
- public function setProjectId(int $value)
+ public function setProjectId(int $value): bool
{
- if ($this->data['project_id'] === $value) {
- return false;
- }
-
- $this->data['project_id'] = $value;
-
- return $this->setModified('project_id');
+ return $this->setDataItem('project_id', $value);
}
- /**
- * @return string
- */
- public function getName()
+ public function getName(): ?string
{
- return $this->data['name'];
+ return $this->getDataItem('name');
}
- /**
- * @return bool
- */
- public function setName(string $value)
+ public function setName(string $value): bool
{
- if ($this->data['name'] === $value) {
- return false;
- }
-
- $this->data['name'] = $value;
-
- return $this->setModified('name');
+ return $this->setDataItem('name', $value);
}
- /**
- * @return array
- */
- public function getBranches()
+ public function getBranches(): array
{
- return array_filter(
- array_map(
- 'trim',
- explode("\n", $this->data['branches'])
- )
- );
+ return $this->getDataItem('branches');
}
- /**
- * @return bool
- */
- public function setBranches(array $value)
+ public function setBranches(array $value): bool
{
- $branches = implode("\n", $value);
- if ($this->data['branches'] === $branches) {
- return false;
- }
-
- $this->data['branches'] = $branches;
-
- return $this->setModified('branches');
+ return $this->setDataItem('branches', $value);
}
}
diff --git a/src/Model/Base/Project.php b/src/Model/Base/Project.php
index c582e20b4..e82a759e2 100644
--- a/src/Model/Base/Project.php
+++ b/src/Model/Base/Project.php
@@ -4,33 +4,40 @@
namespace PHPCensor\Model\Base;
-use DateTime;
-use Exception;
-use PHPCensor\Exception\InvalidArgumentException;
+use PHPCensor\Common\Exception\InvalidArgumentException;
use PHPCensor\Model;
-
+use PHPCensor\Traits\Model\HasCreateDateTrait;
+use PHPCensor\Traits\Model\HasUserIdTrait;
+
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dan Cryer
+ * @author Dmitry Khomutov
+ */
class Project extends Model
{
- public const TYPE_LOCAL = 'local';
- public const TYPE_GIT = 'git';
- public const TYPE_GITHUB = 'github';
- public const TYPE_BITBUCKET = 'bitbucket';
- public const TYPE_GITLAB = 'gitlab';
- public const TYPE_GOGS = 'gogs';
- public const TYPE_HG = 'hg';
- public const TYPE_BITBUCKET_HG = 'bitbucket-hg';
+ use HasCreateDateTrait;
+ use HasUserIdTrait;
+
+ public const TYPE_LOCAL = 'local';
+ public const TYPE_GIT = 'git';
+ public const TYPE_GITHUB = 'github';
+ public const TYPE_BITBUCKET = 'bitbucket';
+ public const TYPE_GITLAB = 'gitlab';
+ public const TYPE_GOGS = 'gogs';
+ public const TYPE_HG = 'hg';
+ public const TYPE_BITBUCKET_HG = 'bitbucket-hg';
public const TYPE_BITBUCKET_SERVER = 'bitbucket-server';
- public const TYPE_SVN = 'svn';
+ public const TYPE_SVN = 'svn';
- public const MIN_BUILD_PRIORITY = 1;
- public const MAX_BUILD_PRIORITY = 2000;
- public const DEFAULT_BUILD_PRIORITY = 1000;
+ public const MIN_BUILD_PRIORITY = 1;
+ public const MAX_BUILD_PRIORITY = 2000;
+ public const DEFAULT_BUILD_PRIORITY = 1000;
public const OFFSET_BETWEEN_BUILD_AND_QUEUE = 24;
- /**
- * @var array
- */
- protected $data = [
+ protected array $data = [
'id' => null,
'title' => null,
'reference' => null,
@@ -49,10 +56,18 @@ class Project extends Model
'user_id' => null,
];
- /**
- * @var array
- */
- public static $allowedTypes = [
+ protected array $dataTypes = [
+ 'allow_public_status' => 'boolean',
+ 'archived' => 'boolean',
+ 'group_id' => 'integer',
+ 'default_branch_only' => 'boolean',
+ 'create_date' => 'datetime',
+ 'user_id' => 'integer',
+ 'access_information' => 'array',
+ 'overwrite_build_config' => 'boolean'
+ ];
+
+ public static array $allowedTypes = [
self::TYPE_LOCAL,
self::TYPE_GIT,
self::TYPE_GITHUB,
@@ -65,382 +80,150 @@ class Project extends Model
self::TYPE_BITBUCKET_SERVER
];
- /**
- * @return int
- */
- public function getId()
- {
- return (int)$this->data['id'];
- }
-
- /**
- * @return bool
- */
- public function setId(int $value)
- {
- if ($this->data['id'] === $value) {
- return false;
- }
-
- $this->data['id'] = $value;
-
- return $this->setModified('id');
- }
-
- /**
- * @return string
- */
- public function getTitle()
+ public function getTitle(): ?string
{
- return $this->data['title'];
+ return $this->getDataItem('title');
}
- /**
- * @return bool
- */
- public function setTitle(string $value)
+ public function setTitle(string $value): bool
{
- if ($this->data['title'] === $value) {
- return false;
- }
-
- $this->data['title'] = $value;
-
- return $this->setModified('title');
+ return $this->setDataItem('title', $value);
}
- /**
- * @return string
- */
- public function getReference()
+ public function getReference(): ?string
{
- return $this->data['reference'];
+ return $this->getDataItem('reference');
}
- /**
- * @return bool
- */
- public function setReference(string $value)
+ public function setReference(string $value): bool
{
- if ($this->data['reference'] === $value) {
- return false;
- }
-
- $this->data['reference'] = $value;
-
- return $this->setModified('reference');
+ return $this->setDataItem('reference', $value);
}
- /**
- * @return string
- */
- public function getDefaultBranch()
+ public function getDefaultBranch(): ?string
{
- return $this->data['default_branch'];
+ return $this->getDataItem('default_branch');
}
- /**
- * @return bool
- */
- public function setDefaultBranch(string $value)
+ public function setDefaultBranch(string $value): bool
{
- if ($this->data['default_branch'] === $value) {
- return false;
- }
-
- $this->data['default_branch'] = $value;
-
- return $this->setModified('default_branch');
+ return $this->setDataItem('default_branch', $value);
}
- /**
- * @return bool
- */
- public function getDefaultBranchOnly()
+ public function getDefaultBranchOnly(): bool
{
- return (bool)$this->data['default_branch_only'];
+ return $this->getDataItem('default_branch_only');
}
- /**
- * @return bool
- */
- public function setDefaultBranchOnly(bool $value)
+ public function setDefaultBranchOnly(bool $value): bool
{
- if ($this->data['default_branch_only'] === (int)$value) {
- return false;
- }
-
- $this->data['default_branch_only'] = (int)$value;
-
- return $this->setModified('default_branch_only');
+ return $this->setDataItem('default_branch_only', $value);
}
- /**
- * @return string
- */
- public function getSshPrivateKey()
+ public function getSshPrivateKey(): ?string
{
- return $this->data['ssh_private_key'];
+ return $this->getDataItem('ssh_private_key');
}
- /**
- * @return bool
- */
- public function setSshPrivateKey(?string $value)
+ public function setSshPrivateKey(?string $value): bool
{
- if ($this->data['ssh_private_key'] === $value) {
- return false;
- }
-
- $this->data['ssh_private_key'] = $value;
-
- return $this->setModified('ssh_private_key');
+ return $this->setDataItem('ssh_private_key', $value);
}
- /**
- * @return string
- */
- public function getSshPublicKey()
+ public function getSshPublicKey(): ?string
{
- return $this->data['ssh_public_key'];
+ return $this->getDataItem('ssh_public_key');
}
- /**
- * @return bool
- */
- public function setSshPublicKey(?string $value)
+ public function setSshPublicKey(?string $value): bool
{
- if ($this->data['ssh_public_key'] === $value) {
- return false;
- }
-
- $this->data['ssh_public_key'] = $value;
-
- return $this->setModified('ssh_public_key');
+ return $this->setDataItem('ssh_public_key', $value);
}
- /**
- * @return string
- */
- public function getType()
+ public function getType(): ?string
{
- return $this->data['type'];
+ return $this->getDataItem('type');
}
/**
- * @return bool
- *
* @throws InvalidArgumentException
*/
- public function setType(string $value)
+ public function setType(string $value): bool
{
- if (!in_array($value, static::$allowedTypes, true)) {
+ if (!\in_array($value, static::$allowedTypes, true)) {
throw new InvalidArgumentException(
- 'Column "type" must be one of: ' . join(', ', static::$allowedTypes) . '.'
+ 'Column "type" must be one of: ' . \join(', ', static::$allowedTypes) . '.'
);
}
- if ($this->data['type'] === $value) {
- return false;
- }
-
- $this->data['type'] = $value;
-
- return $this->setModified('type');
- }
-
- /**
- * @param string|null $key
- *
- * @return array|string|null
- */
- public function getAccessInformation($key = null)
- {
- $data = \json_decode((string)$this->data['access_information'], true);
- $accessInformation = null;
- if (is_null($key)) {
- $accessInformation = $data;
- } elseif (isset($data[$key])) {
- $accessInformation = $data[$key];
- }
-
- return $accessInformation;
- }
-
- /**
- * @return bool
- */
- public function setAccessInformation(array $value)
- {
- $accessInformation = \json_encode($value);
- if ($this->data['access_information'] === $accessInformation) {
- return false;
- }
-
- $this->data['access_information'] = $accessInformation;
-
- return $this->setModified('access_information');
- }
-
- /**
- * @return string
- */
- public function getBuildConfig()
- {
- return $this->data['build_config'];
+ return $this->setDataItem('type', $value);
}
/**
- * @return bool
+ * @return mixed
*/
- public function setBuildConfig(?string $value)
+ public function getAccessInformation(string $key = null)
{
- if ($this->data['build_config'] === $value) {
- return false;
+ $data = $this->getDataItem('access_information');
+ if ($key === null) {
+ return $data;
}
- $this->data['build_config'] = $value;
-
- return $this->setModified('build_config');
+ return $data[$key] ?? null;
}
- /**
- * @return bool
- */
- public function getOverwriteBuildConfig()
+ public function setAccessInformation(array $value): bool
{
- return (bool)$this->data['overwrite_build_config'];
+ return $this->setDataItem('access_information', $value);
}
- /**
- * @return bool
- */
- public function setOverwriteBuildConfig(bool $value)
+ public function getBuildConfig(): ?string
{
- if ($this->data['overwrite_build_config'] === (int)$value) {
- return false;
- }
-
- $this->data['overwrite_build_config'] = (int)$value;
-
- return $this->setModified('overwrite_build_config');
- }
-
- /**
- * @return bool
- */
- public function getAllowPublicStatus()
- {
- return (bool)$this->data['allow_public_status'];
+ return $this->getDataItem('build_config');
}
- /**
- * @return bool
- */
- public function setAllowPublicStatus(bool $value)
+ public function setBuildConfig(?string $value): bool
{
- if ($this->data['allow_public_status'] === (int)$value) {
- return false;
- }
-
- $this->data['allow_public_status'] = (int)$value;
-
- return $this->setModified('allow_public_status');
+ return $this->setDataItem('build_config', $value);
}
- /**
- * @return bool
- */
- public function getArchived()
+ public function getOverwriteBuildConfig(): bool
{
- return (bool)$this->data['archived'];
+ return $this->getDataItem('overwrite_build_config');
}
- /**
- * @return bool
- */
- public function setArchived(bool $value)
+ public function setOverwriteBuildConfig(bool $value): bool
{
- if ($this->data['archived'] === (int)$value) {
- return false;
- }
-
- $this->data['archived'] = (int)$value;
-
- return $this->setModified('archived');
+ return $this->setDataItem('overwrite_build_config', $value);
}
- /**
- * @return int
- */
- public function getGroupId()
+ public function getAllowPublicStatus(): bool
{
- return (int)$this->data['group_id'];
+ return $this->getDataItem('allow_public_status');
}
- /**
- * @return bool
- */
- public function setGroupId(int $value)
+ public function setAllowPublicStatus(bool $value): bool
{
- if ($this->data['group_id'] === $value) {
- return false;
- }
-
- $this->data['group_id'] = $value;
-
- return $this->setModified('group_id');
+ return $this->setDataItem('allow_public_status', $value);
}
- /**
- * @return DateTime|null
- *
- * @throws Exception
- */
- public function getCreateDate()
+ public function getArchived(): bool
{
- if ($this->data['create_date']) {
- return new DateTime($this->data['create_date']);
- }
-
- return null;
+ return $this->getDataItem('archived');
}
- /**
- * @return bool
- */
- public function setCreateDate(DateTime $value)
+ public function setArchived(bool $value): bool
{
- $stringValue = $value->format('Y-m-d H:i:s');
-
- if ($this->data['create_date'] === $stringValue) {
- return false;
- }
-
- $this->data['create_date'] = $stringValue;
-
- return $this->setModified('create_date');
+ return $this->setDataItem('archived', $value);
}
- /**
- * @return int|null
- */
- public function getUserId()
+ public function getGroupId(): int
{
- return (null !== $this->data['user_id']) ? (int)$this->data['user_id'] : null;
+ return $this->getDataItem('group_id');
}
- /**
- * @return bool
- */
- public function setUserId(?int $value)
+ public function setGroupId(int $value): bool
{
- if ($this->data['user_id'] === $value) {
- return false;
- }
-
- $this->data['user_id'] = $value;
-
- return $this->setModified('user_id');
+ return $this->setDataItem('group_id', $value);
}
}
diff --git a/src/Model/Base/ProjectGroup.php b/src/Model/Base/ProjectGroup.php
index e1a7bc55e..07da33b6d 100644
--- a/src/Model/Base/ProjectGroup.php
+++ b/src/Model/Base/ProjectGroup.php
@@ -4,116 +4,40 @@
namespace PHPCensor\Model\Base;
-use DateTime;
-use Exception;
-use PHPCensor\Exception\InvalidArgumentException;
use PHPCensor\Model;
-
+use PHPCensor\Traits\Model\HasCreateDateTrait;
+use PHPCensor\Traits\Model\HasUserIdTrait;
+
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class ProjectGroup extends Model
{
- /**
- * @var array
- */
- protected $data = [
+ use HasCreateDateTrait;
+ use HasUserIdTrait;
+
+ protected array $data = [
'id' => null,
'title' => null,
'create_date' => null,
'user_id' => null,
];
- /**
- * @return int
- */
- public function getId()
- {
- return (int)$this->data['id'];
- }
-
- /**
- * @return bool
- */
- public function setId(int $value)
- {
- if ($this->data['id'] === $value) {
- return false;
- }
-
- $this->data['id'] = $value;
-
- return $this->setModified('id');
- }
-
- /**
- * @return string
- */
- public function getTitle()
- {
- return $this->data['title'];
- }
-
- /**
- * @return bool
- */
- public function setTitle(string $value)
- {
- if ($this->data['title'] === $value) {
- return false;
- }
-
- $this->data['title'] = $value;
-
- return $this->setModified('title');
- }
-
- /**
- * @return DateTime|null
- *
- * @throws Exception
- */
- public function getCreateDate()
- {
- if ($this->data['create_date']) {
- return new DateTime($this->data['create_date']);
- }
-
- return null;
- }
-
- /**
- * @return bool
- */
- public function setCreateDate(DateTime $value)
- {
- $stringValue = $value->format('Y-m-d H:i:s');
-
- if ($this->data['create_date'] === $stringValue) {
- return false;
- }
-
- $this->data['create_date'] = $stringValue;
-
- return $this->setModified('create_date');
- }
+ protected array $dataTypes = [
+ 'user_id' => 'integer',
+ 'create_date' => 'datetime'
+ ];
- /**
- * @return string|null
- */
- public function getUserId()
+ public function getTitle(): ?string
{
- return (null !== $this->data['user_id']) ? (int)$this->data['user_id'] : null;
+ return $this->getDataItem('title');
}
- /**
- * @return bool
- */
- public function setUserId(?int $value)
+ public function setTitle(string $value): bool
{
- if ($this->data['user_id'] === $value) {
- return false;
- }
-
- $this->data['user_id'] = $value;
-
- return $this->setModified('user_id');
+ return $this->setDataItem('title', $value);
}
}
diff --git a/src/Model/Base/Secret.php b/src/Model/Base/Secret.php
new file mode 100644
index 000000000..8f021ff1b
--- /dev/null
+++ b/src/Model/Base/Secret.php
@@ -0,0 +1,54 @@
+
+ */
+class Secret extends Model
+{
+ use HasCreateDateTrait;
+ use HasUserIdTrait;
+
+ protected array $data = [
+ 'id' => null,
+ 'name' => null,
+ 'value' => null,
+ 'create_date' => null,
+ 'user_id' => null,
+ ];
+
+ protected array $dataTypes = [
+ 'create_date' => 'datetime',
+ 'user_id' => 'integer',
+ ];
+
+ public function getName(): ?string
+ {
+ return $this->getDataItem('name');
+ }
+
+ public function setName(string $value): bool
+ {
+ return $this->setDataItem('name', $value);
+ }
+
+ public function getValue(): ?string
+ {
+ return $this->getDataItem('value');
+ }
+
+ public function setValue(string $value): bool
+ {
+ return $this->setDataItem('value', $value);
+ }
+}
diff --git a/src/Model/Base/User.php b/src/Model/Base/User.php
index de58b128f..b35cc0d26 100644
--- a/src/Model/Base/User.php
+++ b/src/Model/Base/User.php
@@ -4,15 +4,18 @@
namespace PHPCensor\Model\Base;
-use PHPCensor\Exception\InvalidArgumentException;
use PHPCensor\Model;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dan Cryer
+ * @author Dmitry Khomutov
+ */
class User extends Model
{
- /**
- * @var array
- */
- protected $data = [
+ protected array $data = [
'id' => null,
'email' => null,
'hash' => null,
@@ -25,236 +28,107 @@ class User extends Model
'remember_key' => null,
];
- /**
- * @return int
- */
- public function getId()
- {
- return (int)$this->data['id'];
- }
-
- /**
- * @return bool
- */
- public function setId(int $value)
- {
- if ($this->data['id'] === $value) {
- return false;
- }
-
- $this->data['id'] = $value;
-
- return $this->setModified('id');
- }
+ protected array $dataTypes = [
+ 'is_admin' => 'boolean',
+ 'per_page' => 'integer',
+ 'provider_data' => 'array'
+ ];
- /**
- * @return string
- */
- public function getEmail()
+ public function getEmail(): ?string
{
- return $this->data['email'];
+ return $this->getDataItem('email');
}
- /**
- * @return bool
- */
- public function setEmail(string $value)
+ public function setEmail(string $value): bool
{
- if ($this->data['email'] === $value) {
- return false;
- }
-
- $this->data['email'] = $value;
-
- return $this->setModified('email');
+ return $this->setDataItem('email', $value);
}
- /**
- * @return string
- */
- public function getHash()
+ public function getHash(): ?string
{
- return $this->data['hash'];
+ return $this->getDataItem('hash');
}
- /**
- * @return bool
- */
- public function setHash(string $value)
+ public function setHash(string $value): bool
{
- if ($this->data['hash'] === $value) {
- return false;
- }
-
- $this->data['hash'] = $value;
-
- return $this->setModified('hash');
+ return $this->setDataItem('hash', $value);
}
- /**
- * @return bool
- */
- public function getIsAdmin()
+ public function getIsAdmin(): bool
{
- return (bool)$this->data['is_admin'];
+ return $this->getDataItem('is_admin');
}
- /**
- * @return bool
- */
- public function setIsAdmin(bool $value)
+ public function setIsAdmin(bool $value): bool
{
- if ($this->data['is_admin'] === (int)$value) {
- return false;
- }
-
- $this->data['is_admin'] = (int)$value;
-
- return $this->setModified('is_admin');
+ return $this->setDataItem('is_admin', $value);
}
- /**
- * @return string
- */
- public function getName()
+ public function getName(): ?string
{
- return $this->data['name'];
+ return $this->getDataItem('name');
}
- /**
- * @return bool
- */
- public function setName(string $value)
+ public function setName(string $value): bool
{
- if ($this->data['name'] === $value) {
- return false;
- }
-
- $this->data['name'] = $value;
-
- return $this->setModified('name');
+ return $this->setDataItem('name', $value);
}
- /**
- * @return string
- */
- public function getLanguage()
+ public function getLanguage(): ?string
{
- return $this->data['language'];
+ return $this->getDataItem('language');
}
- /**
- * @param string $value
- *
- * @return bool
- */
- public function setLanguage($value)
+ public function setLanguage(?string $value): bool
{
- if ($this->data['language'] === $value) {
- return false;
- }
-
- $this->data['language'] = $value;
-
- return $this->setModified('language');
+ return $this->setDataItem('language', $value);
}
- /**
- * @return int
- */
- public function getPerPage()
+ public function getPerPage(): ?int
{
- return (int)$this->data['per_page'];
+ return $this->getDataItem('per_page');
}
- /**
- * @return bool
- */
- public function setPerPage(?int $value)
+ public function setPerPage(?int $value): bool
{
- if ($this->data['per_page'] === $value) {
- return false;
- }
-
- $this->data['per_page'] = $value;
-
- return $this->setModified('per_page');
+ return $this->setDataItem('per_page', $value);
}
- /**
- * @return string
- */
- public function getProviderKey()
+ public function getProviderKey(): ?string
{
- return $this->data['provider_key'];
+ return $this->getDataItem('provider_key');
}
- /**
- * @return bool
- */
- public function setProviderKey(string $value)
+ public function setProviderKey(string $value): bool
{
- if ($this->data['provider_key'] === $value) {
- return false;
- }
-
- $this->data['provider_key'] = $value;
-
- return $this->setModified('provider_key');
+ return $this->setDataItem('provider_key', $value);
}
/**
- * @param string|null $key
- *
- * @return array|string|null
+ * @return mixed
*/
- public function getProviderData($key = null)
+ public function getProviderData(string $key = null)
{
- $data = json_decode($this->data['provider_data'], true);
- $providerData = null;
- if (is_null($key)) {
- $providerData = $data;
- } elseif (isset($data[$key])) {
- $providerData = $data[$key];
+ $data = $this->getDataItem('provider_data');
+ if ($key === null) {
+ return $data;
}
- return $providerData;
+ return $data[$key] ?? null;
}
- /**
- * @return bool
- */
- public function setProviderData(array $value)
+ public function setProviderData(array $value): bool
{
- $providerData = json_encode($value);
- if ($this->data['provider_data'] === $providerData) {
- return false;
- }
-
- $this->data['provider_data'] = $providerData;
-
- return $this->setModified('provider_data');
+ return $this->setDataItem('provider_data', $value);
}
- /**
- * @return string
- */
- public function getRememberKey()
+ public function getRememberKey(): ?string
{
- return $this->data['remember_key'];
+ return $this->getDataItem('remember_key');
}
- /**
- * @return bool
- */
- public function setRememberKey(?string $value)
+ public function setRememberKey(?string $value): bool
{
- if ($this->data['remember_key'] === $value) {
- return false;
- }
-
- $this->data['remember_key'] = $value;
-
- return $this->setModified('remember_key');
+ return $this->setDataItem('remember_key', $value);
}
}
diff --git a/src/Model/Base/WebhookRequest.php b/src/Model/Base/WebhookRequest.php
new file mode 100644
index 000000000..01b4cdb3f
--- /dev/null
+++ b/src/Model/Base/WebhookRequest.php
@@ -0,0 +1,70 @@
+
+ */
+class WebhookRequest extends Model
+{
+ use HasCreateDateTrait;
+
+ public const WEBHOOK_TYPE_GIT = 'git';
+ public const WEBHOOK_TYPE_GITHUB = 'github';
+ public const WEBHOOK_TYPE_BITBUCKET = 'bitbucket';
+ public const WEBHOOK_TYPE_GITLAB = 'gitlab';
+ public const WEBHOOK_TYPE_GOGS = 'gogs';
+ public const WEBHOOK_TYPE_HG = 'hg';
+ public const WEBHOOK_TYPE_SVN = 'svn';
+
+ protected array $data = [
+ 'id' => null,
+ 'project_id' => null,
+ 'webhook_type' => null,
+ 'payload' => null,
+ 'create_date' => null,
+ ];
+
+ protected array $dataTypes = [
+ 'project_id' => 'integer',
+ 'create_date' => 'datetime',
+ ];
+
+ public function getProjectId(): ?int
+ {
+ return $this->getDataItem('project_id');
+ }
+
+ public function setProjectId(int $value): bool
+ {
+ return $this->setDataItem('project_id', $value);
+ }
+
+ public function getWebhookType(): ?string
+ {
+ return $this->getDataItem('webhook_type');
+ }
+
+ public function setWebhookType(string $value): bool
+ {
+ return $this->setDataItem('webhook_type', $value);
+ }
+
+ public function getPayload(): ?string
+ {
+ return $this->getDataItem('payload');
+ }
+
+ public function setPayload(?string $value): bool
+ {
+ return $this->setDataItem('payload', $value);
+ }
+}
diff --git a/src/Model/Build.php b/src/Model/Build.php
index 53817a4b3..145ae8c52 100644
--- a/src/Model/Build.php
+++ b/src/Model/Build.php
@@ -1,5 +1,7 @@
+ * @author Dmitry Khomutov
*/
class Build extends BaseBuild
{
@@ -33,20 +39,14 @@ class Build extends BaseBuild
public const STAGE_FIXED = 'fixed';
public const STAGE_BROKEN = 'broken';
- /**
- * @var array
- */
- public static $pullRequestSources = [
+ public static array $pullRequestSources = [
self::SOURCE_WEBHOOK_PULL_REQUEST_CREATED,
self::SOURCE_WEBHOOK_PULL_REQUEST_UPDATED,
self::SOURCE_WEBHOOK_PULL_REQUEST_APPROVED,
self::SOURCE_WEBHOOK_PULL_REQUEST_MERGED,
];
- /**
- * @var array
- */
- public static $webhookSources = [
+ public static array $webhookSources = [
self::SOURCE_WEBHOOK_PUSH,
self::SOURCE_WEBHOOK_PULL_REQUEST_CREATED,
self::SOURCE_WEBHOOK_PULL_REQUEST_UPDATED,
@@ -54,20 +54,11 @@ class Build extends BaseBuild
self::SOURCE_WEBHOOK_PULL_REQUEST_MERGED,
];
- /**
- * @var array
- */
- protected $totalErrorsCount = [];
+ protected array $totalErrorsCount = [];
- /**
- * @var string
- */
- protected $buildDirectory;
+ protected string $buildDirectory;
- /**
- * @var string
- */
- protected $buildBranchDirectory;
+ protected string $buildBranchDirectory;
/**
* @return Project|null
@@ -82,39 +73,11 @@ public function getProject()
}
/** @var ProjectStore $projectStore */
- $projectStore = Factory::getStore('Project');
+ $projectStore = $this->storeRegistry->get('Project');
return $projectStore->getById($projectId);
}
- /**
- * @param string $name
- * @param mixed $value
- */
- public function addExtraValue($name, $value)
- {
- $extra = json_decode($this->data['extra'], true);
- if ($extra === false) {
- $extra = [];
- }
- $extra[$name] = $value;
-
- $this->setExtra($extra);
- }
-
- /**
- * @param string $name
- */
- public function removeExtraValue($name)
- {
- $extra = $this->getExtra();
- if (!empty($extra[$name])) {
- unset($extra[$name]);
- }
-
- $this->setExtra($extra);
- }
-
/**
* Get BuildError models by BuildId for this Build.
*
@@ -122,7 +85,7 @@ public function removeExtraValue($name)
*/
public function getBuildBuildErrors()
{
- return Factory::getStore('BuildError')->getByBuildId($this->getId());
+ return $this->storeRegistry->get('BuildError')->getByBuildId($this->getId());
}
/**
@@ -132,7 +95,7 @@ public function getBuildBuildErrors()
*/
public function getBuildBuildMetas()
{
- return Factory::getStore('BuildMeta')->getByBuildId($this->getId());
+ return $this->storeRegistry->get('BuildMeta')->getByBuildId($this->getId());
}
/**
@@ -213,9 +176,9 @@ public function getProjectTitle()
*/
public function storeMeta($key, $value)
{
- $value = json_encode($value);
+ $value = \json_encode($value);
- Factory::getStore('Build')->setMeta($this->getId(), $key, $value);
+ $this->storeRegistry->get('Build')->setMeta($this->getId(), $key, $value);
}
/**
@@ -239,8 +202,8 @@ public function handleConfigBeforeClone(Builder $builder)
$yamlParser = new YamlParser();
$buildConfig = $yamlParser->parse($buildConfig);
- if ($buildConfig && is_array($buildConfig)) {
- $builder->logDebug('Config before repository clone (DB): ' . json_encode($buildConfig));
+ if ($buildConfig && \is_array($buildConfig)) {
+ $builder->logDebug('Config before repository clone (DB): ' . \json_encode($buildConfig));
$builder->setConfig($buildConfig);
}
@@ -250,25 +213,21 @@ public function handleConfigBeforeClone(Builder $builder)
}
/**
- * @param string $buildPath
- *
- * @return bool
- *
* @throws Exception
*/
- protected function handleConfig(Builder $builder, $buildPath)
+ protected function handleConfig(Builder $builder, string $buildPath): bool
{
$yamlParser = new YamlParser();
$overwriteBuildConfig = $this->getProject()->getOverwriteBuildConfig();
$buildConfig = $builder->getConfig();
- $repositoryConfig = $this->getZeroConfigPlugins($builder);
+ $repositoryConfig = $this->getZeroConfigPlugins();
$repositoryConfigFrom = '';
- if (file_exists($buildPath . '/.php-censor.yml')) {
+ if (\file_exists($buildPath . '/.php-censor.yml')) {
$repositoryConfigFrom = '.php-censor.yml';
$repositoryConfig = $yamlParser->parse(
- file_get_contents($buildPath . '/.php-censor.yml')
+ \file_get_contents($buildPath . '/.php-censor.yml')
);
}
@@ -281,22 +240,22 @@ protected function handleConfig(Builder $builder, $buildPath)
if (!$buildConfig) {
$builder->logDebug(
- sprintf('Build config from repository (%s)', $repositoryConfigFrom)
+ \sprintf('Build config from repository (%s)', $repositoryConfigFrom)
);
$buildConfig = $repositoryConfig;
} elseif ($buildConfig && !$overwriteBuildConfig) {
$builder->logDebug(
- sprintf('Build config from project (DB) + config from repository (%s)', $repositoryConfigFrom)
+ \sprintf('Build config from project (DB) + config from repository (%s)', $repositoryConfigFrom)
);
- $buildConfig = array_replace_recursive($repositoryConfig, $buildConfig);
+ $buildConfig = \array_replace_recursive($repositoryConfig, $buildConfig);
} elseif ($buildConfig) {
$builder->logDebug('Build config from project (DB)');
}
- if ($buildConfig && is_array($buildConfig)) {
- $builder->logDebug('Final config: ' . json_encode($buildConfig));
+ if ($buildConfig && \is_array($buildConfig)) {
+ $builder->logDebug('Final config: ' . \json_encode($buildConfig));
$builder->setConfig($buildConfig);
}
@@ -311,7 +270,7 @@ protected function handleConfig(Builder $builder, $buildPath)
*
* @throws ReflectionException
*/
- protected function getZeroConfigPlugins(Builder $builder)
+ protected function getZeroConfigPlugins()
{
$pluginDir = SRC_DIR . 'Plugin/';
$dir = new DirectoryIterator($pluginDir);
@@ -333,29 +292,33 @@ protected function getZeroConfigPlugins(Builder $builder)
continue;
}
- if ($item->getExtension() != 'php') {
+ if ($item->getExtension() !== 'php') {
continue;
}
- $className = '\PHPCensor\Plugin\\' . $item->getBasename('.php');
+ $className = 'PHPCensor\Plugin\\' . $item->getBasename('.php');
$reflectedPlugin = new ReflectionClass($className);
- if (!$reflectedPlugin->implementsInterface('\PHPCensor\ZeroConfigPluginInterface')) {
+ if (!$reflectedPlugin->implementsInterface(ZeroConfigPluginInterface::class)) {
continue;
}
foreach ([Build::STAGE_SETUP, Build::STAGE_TEST] as $stage) {
if ($className::canExecuteOnStage($stage, $this)) {
+ $pluginName = $className::pluginName();
+ $stepName = \sprintf('%s_step', $pluginName);
+
$pluginConfig = [
+ 'plugin' => $pluginName,
'zero_config' => true,
];
- if (PhpParallelLint::pluginName() === $className::pluginName()) {
+ if (PhpParallelLint::pluginName() === $pluginName) {
$pluginConfig['allow_failures'] = true;
}
- $config[$stage][$className::pluginName()] = $pluginConfig;
+ $config[$stage][$stepName] = $pluginConfig;
}
}
}
@@ -365,22 +328,15 @@ protected function getZeroConfigPlugins(Builder $builder)
/**
* Allows specific build types (e.g. Github) to report violations back to their respective services.
- *
- * @param string $plugin
- * @param string $message
- * @param int $severity
- * @param string $file
- * @param int $lineStart
- * @param int $lineEnd
*/
public function reportError(
Builder $builder,
- $plugin,
- $message,
- $severity = BuildError::SEVERITY_NORMAL,
- $file = null,
- $lineStart = null,
- $lineEnd = null
+ string $plugin,
+ string $message,
+ int $severity = BuildError::SEVERITY_NORMAL,
+ ?string $file = null,
+ ?int $lineStart = null,
+ ?int $lineEnd = null
) {
$writer = $builder->getBuildErrorWriter();
$writer->write(
@@ -404,8 +360,8 @@ public function getBuildDirectory()
$createDate = $this->getCreateDate();
if (empty($this->buildDirectory)) {
- $this->buildDirectory = $this->getProjectId() . '/' . $this->getId() . '_' . substr(
- md5(
+ $this->buildDirectory = $this->getProjectId() . '/' . $this->getId() . '_' . \substr(
+ \md5(
($this->getId() . '_' . ($createDate ? $createDate->format('Y-m-d H:i:s') : null))
),
0,
@@ -427,8 +383,8 @@ public function getBuildBranchDirectory()
$createDate = $this->getCreateDate();
if (empty($this->buildBranchDirectory)) {
- $this->buildBranchDirectory = $this->getProjectId() . '/' . $this->getBranch() . '_' . substr(
- md5(
+ $this->buildBranchDirectory = $this->getProjectId() . '/' . $this->getBranch() . '_' . \substr(
+ \md5(
($this->getBranch() . '_' . ($createDate ? $createDate->format('Y-m-d H:i:s') : null))
),
0,
@@ -448,33 +404,31 @@ public function getBuildPath()
return null;
}
- return rtrim(
- realpath(RUNTIME_DIR . 'builds'),
+ return \rtrim(
+ \realpath(RUNTIME_DIR . 'builds'),
'/\\'
) . '/' . $this->getBuildDirectory() . '/';
}
/**
* Removes the build directory.
- *
- * @param bool $withArtifacts
*/
- public function removeBuildDirectory($withArtifacts = false)
+ public function removeBuildDirectory(bool $withArtifacts = false)
{
// Get the path and remove the trailing slash as this may prompt PHP
// to see this as a directory even if it's a link.
- $buildPath = rtrim($this->getBuildPath(), '/');
+ $buildPath = \rtrim($this->getBuildPath(), '/');
- if (!$buildPath || !is_dir($buildPath)) {
+ if (!$buildPath || !\is_dir($buildPath)) {
return;
}
try {
$fileSystem = new Filesystem();
- if (is_link($buildPath)) {
+ if (\is_link($buildPath)) {
// Remove the symlink without using recursive.
- exec(sprintf('rm "%s"', $buildPath));
+ \exec(\sprintf('rm "%s"', $buildPath));
} else {
$fileSystem->remove($buildPath);
}
@@ -485,7 +439,7 @@ public function removeBuildDirectory($withArtifacts = false)
$fileSystem->remove(PUBLIC_DIR . 'artifacts/pdepend/' . $buildDirectory);
$fileSystem->remove(PUBLIC_DIR . 'artifacts/phpunit/' . $buildDirectory);
}
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
}
}
@@ -527,15 +481,15 @@ public function getPrettyDuration()
$end = new DateTime();
}
- $diff = date_diff($start, $end);
+ $diff = \date_diff($start, $end);
$parts = [];
foreach (['y', 'm', 'd', 'h', 'i', 's'] as $timePart) {
- if ($diff->{$timePart} != 0) {
- $parts[] = $diff->{$timePart} . ($timePart == 'i' ? 'm' : $timePart);
+ if ($diff->{$timePart} !== 0) {
+ $parts[] = $diff->{$timePart} . ($timePart === 'i' ? 'm' : $timePart);
}
}
- return implode(" ", $parts);
+ return \implode(" ", $parts);
}
/**
@@ -559,9 +513,9 @@ public function createWorkingCopy(Builder $builder, $buildPath)
*/
protected function writeSshKey()
{
- $tempKeyFile = tempnam(sys_get_temp_dir(), 'key_');
+ $tempKeyFile = \tempnam(\sys_get_temp_dir(), 'key_');
- file_put_contents($tempKeyFile, $this->getProject()->getSshPrivateKey());
+ \file_put_contents($tempKeyFile, $this->getProject()->getSshPrivateKey());
return $tempKeyFile;
}
@@ -583,10 +537,10 @@ protected function writeSshWrapper($keyFile)
ssh {$sshFlags} -o IdentityFile={$keyFile} $*
OUT;
- $tempShFile = tempnam(sys_get_temp_dir(), 'sh_');
+ $tempShFile = \tempnam(\sys_get_temp_dir(), 'sh_');
- file_put_contents($tempShFile, $script);
- shell_exec('chmod +x "' . $tempShFile . '"');
+ \file_put_contents($tempShFile, $script);
+ \shell_exec('chmod +x "' . $tempShFile . '"');
return $tempShFile;
}
@@ -650,7 +604,7 @@ public function getTotalErrorsCount($plugin = null, $severity = null, $isNew = n
if (!isset($this->totalErrorsCount[$key])) {
/** @var BuildErrorStore $store */
- $store = Factory::getStore('BuildError');
+ $store = $this->storeRegistry->get('BuildError');
$this->totalErrorsCount[$key] = (int)$store->getErrorTotalForBuild(
$this->getId(),
@@ -664,27 +618,52 @@ public function getTotalErrorsCount($plugin = null, $severity = null, $isNew = n
}
/**
- * @return int
- *
* @throws InvalidArgumentException
* @throws HttpException
*/
- public function getErrorsTrend()
+ public function getErrorsTrend(): array
{
$total = (int)$this->getErrorsTotal();
- $previous = $this->getErrorsTotalPrevious();
+ $previous = (int)$this->getErrorsTotalPrevious();
- if (null === $previous) {
- return 0;
- }
-
- $previous = (int)$previous;
if ($previous > $total) {
- return 1;
+ return [
+ 'trend' => 1,
+ 'delta' => $total - $previous,
+ ];
} elseif ($previous < $total) {
- return -1;
+ return [
+ 'trend' => -1,
+ 'delta' => $total - $previous,
+ ];
+ }
+
+ return [
+ 'trend' => 0,
+ 'delta' => 0,
+ ];
+ }
+
+ /**
+ * @throws InvalidArgumentException
+ * @throws HttpException
+ */
+ public function getTestCoverageTrend(): array
+ {
+ $total = $this->getTestCoverage();
+ $previous = $this->getTestCoveragePrevious();
+
+ if (null === $total) {
+ $total = '0.00';
+ }
+
+ if (null === $previous) {
+ $previous = '0.00';
}
- return 0;
+ return [
+ 'trend' => \bccomp($previous, $total, 2),
+ 'delta' => \bcsub($total, $previous, 2),
+ ];
}
}
diff --git a/src/Model/Build/BitbucketBuild.php b/src/Model/Build/BitbucketBuild.php
index c76787094..3a4918be5 100644
--- a/src/Model/Build/BitbucketBuild.php
+++ b/src/Model/Build/BitbucketBuild.php
@@ -5,26 +5,29 @@
use Exception;
use GuzzleHttp\Client;
use PHPCensor\Builder;
-use PHPCensor\Config;
use PHPCensor\Helper\Bitbucket;
use PHPCensor\Helper\Diff;
use PHPCensor\Model\Build;
use PHPCensor\Model\BuildError;
+use PHPCensor\Traits\Model\Build\GitGetDiffLineNumberTrait;
/**
* BitBucket Build Model
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class BitbucketBuild extends GitBuild
{
- /**
- * @var array
- */
- public static $pullrequestTriggersToSources = [
- 'pullrequest:created' => Build::SOURCE_WEBHOOK_PULL_REQUEST_CREATED,
- 'pullrequest:updated' => Build::SOURCE_WEBHOOK_PULL_REQUEST_UPDATED,
- 'pullrequest:approved' => Build::SOURCE_WEBHOOK_PULL_REQUEST_APPROVED,
+ use GitGetDiffLineNumberTrait;
+
+ public static array $pullrequestTriggersToSources = [
+ 'pullrequest:created' => Build::SOURCE_WEBHOOK_PULL_REQUEST_CREATED,
+ 'pullrequest:updated' => Build::SOURCE_WEBHOOK_PULL_REQUEST_UPDATED,
+ 'pullrequest:approved' => Build::SOURCE_WEBHOOK_PULL_REQUEST_APPROVED,
'pullrequest:fulfilled' => Build::SOURCE_WEBHOOK_PULL_REQUEST_MERGED,
];
@@ -55,7 +58,7 @@ public function getBranchLink()
*/
public function getRemoteBranchLink()
{
- $remoteBranch = $this->getExtra('remote_branch');
+ $remoteBranch = $this->getExtra('remote_branch');
$remoteReference = $this->getExtra('remote_reference');
return 'https://bitbucket.org/' . $remoteReference . '/src/?at=' . $remoteBranch;
@@ -78,7 +81,7 @@ public function getTagLink()
*/
public function sendStatusPostback()
{
- if (!in_array($this->getSource(), Build::$webhookSources, true)) {
+ if (!\in_array($this->getSource(), Build::$webhookSources, true)) {
return false;
}
@@ -87,14 +90,14 @@ public function sendStatusPostback()
return false;
}
- $username = Config::getInstance()->get('php-censor.bitbucket.username');
- $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password');
+ $username = $this->configuration->get('php-censor.bitbucket.username');
+ $appPassword = $this->configuration->get('php-censor.bitbucket.app_password');
- if (empty($username) || empty($appPassword) || empty($this->data['id'])) {
+ if (empty($username) || empty($appPassword) || empty($this->getId())) {
return false;
}
- $allowStatusCommit = (bool)Config::getInstance()->get(
+ $allowStatusCommit = (bool)$this->configuration->get(
'php-censor.bitbucket.status.commit',
false
);
@@ -108,50 +111,54 @@ public function sendStatusPostback()
case 1:
$status = 'INPROGRESS';
$description = 'PHP Censor build running.';
+
break;
case 2:
$status = 'SUCCESSFUL';
$description = 'PHP Censor build passed.';
+
break;
case 3:
$status = 'FAILED';
$description = 'PHP Censor build failed.';
+
break;
default:
$status = 'STOPPED';
$description = 'PHP Censor build failed to complete.';
+
break;
}
- $phpCensorUrl = Config::getInstance()->get('php-censor.url');
+ $phpCensorUrl = $this->configuration->get('php-censor.url');
- $url = sprintf(
+ $url = \sprintf(
'/2.0/repositories/%s/commit/%s/statuses/build',
- (in_array($this->getSource(), Build::$pullRequestSources, true)
+ (\in_array($this->getSource(), Build::$pullRequestSources, true)
? $this->getExtra('remote_reference')
: $project->getReference()),
$this->getCommitId()
);
$client = new Client([
- 'base_uri' => 'https://api.bitbucket.org',
+ 'base_uri' => 'https://api.bitbucket.org',
'http_errors' => false,
]);
$response = $client->post($url, [
- 'auth' => [$username, $appPassword],
+ 'auth' => [$username, $appPassword],
'headers' => [
'Content-Type' => 'application/json',
],
'json' => [
- 'state' => $status,
- 'key' => 'PHP-CENSOR',
- 'url' => $phpCensorUrl . '/build/view/' . $this->getId(),
- 'name' => 'PHP Censor Build #' . $this->getId(),
+ 'state' => $status,
+ 'key' => 'PHP-CENSOR',
+ 'url' => $phpCensorUrl . '/build/view/' . $this->getId(),
+ 'name' => 'PHP Censor Build #' . $this->getId(),
'description' => $description,
],
]);
- $status = (int)$response->getStatusCode();
+ $status = $response->getStatusCode();
return ($status >= 200 && $status < 300);
}
@@ -163,7 +170,7 @@ public function sendStatusPostback()
*/
protected function getCloneUrl()
{
- $key = trim($this->getProject()->getSshPrivateKey());
+ $key = \trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
return 'git@bitbucket.org:' . $this->getProject()->getReference() . '.git';
@@ -175,22 +182,13 @@ protected function getCloneUrl()
/**
* Get a template to use for generating links to files.
*
- * @return string|null
+ * @return string
*/
public function getFileLinkTemplate()
{
- $reference = $this->getProject()->getReference();
-
- if (in_array($this->getSource(), Build::$pullRequestSources, true)) {
- $reference = $this->getExtra('remote_reference');
- }
-
- $link = 'https://bitbucket.org/' . $reference . '/';
- $link .= 'src/' . $this->getCommitId() . '/';
- $link .= '{FILE}';
- $link .= '#{BASEFILE}-{LINE}';
+ $bitbucket = new Bitbucket($this->configuration);
- return $link;
+ return $bitbucket->getFileLinkTemplate($this);
}
/**
@@ -198,12 +196,12 @@ public function getFileLinkTemplate()
*/
protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = null)
{
- $success = true;
+ $success = true;
$skipGitFinalization = false;
try {
- if (in_array($this->getSource(), Build::$pullRequestSources, true)) {
- $helper = new Bitbucket();
+ if (\in_array($this->getSource(), Build::$pullRequestSources, true)) {
+ $helper = new Bitbucket($this->configuration);
$diff = $helper->getPullRequestDiff(
$this->getProject()->getReference(),
$this->getExtra('pull_request_number')
@@ -215,10 +213,10 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
$success = $builder->executeCommand($cmd, $cloneTo, $diffFile);
- unlink($diffFile);
+ \unlink($diffFile);
$skipGitFinalization = true;
}
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$success = false;
}
@@ -239,11 +237,11 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
*/
protected function writeDiff($cloneTo, $diff)
{
- $filePath = dirname($cloneTo . '/temp');
+ $filePath = \dirname($cloneTo . '/temp');
$diffFile = $filePath . '.patch';
- file_put_contents($diffFile, $diff);
- chmod($diffFile, 0600);
+ \file_put_contents($diffFile, $diff);
+ \chmod($diffFile, 0600);
return $diffFile;
}
@@ -263,12 +261,12 @@ public function reportError(
parent::reportError($builder, $plugin, $message, $severity, $file, $lineStart, $lineEnd);
try {
- $allowCommentCommit = (bool)Config::getInstance()->get(
+ $allowCommentCommit = (bool)$this->configuration->get(
'php-censor.bitbucket.comments.commit',
false
);
- $allowCommentPullRequest = (bool)Config::getInstance()->get(
+ $allowCommentPullRequest = (bool)$this->configuration->get(
'php-censor.bitbucket.comments.pull_request',
false
);
@@ -277,12 +275,12 @@ public function reportError(
if ($file) {
$diffLineNumber = $this->getDiffLineNumber($builder, $file, $lineStart);
- if (!is_null($diffLineNumber)) {
- $helper = new Bitbucket();
+ if (!\is_null($diffLineNumber)) {
+ $helper = new Bitbucket($this->configuration);
- $repo = $this->getProject()->getReference();
+ $repo = $this->getProject()->getReference();
$prNumber = $this->getExtra('pull_request_number');
- $commit = $this->getCommitId();
+ $commit = $this->getCommitId();
if (!empty($prNumber)) {
if ($allowCommentPullRequest) {
@@ -298,43 +296,6 @@ public function reportError(
}
} catch (\Throwable $e) {
$builder->getBuildLogger()->logFailure('Exception: ' . $e->getMessage(), $e);
- } catch (\Exception $e) {
- $builder->getBuildLogger()->logFailure('Exception: ' . $e->getMessage(), $e);
}
}
-
- /**
- * Uses git diff to figure out what the diff line position is, based on the error line number.
- *
- * @param string $file
- * @param int $line
- *
- * @return int|null
- */
- protected function getDiffLineNumber(Builder $builder, $file, $line)
- {
- $builder->logExecOutput(false);
-
- $line = (int)$line;
- $prNumber = $this->getExtra('pull_request_number');
- $path = $builder->buildPath;
-
- if (!empty($prNumber)) {
- $builder->executeCommand('cd "%s" && git diff "origin/%s" "%s"', $path, $this->getBranch(), $file);
- } else {
- $commitId = $this->getCommitId();
- $compare = empty($commitId) ? 'HEAD' : $commitId;
-
- $builder->executeCommand('cd "%s" && git diff "%s^^" "%s"', $path, $compare, $file);
- }
-
- $builder->logExecOutput(true);
-
- $diff = $builder->getLastOutput();
-
- $helper = new Diff();
- $lines = $helper->getLinePositions($diff);
-
- return isset($lines[$line]) ? $lines[$line] : null;
- }
}
diff --git a/src/Model/Build/BitbucketHgBuild.php b/src/Model/Build/BitbucketHgBuild.php
index 0ccdc0320..6ef6348b4 100644
--- a/src/Model/Build/BitbucketHgBuild.php
+++ b/src/Model/Build/BitbucketHgBuild.php
@@ -2,12 +2,16 @@
namespace PHPCensor\Model\Build;
-use PHPCensor\Model\Build;
+use PHPCensor\Helper\Bitbucket;
/**
* BitbucketHgBuild Build Model
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Artem Bochkov
+ * @author Dmitry Khomutov
*/
class BitbucketHgBuild extends HgBuild
{
@@ -61,7 +65,7 @@ public function getTagLink()
*/
protected function getCloneUrl()
{
- $key = trim($this->getProject()->getSshPrivateKey());
+ $key = \trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
return 'ssh://hg@bitbucket.org/' . $this->getProject()->getReference();
@@ -77,17 +81,8 @@ protected function getCloneUrl()
*/
public function getFileLinkTemplate()
{
- $reference = $this->getProject()->getReference();
-
- if (in_array($this->getSource(), Build::$pullRequestSources, true)) {
- $reference = $this->getExtra('remote_reference');
- }
-
- $link = 'https://bitbucket.org/' . $reference . '/';
- $link .= 'src/' . $this->getCommitId() . '/';
- $link .= '{FILE}';
- $link .= '#{BASEFILE}-{LINE}';
+ $bitbucket = new Bitbucket($this->configuration);
- return $link;
+ return $bitbucket->getFileLinkTemplate($this);
}
}
diff --git a/src/Model/Build/BitbucketServerBuild.php b/src/Model/Build/BitbucketServerBuild.php
index 378073dc8..2c0707c1d 100644
--- a/src/Model/Build/BitbucketServerBuild.php
+++ b/src/Model/Build/BitbucketServerBuild.php
@@ -4,14 +4,18 @@
use Exception;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model\Build;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class BitbucketServerBuild extends GitBuild
{
- /**
- * @var array
- */
- public static $pullrequestTriggersToSources = [
+ public static array $pullrequestTriggersToSources = [
'pr:opened' => Build::SOURCE_WEBHOOK_PULL_REQUEST_CREATED,
'pr:updated' => Build::SOURCE_WEBHOOK_PULL_REQUEST_UPDATED,
'pr:approved' => Build::SOURCE_WEBHOOK_PULL_REQUEST_APPROVED,
@@ -92,7 +96,7 @@ public function getFileLinkTemplate()
{
$reference = $this->getProject()->getReference();
- if (in_array($this->getSource(), Build::$pullRequestSources, true)) {
+ if (\in_array($this->getSource(), Build::$pullRequestSources, true)) {
$reference = $this->getExtra('remote_reference');
}
@@ -113,7 +117,7 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
$skipGitFinalization = false;
try {
- if (in_array($this->getSource(), Build::$pullRequestSources, true)) {
+ if (\in_array($this->getSource(), Build::$pullRequestSources, true)) {
$diff = $this->getPullRequestDiff($builder, $cloneTo, $extra['remote_branch']);
$diffFile = $this->writeDiff($builder->buildPath, $diff);
@@ -127,10 +131,9 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
$success = $builder->executeCommand($applyCmd, $diffFile);
}
- //unlink($diffFile);
$skipGitFinalization = true;
}
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$success = false;
}
@@ -156,7 +159,7 @@ protected function getPullRequestDiff(Builder $builder, $cloneTo, $targetBranch)
return $builder->getLastOutput();
}
- throw new Exception('Unable to create diff patch.');
+ throw new RuntimeException('Unable to create diff patch.');
}
/**
@@ -169,11 +172,11 @@ protected function getPullRequestDiff(Builder $builder, $cloneTo, $targetBranch)
*/
protected function writeDiff($cloneTo, $diff)
{
- $filePath = dirname($cloneTo . '/temp');
+ $filePath = \dirname($cloneTo . '/temp');
$diffFile = $filePath . '.patch';
- file_put_contents($diffFile, $diff);
- chmod($diffFile, 0600);
+ \file_put_contents($diffFile, $diff);
+ \chmod($diffFile, 0600);
return $diffFile;
}
diff --git a/src/Model/Build/GitBuild.php b/src/Model/Build/GitBuild.php
index 3bcd320f6..65528935e 100644
--- a/src/Model/Build/GitBuild.php
+++ b/src/Model/Build/GitBuild.php
@@ -4,15 +4,21 @@
use Exception;
use PHPCensor\Builder;
+use PHPCensor\Common\Application\ConfigurationInterface;
use PHPCensor\Model\Build;
+use PHPCensor\StoreRegistry;
use Psr\Log\LogLevel;
/**
* Remote Git Build Model
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
-class GitBuild extends Build
+class GitBuild extends TypedBuild
{
/**
* Get the URL to be used to clone this remote repository.
@@ -35,7 +41,7 @@ protected function getCloneUrl()
*/
public function createWorkingCopy(Builder $builder, $buildPath)
{
- $key = trim($this->getProject()->getSshPrivateKey());
+ $key = \trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
$success = $this->cloneBySsh($builder, $buildPath);
@@ -93,11 +99,11 @@ protected function cloneByHttp(Builder $builder, $cloneTo)
$buildSettings = $builder->getConfig('build_settings');
if ($buildSettings && isset($buildSettings['clone_depth']) && (0 < (int)$buildSettings['clone_depth'])) {
- $cmd .= ' --depth ' . intval($buildSettings['clone_depth']) . ' ';
+ $cmd .= ' --depth ' . \intval($buildSettings['clone_depth']) . ' ';
}
- $cmd .= ' -b "%s" "%s" "%s"';
- $success = $builder->executeCommand($cmd, $this->getBranch(), $this->getCloneUrl(), $cloneTo);
+ $cmd .= ' -b %s "%s" "%s"';
+ $success = $builder->executeCommand($cmd, \escapeshellarg($this->getBranch()), $this->getCloneUrl(), $cloneTo);
if ($success) {
$success = $this->postCloneSetup($builder, $cloneTo);
@@ -123,13 +129,13 @@ protected function cloneBySsh(Builder $builder, $cloneTo)
$buildSettings = $builder->getConfig('build_settings');
if ($buildSettings && isset($buildSettings['clone_depth']) && (0 < (int)$buildSettings['clone_depth'])) {
- $cmd .= ' --depth ' . intval($buildSettings['clone_depth']) . ' ';
+ $cmd .= ' --depth ' . \intval($buildSettings['clone_depth']) . ' ';
}
- $cmd .= ' -b "%s" "%s" "%s"';
+ $cmd .= ' -b %s "%s" "%s"';
$cmd = 'export GIT_SSH="' . $gitSshWrapper . '" && ' . $cmd;
- $success = $builder->executeCommand($cmd, $this->getBranch(), $this->getCloneUrl(), $cloneTo);
+ $success = $builder->executeCommand($cmd, \escapeshellarg($this->getBranch()), $this->getCloneUrl(), $cloneTo);
if ($success) {
$extra = [
@@ -140,8 +146,8 @@ protected function cloneBySsh(Builder $builder, $cloneTo)
}
// Remove the key file and git wrapper:
- unlink($keyFile);
- unlink($gitSshWrapper);
+ \unlink($keyFile);
+ \unlink($gitSshWrapper);
return $success;
}
@@ -161,21 +167,21 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
if (empty($this->getEnvironmentId()) && !empty($commitId)) {
$cmd = $chdir . ' && git checkout %s --quiet';
- $success = $builder->executeCommand($cmd, $cloneTo, $commitId);
+ $success = $builder->executeCommand($cmd, $cloneTo, \escapeshellarg($commitId));
}
// Always update the commit hash with the actual HEAD hash
if ($builder->executeCommand($chdir . ' && git rev-parse HEAD', $cloneTo)) {
- $commitId = trim($builder->getLastOutput());
+ $commitId = \trim($builder->getLastOutput());
$this->setCommitId($commitId);
- if ($builder->executeCommand($chdir . ' && git log -1 --pretty=format:%%s %s', $cloneTo, $commitId)) {
- $this->setCommitMessage(trim($builder->getLastOutput()));
+ if ($builder->executeCommand($chdir . ' && git log -1 --pretty=format:%%s %s', $cloneTo, \escapeshellarg($commitId))) {
+ $this->setCommitMessage(\trim($builder->getLastOutput()));
}
- if ($builder->executeCommand($chdir . ' && git log -1 --pretty=format:%%ae %s', $cloneTo, $commitId)) {
- $this->setCommitterEmail(trim($builder->getLastOutput()));
+ if ($builder->executeCommand($chdir . ' && git log -1 --pretty=format:%%ae %s', $cloneTo, \escapeshellarg($commitId))) {
+ $this->setCommitterEmail(\trim($builder->getLastOutput()));
}
}
diff --git a/src/Model/Build/GithubBuild.php b/src/Model/Build/GithubBuild.php
index 30ad6dc96..1b537b975 100644
--- a/src/Model/Build/GithubBuild.php
+++ b/src/Model/Build/GithubBuild.php
@@ -5,23 +5,25 @@
use Exception;
use GuzzleHttp\Client;
use PHPCensor\Builder;
-use PHPCensor\Config;
-use PHPCensor\Helper\Diff;
use PHPCensor\Helper\Github;
use PHPCensor\Model\Build;
use PHPCensor\Model\BuildError;
+use PHPCensor\Traits\Model\Build\GitGetDiffLineNumberTrait;
/**
* Github Build Model
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class GithubBuild extends GitBuild
{
- /**
- * @var array
- */
- public static $pullrequestTriggersToSources = [
+ use GitGetDiffLineNumberTrait;
+
+ public static array $pullrequestTriggersToSources = [
'opened' => Build::SOURCE_WEBHOOK_PULL_REQUEST_CREATED,
'synchronize' => Build::SOURCE_WEBHOOK_PULL_REQUEST_UPDATED,
'reopened' => Build::SOURCE_WEBHOOK_PULL_REQUEST_UPDATED,
@@ -91,7 +93,7 @@ public function getTagLink()
*/
public function sendStatusPostback()
{
- if (!in_array($this->getSource(), Build::$webhookSources, true)) {
+ if (!\in_array($this->getSource(), Build::$webhookSources, true)) {
return false;
}
@@ -100,12 +102,12 @@ public function sendStatusPostback()
return false;
}
- $token = Config::getInstance()->get('php-censor.github.token');
- if (empty($token) || empty($this->data['id'])) {
+ $token = $this->configuration->get('php-censor.github.token');
+ if (empty($token) || empty($this->getId())) {
return false;
}
- $allowStatusCommit = (bool)Config::getInstance()->get(
+ $allowStatusCommit = (bool)$this->configuration->get(
'php-censor.github.status.commit',
false
);
@@ -119,22 +121,26 @@ public function sendStatusPostback()
case 1:
$status = 'pending';
$description = 'PHP Censor build running.';
+
break;
case 2:
$status = 'success';
$description = 'PHP Censor build passed.';
+
break;
case 3:
$status = 'failure';
$description = 'PHP Censor build failed.';
+
break;
default:
$status = 'error';
$description = 'PHP Censor build failed to complete.';
+
break;
}
- $phpCensorUrl = Config::getInstance()->get('php-censor.url');
+ $phpCensorUrl = $this->configuration->get('php-censor.url');
$url = '/repos/' . $project->getReference() . '/statuses/' . $this->getCommitId();
$client = new Client([
@@ -166,7 +172,7 @@ public function sendStatusPostback()
*/
protected function getCloneUrl()
{
- $key = trim($this->getProject()->getSshPrivateKey());
+ $key = \trim($this->getProject()->getSshPrivateKey());
$port = $this->getProject()->getAccessInformation('port');
@@ -185,19 +191,17 @@ protected function getCloneUrl()
/**
* Get a parsed version of the commit message, with links to issues and commits.
- *
- * @return string
*/
- public function getCommitMessage()
+ public function getCommitMessage(): ?string
{
$message = parent::getCommitMessage();
$project = $this->getProject();
- if (!is_null($project)) {
+ if (!\is_null($project)) {
$reference = $project->getReference();
$commitLink = '#$1';
- $message = preg_replace('/\#([0-9]+)/', $commitLink, $message);
- $message = preg_replace(
+ $message = \preg_replace('/\#([0-9]+)/', $commitLink, $message);
+ $message = \preg_replace(
'/\@([a-zA-Z0-9_]+)/',
'@$1',
$message
@@ -215,7 +219,7 @@ public function getCommitMessage()
public function getFileLinkTemplate()
{
$reference = $this->getProject()->getReference();
- if (in_array($this->getSource(), Build::$pullRequestSources, true)) {
+ if (\in_array($this->getSource(), Build::$pullRequestSources, true)) {
$reference = $this->getExtra('remote_reference');
}
@@ -235,7 +239,7 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
$success = true;
try {
- if (in_array($this->getSource(), Build::$pullRequestSources, true)) {
+ if (\in_array($this->getSource(), Build::$pullRequestSources, true)) {
$pullRequestId = $this->getExtra('pull_request_number');
$cmd = 'cd "%s" && git checkout -b php-censor/'
@@ -248,7 +252,7 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
$success = $builder->executeCommand($cmd, $cloneTo, $this->getBranch(), $pullRequestId);
}
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$success = false;
}
@@ -264,22 +268,22 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
*/
public function reportError(
Builder $builder,
- $plugin,
- $message,
- $severity = BuildError::SEVERITY_NORMAL,
- $file = null,
- $lineStart = null,
- $lineEnd = null
+ string $plugin,
+ string $message,
+ int $severity = BuildError::SEVERITY_NORMAL,
+ ?string $file = null,
+ ?int $lineStart = null,
+ ?int $lineEnd = null
) {
parent::reportError($builder, $plugin, $message, $severity, $file, $lineStart, $lineEnd);
try {
- $allowCommentCommit = (bool)Config::getInstance()->get(
+ $allowCommentCommit = (bool)$this->configuration->get(
'php-censor.github.comments.commit',
false
);
- $allowCommentPullRequest = (bool)Config::getInstance()->get(
+ $allowCommentPullRequest = (bool)$this->configuration->get(
'php-censor.github.comments.pull_request',
false
);
@@ -288,8 +292,8 @@ public function reportError(
if ($file) {
$diffLineNumber = $this->getDiffLineNumber($builder, $file, $lineStart);
- if (!is_null($diffLineNumber)) {
- $helper = new Github();
+ if (!\is_null($diffLineNumber)) {
+ $helper = new Github($this->configuration);
$repo = $this->getProject()->getReference();
$prNumber = $this->getExtra('pull_request_number');
@@ -309,43 +313,6 @@ public function reportError(
}
} catch (\Throwable $e) {
$builder->getBuildLogger()->logFailure('Exception: ' . $e->getMessage(), $e);
- } catch (\Exception $e) {
- $builder->getBuildLogger()->logFailure('Exception: ' . $e->getMessage(), $e);
}
}
-
- /**
- * Uses git diff to figure out what the diff line position is, based on the error line number.
- *
- * @param string $file
- * @param int $line
- *
- * @return int|null
- */
- protected function getDiffLineNumber(Builder $builder, $file, $line)
- {
- $builder->logExecOutput(false);
-
- $line = (int)$line;
- $prNumber = $this->getExtra('pull_request_number');
- $path = $builder->buildPath;
-
- if (!empty($prNumber)) {
- $builder->executeCommand('cd "%s" && git diff "origin/%s" "%s"', $path, $this->getBranch(), $file);
- } else {
- $commitId = $this->getCommitId();
- $compare = empty($commitId) ? 'HEAD' : $commitId;
-
- $builder->executeCommand('cd "%s" && git diff "%s^^" "%s"', $path, $compare, $file);
- }
-
- $builder->logExecOutput(true);
-
- $diff = $builder->getLastOutput();
-
- $helper = new Diff();
- $lines = $helper->getLinePositions($diff);
-
- return isset($lines[$line]) ? $lines[$line] : null;
- }
}
diff --git a/src/Model/Build/GitlabBuild.php b/src/Model/Build/GitlabBuild.php
index dbeb86454..b37b8f911 100644
--- a/src/Model/Build/GitlabBuild.php
+++ b/src/Model/Build/GitlabBuild.php
@@ -5,7 +5,11 @@
/**
* Gitlab Build Model
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author André Cianfarani
+ * @author Dmitry Khomutov
*/
class GitlabBuild extends GitBuild
{
@@ -40,7 +44,7 @@ public function getBranchLink()
*/
public function getFileLinkTemplate()
{
- return sprintf(
+ return \sprintf(
'//%s/%s/blob/%s/{FILE}#L{LINE}',
$this->getProject()->getAccessInformation('domain'),
$this->getProject()->getReference(),
@@ -53,7 +57,7 @@ public function getFileLinkTemplate()
*/
protected function getCloneUrl()
{
- $key = trim($this->getProject()->getSshPrivateKey());
+ $key = \trim($this->getProject()->getSshPrivateKey());
$user = $this->getProject()->getAccessInformation('user');
$domain = $this->getProject()->getAccessInformation('domain');
diff --git a/src/Model/Build/GogsBuild.php b/src/Model/Build/GogsBuild.php
index 7a478cd47..0788529d5 100644
--- a/src/Model/Build/GogsBuild.php
+++ b/src/Model/Build/GogsBuild.php
@@ -4,6 +4,11 @@
/**
* GogsBuild Build Model
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class GogsBuild extends GitBuild
{
@@ -14,7 +19,7 @@ class GogsBuild extends GitBuild
*/
protected function getCleanedReferenceForLink()
{
- return preg_replace('/\.git$/i', '', $this->getProject()->getReference());
+ return \preg_replace('/\.git$/i', '', $this->getProject()->getReference());
}
/**
@@ -44,7 +49,7 @@ public function getBranchLink()
*/
public function getFileLinkTemplate()
{
- return sprintf(
+ return \sprintf(
'%s/src/%s/{FILE}#L{LINE}',
$this->getCleanedReferenceForLink(),
$this->getCommitId()
diff --git a/src/Model/Build/HgBuild.php b/src/Model/Build/HgBuild.php
index 5a2f7c001..046dc8241 100644
--- a/src/Model/Build/HgBuild.php
+++ b/src/Model/Build/HgBuild.php
@@ -4,15 +4,33 @@
use Exception;
use PHPCensor\Builder;
+use PHPCensor\Common\Application\ConfigurationInterface;
use PHPCensor\Model\Build;
+use PHPCensor\StoreRegistry;
/**
* Mercurial Build Model
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Pavel Gopanenko
+ * @author Dmitry Khomutov
*/
class HgBuild extends Build
{
+ protected ConfigurationInterface $configuration;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ StoreRegistry $storeRegistry,
+ array $initialData = []
+ ) {
+ parent::__construct($storeRegistry, $initialData);
+
+ $this->configuration = $configuration;
+ }
+
/**
* Get the URL to be used to clone this remote repository.
*
@@ -34,7 +52,7 @@ protected function getCloneUrl()
*/
public function createWorkingCopy(Builder $builder, $buildPath)
{
- $key = trim($this->getProject()->getSshPrivateKey());
+ $key = \trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
$success = $this->cloneBySsh($builder, $buildPath);
@@ -60,7 +78,7 @@ public function createWorkingCopy(Builder $builder, $buildPath)
*/
protected function cloneByHttp(Builder $builder, $cloneTo)
{
- return $builder->executeCommand('hg clone %s "%s" -r %s', $this->getCloneUrl(), $cloneTo, $this->getBranch());
+ return $builder->executeCommand('hg clone %s "%s" -r %s', $this->getCloneUrl(), $cloneTo, \escapeshellarg($this->getBranch()));
}
/**
@@ -76,14 +94,14 @@ protected function cloneBySsh(Builder $builder, $cloneTo)
// Do the hg clone:
$cmd = 'hg clone --ssh "ssh -i ' . $keyFile . '" %s "%s" -r %s';
- $success = $builder->executeCommand($cmd, $this->getCloneUrl(), $cloneTo, $this->getBranch());
+ $success = $builder->executeCommand($cmd, $this->getCloneUrl(), $cloneTo, \escapeshellarg($this->getBranch()));
if ($success) {
$success = $this->postCloneSetup($builder, $cloneTo);
}
// Remove the key file:
- unlink($keyFile);
+ \unlink($keyFile);
return $success;
}
@@ -103,7 +121,7 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul
// Allow switching to a specific branch:
if (!empty($commitId)) {
$cmd = 'cd "%s" && hg checkout %s';
- $success = $builder->executeCommand($cmd, $cloneTo, $this->getBranch());
+ $success = $builder->executeCommand($cmd, $cloneTo, \escapeshellarg($this->getBranch()));
}
return $success;
diff --git a/src/Model/Build/LocalBuild.php b/src/Model/Build/LocalBuild.php
index 7a82fd9af..a129ec73b 100644
--- a/src/Model/Build/LocalBuild.php
+++ b/src/Model/Build/LocalBuild.php
@@ -9,9 +9,13 @@
/**
* Local Build Model
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
-class LocalBuild extends Build
+class LocalBuild extends TypedBuild
{
/**
* Create a working copy by cloning, copying, or similar.
@@ -25,12 +29,12 @@ class LocalBuild extends Build
public function createWorkingCopy(Builder $builder, $buildPath)
{
$reference = $this->getProject()->getReference();
- $reference = substr($reference, -1) == '/' ? substr($reference, 0, -1) : $reference;
- $buildPath = substr($buildPath, 0, -1);
+ $reference = \substr($reference, -1) === '/' ? \substr($reference, 0, -1) : $reference;
+ $buildPath = \substr($buildPath, 0, -1);
// If there's a /config file in the reference directory, it is probably a bare repository
// which we'll extract into our build path directly.
- if (is_file($reference . '/config') &&
+ if (\is_file($reference . '/config') &&
true === $this->handleBareRepository($builder, $reference, $buildPath)) {
return $this->handleConfig($builder, $buildPath);
}
@@ -63,7 +67,7 @@ public function createWorkingCopy(Builder $builder, $buildPath)
*/
protected function handleBareRepository(Builder $builder, $reference, $buildPath)
{
- $gitConfig = parse_ini_file($reference.'/config', true);
+ $gitConfig = \parse_ini_file($reference.'/config', true);
// If it is indeed a bare repository, then extract it into our build path:
if ($gitConfig['core']['bare']) {
@@ -86,13 +90,13 @@ protected function handleBareRepository(Builder $builder, $reference, $buildPath
*/
protected function handleSymlink(Builder $builder, $reference, $buildPath)
{
- if (is_link($buildPath) && is_file($buildPath)) {
- unlink($buildPath);
+ if (\is_link($buildPath) && \is_file($buildPath)) {
+ \unlink($buildPath);
}
- $builder->log(sprintf('Symlinking: %s to %s', $reference, $buildPath));
+ $builder->log(\sprintf('Symlinking: %s to %s', $reference, $buildPath));
- if (!symlink($reference, $buildPath)) {
+ if (!\symlink($reference, $buildPath)) {
$builder->logFailure('Failed to symlink.');
return false;
diff --git a/src/Model/Build/SvnBuild.php b/src/Model/Build/SvnBuild.php
index a7ac774cc..a1ab34981 100644
--- a/src/Model/Build/SvnBuild.php
+++ b/src/Model/Build/SvnBuild.php
@@ -9,11 +9,15 @@
/**
* Remote Subversion Build Model
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Nadir Dzhilkibaev
+ * @author Dmitry Khomutov
*/
-class SvnBuild extends Build
+class SvnBuild extends TypedBuild
{
- protected $svnCommand = 'svn export -q --non-interactive ';
+ protected string $svnCommand = 'svn export -q --non-interactive ';
/**
* Get the URL to be used to clone this remote repository.
@@ -22,15 +26,15 @@ class SvnBuild extends Build
*/
protected function getCloneUrl()
{
- $url = rtrim($this->getProject()->getReference(), '/') . '/';
- $branch = ltrim($this->getBranch(), '/');
+ $url = \rtrim($this->getProject()->getReference(), '/') . '/';
+ $branch = \ltrim($this->getBranch(), '/');
// For empty default branch or default branch name like "/trunk" or "trunk" (-> "trunk")
- if (empty($branch) || $branch == 'trunk') {
+ if (empty($branch) || $branch === 'trunk') {
$url .= 'trunk';
- // For default branch with standard default branch directory ("branches") like "/branch-1" or "branch-1"
- // (-> "branches/branch-1")
- } elseif (false === strpos($branch, '/')) {
+ // For default branch with standard default branch directory ("branches") like "/branch-1" or "branch-1"
+ // (-> "branches/branch-1")
+ } elseif (false === \strpos($branch, '/')) {
$url .= 'branches/' . $branch;
// For default branch with non-standard branch directory like "/branch/branch-1" or "branch/branch-1"
// (-> "branch/branch-1")
@@ -50,14 +54,14 @@ protected function extendSvnCommandFromConfig(Builder $builder)
$buildSettings = $builder->getConfig('build_settings');
if ($buildSettings) {
- if (isset($buildSettings['svn']) && is_array($buildSettings['svn'])) {
+ if (isset($buildSettings['svn']) && \is_array($buildSettings['svn'])) {
foreach ($buildSettings['svn'] as $key => $value) {
$cmd .= " --${key} ${value} ";
}
}
if (isset($buildSettings['clone_depth']) && 0 < (int)$buildSettings['clone_depth']) {
- $cmd .= ' --depth ' . intval($buildSettings['clone_depth']) . ' ';
+ $cmd .= ' --depth ' . \intval($buildSettings['clone_depth']) . ' ';
}
}
@@ -77,7 +81,7 @@ public function createWorkingCopy(Builder $builder, $buildPath)
{
$this->extendSvnCommandFromConfig($builder);
- $key = trim($this->getProject()->getSshPrivateKey());
+ $key = \trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
$success = $this->cloneBySsh($builder, $buildPath);
@@ -107,7 +111,7 @@ protected function cloneByHttp(Builder $builder, $cloneTo)
if (!empty($this->getCommitId())) {
$cmd .= ' -r %s %s "%s"';
- $success = $builder->executeCommand($cmd, $this->getCommitId(), $this->getCloneUrl(), $cloneTo);
+ $success = $builder->executeCommand($cmd, \escapeshellarg($this->getCommitId()), $this->getCloneUrl(), $cloneTo);
} else {
$cmd .= ' %s "%s"';
$success = $builder->executeCommand($cmd, $this->getCloneUrl(), $cloneTo);
@@ -133,8 +137,8 @@ protected function cloneBySsh(Builder $builder, $cloneTo)
$success = $builder->executeCommand($cmd, $this->getCloneUrl(), $cloneTo);
// Remove the key file and svn wrapper:
- unlink($keyFile);
- unlink($sshWrapper);
+ \unlink($keyFile);
+ \unlink($sshWrapper);
return $success;
}
diff --git a/src/Model/Build/TypedBuild.php b/src/Model/Build/TypedBuild.php
new file mode 100644
index 000000000..410f3a497
--- /dev/null
+++ b/src/Model/Build/TypedBuild.php
@@ -0,0 +1,30 @@
+
+ */
+class TypedBuild extends Build
+{
+ protected ConfigurationInterface $configuration;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ StoreRegistry $storeRegistry,
+ array $initialData = []
+ ) {
+ parent::__construct($storeRegistry, $initialData);
+
+ $this->configuration = $configuration;
+ }
+}
diff --git a/src/Model/BuildError.php b/src/Model/BuildError.php
index 63c5ed892..b8e1496b0 100644
--- a/src/Model/BuildError.php
+++ b/src/Model/BuildError.php
@@ -1,11 +1,19 @@
+ * @author Dmitry Khomutov
+ */
class BuildError extends BaseBuildError
{
/**
@@ -19,7 +27,7 @@ public function getBuild()
}
/** @var BuildStore $buildStore */
- $buildStore = Factory::getStore('Build');
+ $buildStore = $this->storeRegistry->get('Build');
return $buildStore->getById($buildId);
}
@@ -82,7 +90,7 @@ public static function getSeverityName($severity)
*/
public static function generateHash($plugin, $file, $lineStart, $lineEnd, $severity, $message)
{
- return md5($plugin . $file . $lineStart . $lineEnd . $severity . $message);
+ return \md5($plugin . $file . $lineStart . $lineEnd . $severity . $message);
}
/**
diff --git a/src/Model/BuildMeta.php b/src/Model/BuildMeta.php
index b6e09dd78..8dbc8a4ea 100644
--- a/src/Model/BuildMeta.php
+++ b/src/Model/BuildMeta.php
@@ -1,11 +1,19 @@
+ * @author Dmitry Khomutov
+ */
class BuildMeta extends BaseBuildMeta
{
/**
@@ -19,7 +27,7 @@ public function getBuild()
}
/** @var BuildStore $buildStore */
- $buildStore = Factory::getStore('Build');
+ $buildStore = $this->storeRegistry->get('Build');
return $buildStore->getById($buildId);
}
diff --git a/src/Model/Environment.php b/src/Model/Environment.php
index acac89084..745b4d671 100644
--- a/src/Model/Environment.php
+++ b/src/Model/Environment.php
@@ -1,9 +1,17 @@
+ */
class Environment extends BaseEnvironment
{
}
diff --git a/src/Model/Project.php b/src/Model/Project.php
index 5c2b4e252..ff377e942 100644
--- a/src/Model/Project.php
+++ b/src/Model/Project.php
@@ -1,16 +1,21 @@
+ * @author Dmitry Khomutov
*/
class Project extends BaseProject
{
@@ -25,7 +30,7 @@ public function getGroup()
}
/** @var ProjectGroupStore $groupStore */
- $groupStore = Factory::getStore('ProjectGroup');
+ $groupStore = $this->storeRegistry->get('ProjectGroup');
return $groupStore->getById($groupId);
}
@@ -37,7 +42,7 @@ public function getGroup()
*/
public function getProjectBuilds()
{
- return Factory::getStore('Build')->getByProjectId($this->getId());
+ return $this->storeRegistry->get('Build')->getByProjectId($this->getId());
}
/**
@@ -60,10 +65,10 @@ public function getLatestBuild($branch, $status = null)
}
$order = ['id' => 'DESC'];
- $builds = Factory::getStore('Build')->getWhere($criteria, 1, 0, $order);
+ $builds = $this->storeRegistry->get('Build')->getWhere($criteria, 1, 0, $order);
- if (is_array($builds['items']) && count($builds['items'])) {
- $latest = array_shift($builds['items']);
+ if (\is_array($builds['items']) && \count($builds['items'])) {
+ $latest = \array_shift($builds['items']);
if (isset($latest) && $latest instanceof Build) {
return $latest;
@@ -84,13 +89,13 @@ public function getPreviousBuild($branch)
{
$criteria = [
'branch' => $branch,
- 'project_id' => $this->getId()
+ 'project_id' => $this->getId(),
];
$order = ['id' => 'DESC'];
- $builds = Factory::getStore('Build')->getWhere($criteria, 1, 1, $order);
+ $builds = $this->storeRegistry->get('Build')->getWhere($criteria, 1, 1, $order);
- if (is_array($builds['items']) && count($builds['items'])) {
- $previous = array_shift($builds['items']);
+ if (\is_array($builds['items']) && \count($builds['items'])) {
+ $previous = \array_shift($builds['items']);
if (isset($previous) && $previous instanceof Build) {
return $previous;
@@ -110,12 +115,14 @@ public function getIcon()
switch ($this->getType()) {
case Project::TYPE_GITHUB:
$icon = 'github';
+
break;
case Project::TYPE_BITBUCKET:
case Project::TYPE_BITBUCKET_HG:
case Project::TYPE_BITBUCKET_SERVER:
$icon = 'bitbucket';
+
break;
case Project::TYPE_GIT:
@@ -125,6 +132,7 @@ public function getIcon()
case Project::TYPE_SVN:
default:
$icon = 'code-fork';
+
break;
}
@@ -136,10 +144,7 @@ public function getIcon()
*/
protected function getEnvironmentStore()
{
- /** @var EnvironmentStore $store */
- $store = Factory::getStore('Environment');
-
- return $store;
+ return $this->storeRegistry->get('Environment');
}
/**
@@ -150,7 +155,6 @@ protected function getEnvironmentStore()
public function getEnvironmentsObjects()
{
$projectId = $this->getId();
-
if (empty($projectId)) {
return null;
}
@@ -167,9 +171,11 @@ public function getEnvironmentsNames()
{
$environments = $this->getEnvironmentsObjects();
$environmentsNames = [];
- foreach ($environments['items'] as $environment) {
- /** @var Environment $environment */
- $environmentsNames[] = $environment->getName();
+ if ($environments) {
+ foreach ($environments['items'] as $environment) {
+ /** @var Environment $environment */
+ $environmentsNames[] = $environment->getName();
+ }
}
return $environmentsNames;
@@ -184,15 +190,16 @@ public function getEnvironments()
{
$environments = $this->getEnvironmentsObjects();
$environmentsConfig = [];
- foreach ($environments['items'] as $environment) {
- /** @var Environment $environment */
- $environmentsConfig[$environment->getName()] = $environment->getBranches();
+ if ($environments) {
+ foreach ($environments['items'] as $environment) {
+ /** @var Environment $environment */
+ $environmentsConfig[$environment->getName()] = $environment->getBranches();
+ }
}
$yamlDumper = new YamlDumper();
- $value = $yamlDumper->dump($environmentsConfig, 10, 0, true, false);
- return $value;
+ return $yamlDumper->dump($environmentsConfig, 10, 0);
}
/**
@@ -204,27 +211,32 @@ public function setEnvironments($value)
{
$yamlParser = new YamlParser();
$environmentsConfig = $yamlParser->parse($value);
- $environmentsNames = !empty($environmentsConfig) ? array_keys($environmentsConfig) : [];
+ $environmentsNames = (!empty($environmentsConfig) && \is_array($environmentsConfig)) ? \array_keys($environmentsConfig) : [];
$currentEnvironments = $this->getEnvironmentsObjects();
$store = $this->getEnvironmentStore();
- foreach ($currentEnvironments['items'] as $environment) {
- /** @var Environment $environment */
- $key = array_search($environment->getName(), $environmentsNames, true);
- if ($key !== false) {
- // already exist
- unset($environmentsNames[$key]);
- $environment->setBranches(!empty($environmentsConfig[$environment->getName()]) ? $environmentsConfig[$environment->getName()] : []);
- $store->save($environment);
- } else {
- // remove
- $store->delete($environment);
+ if (!empty($currentEnvironments['items'])) {
+ foreach ($currentEnvironments['items'] as $environment) {
+ /** @var Environment $environment */
+ $key = \array_search($environment->getName(), $environmentsNames, true);
+ if ($key !== false) {
+ // already exist
+ unset($environmentsNames[$key]);
+ $branches = !empty($environmentsConfig[$environment->getName()])
+ ? $environmentsConfig[$environment->getName()]
+ : [];
+ $environment->setBranches($branches);
+ $store->save($environment);
+ } else {
+ // remove
+ $store->delete($environment);
+ }
}
}
if (!empty($environmentsNames)) {
// add
foreach ($environmentsNames as $environmentName) {
- $environment = new Environment();
+ $environment = new Environment($this->storeRegistry);
$environment->setProjectId($this->getId());
$environment->setName($environmentName);
$environment->setBranches(!empty($environmentsConfig[$environment->getName()]) ? $environmentsConfig[$environment->getName()] : []);
@@ -236,7 +248,7 @@ public function setEnvironments($value)
/**
* @param string $branch
*
- * @return string[]
+ * @return int[]
*/
public function getEnvironmentsNamesByBranch($branch)
{
@@ -245,7 +257,7 @@ public function getEnvironmentsNamesByBranch($branch)
$defaultBranch = ($branch === $this->getDefaultBranch());
foreach ($environments['items'] as $environment) {
/** @var Environment $environment */
- if ($defaultBranch || in_array($branch, $environment->getBranches(), true)) {
+ if ($defaultBranch || \in_array($branch, $environment->getBranches(), true)) {
$environmentsIds[] = $environment->getId();
}
}
@@ -264,7 +276,7 @@ public function getBranchesByEnvironment($environmentId)
$environments = $this->getEnvironmentsObjects();
foreach ($environments['items'] as $environment) {
/** @var Environment $environment */
- if ($environmentId == $environment->getId()) {
+ if ($environmentId === $environment->getId()) {
return $environment->getBranches();
}
}
diff --git a/src/Model/ProjectGroup.php b/src/Model/ProjectGroup.php
index 14b6cf707..35885d9b8 100644
--- a/src/Model/ProjectGroup.php
+++ b/src/Model/ProjectGroup.php
@@ -1,11 +1,18 @@
+ */
class ProjectGroup extends BaseProjectGroup
{
/**
@@ -14,7 +21,7 @@ class ProjectGroup extends BaseProjectGroup
public function getGroupProjects()
{
/** @var ProjectStore $projectStore */
- $projectStore = Factory::getStore('Project');
+ $projectStore = $this->storeRegistry->get('Project');
return $projectStore->getByGroupId($this->getId(), false);
}
diff --git a/src/Model/Secret.php b/src/Model/Secret.php
new file mode 100644
index 000000000..e0e241d46
--- /dev/null
+++ b/src/Model/Secret.php
@@ -0,0 +1,18 @@
+
+ */
+class Secret extends BaseSecret
+{
+ public const SECRET_NAME_PATTERN = '^[-_\w\d]+$';
+}
diff --git a/src/Model/User.php b/src/Model/User.php
index ddeaef3a7..ee091953b 100644
--- a/src/Model/User.php
+++ b/src/Model/User.php
@@ -1,25 +1,28 @@
+ * @author Dmitry Khomutov
*/
class User extends BaseUser
{
- /**
- * @return int
- */
- public function getFinalPerPage()
+ public function getFinalPerPage(ConfigurationInterface $configuration): ?int
{
$perPage = $this->getPerPage();
if ($perPage) {
return $perPage;
}
- return (int)Config::getInstance()->get('php-censor.per_page', 10);
+ return (int)$configuration->get('php-censor.per_page', 10);
}
}
diff --git a/src/Model/WebhookRequest.php b/src/Model/WebhookRequest.php
new file mode 100644
index 000000000..2a5dae163
--- /dev/null
+++ b/src/Model/WebhookRequest.php
@@ -0,0 +1,17 @@
+
+ */
+class WebhookRequest extends BaseWebhookRequest
+{
+}
diff --git a/src/Plugin.php b/src/Plugin.php
index 202abcc02..adc7f278f 100644
--- a/src/Plugin.php
+++ b/src/Plugin.php
@@ -4,10 +4,13 @@
use Exception;
use PHPCensor\Model\Build;
-use PHPCensor\Plugin\Codeception;
/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
abstract class Plugin
{
@@ -73,6 +76,8 @@ abstract class Plugin
*/
protected $binaryName = [];
+ protected ?StoreRegistry $storeRegistry = null;
+
public function __construct(Builder $builder, Build $build, array $options = [])
{
$this->builder = $builder;
@@ -85,21 +90,21 @@ public function __construct(Builder $builder, Build $build, array $options = [])
// Plugin option overwrite builder options for priority_path and binary_path
if (!empty($options['priority_path']) &&
- in_array($options['priority_path'], self::AVAILABLE_PRIORITY_PATHS, true)) {
+ \in_array($options['priority_path'], self::AVAILABLE_PRIORITY_PATHS, true)) {
$this->priorityPath = $options['priority_path'];
} else {
$this->priorityPath = $this->builder->priorityPath;
}
if (!empty($options['binary_name'])) {
- if (is_array($options['binary_name'])) {
+ if (\is_array($options['binary_name'])) {
$this->binaryName = $options['binary_name'];
} else {
$this->binaryName = [(string)$options['binary_name']];
}
}
- $this->builder->logDebug('Plugin options: ' . json_encode($options));
+ $this->builder->logDebug('Plugin options: ' . \json_encode($options));
}
/**
@@ -109,21 +114,21 @@ public function __construct(Builder $builder, Build $build, array $options = [])
*/
protected function normalizePath($rawPath)
{
- $normalizedPath = $this->builder->interpolate($rawPath);
+ $normalizedPath = $this->builder->interpolate($rawPath, true);
- if ('/' !== substr($rawPath, 0, 1)) {
+ if ('/' !== \substr($rawPath, 0, 1)) {
$normalizedPath = $this->build->getBuildPath() . $normalizedPath;
}
- $realPath = realpath($normalizedPath);
+ $realPath = \realpath($normalizedPath);
return (false !== $realPath)
- ? rtrim($realPath, '/\\') . '/'
- : rtrim(
- str_replace(
+ ? \rtrim($realPath, '/\\') . '/'
+ : \rtrim(
+ \str_replace(
'//',
'/',
- str_replace('/./', '/', $normalizedPath)
+ \str_replace('/./', '/', $normalizedPath)
),
'/\\'
) . '/';
@@ -136,9 +141,9 @@ protected function normalizeBinaryPath()
{
$binaryPath = '';
if (!empty($this->options['binary_path'])) {
- $optionBinaryPath = $this->builder->interpolate($this->options['binary_path']);
+ $optionBinaryPath = $this->builder->interpolate($this->options['binary_path'], true);
- if ('/' !== substr($optionBinaryPath, 0, 1)) {
+ if ('/' !== \substr($optionBinaryPath, 0, 1)) {
$binaryPath = $this->build->getBuildPath();
}
@@ -147,15 +152,15 @@ protected function normalizeBinaryPath()
$binaryPath = $this->builder->binaryPath;
}
- $realPath = realpath($binaryPath);
+ $realPath = \realpath($binaryPath);
return (false !== $realPath)
- ? rtrim($realPath, '/\\') . '/'
- : rtrim(
- str_replace(
+ ? \rtrim($realPath, '/\\') . '/'
+ : \rtrim(
+ \str_replace(
'//',
'/',
- str_replace('/./', '/', $binaryPath)
+ \str_replace('/./', '/', $binaryPath)
),
'/\\'
) . '/';
@@ -166,15 +171,15 @@ protected function normalizeBinaryPath()
*/
protected function normalizeDirectory()
{
- if (!empty($this->options['directory']) && is_array($this->options['directory'])) {
+ if (!empty($this->options['directory']) && \is_array($this->options['directory'])) {
return $this->builder->directory;
}
$directory = '';
if (!empty($this->options['directory'])) {
- $optionDirectory = $this->builder->interpolate($this->options['directory']);
+ $optionDirectory = $this->builder->interpolate($this->options['directory'], true);
- if ('/' !== substr($optionDirectory, 0, 1)) {
+ if ('/' !== \substr($optionDirectory, 0, 1)) {
$directory = $this->build->getBuildPath();
}
@@ -183,15 +188,15 @@ protected function normalizeDirectory()
$directory = $this->builder->directory;
}
- $realPath = realpath($directory);
+ $realPath = \realpath($directory);
$finalDirectory = (false !== $realPath)
- ? rtrim($realPath, '/\\') . '/'
- : rtrim(
- str_replace(
+ ? \rtrim($realPath, '/\\') . '/'
+ : \rtrim(
+ \str_replace(
'//',
'/',
- str_replace('/./', '/', $directory)
+ \str_replace('/./', '/', $directory)
),
'/\\'
) . '/';
@@ -209,37 +214,37 @@ protected function normalizeIgnore()
$ignore = $this->builder->ignore;
if (!empty($this->options['ignore'])) {
- $ignore = array_merge($ignore, $this->options['ignore']);
+ $ignore = \array_merge($ignore, $this->options['ignore']);
}
$baseDirectory = $this->builder->buildPath;
- array_walk($ignore, function (&$value) use ($baseDirectory) {
- $value = $this->builder->interpolate($value);
+ \array_walk($ignore, function (&$value) use ($baseDirectory) {
+ $value = $this->builder->interpolate($value, true);
- if ('/' !== substr($value, 0, 1)) {
+ if ('/' !== \substr($value, 0, 1)) {
$value = $baseDirectory . $value;
}
- clearstatcache(true);
- $realPath = realpath($value);
+ \clearstatcache(true);
+ $realPath = \realpath($value);
$value = (false !== $realPath)
? $realPath
: $value;
- $value = str_replace("/./", '/', $value);
- $value = rtrim(
- str_replace(
+ $value = \str_replace("/./", '/', $value);
+ $value = \rtrim(
+ \str_replace(
'//',
'/',
- str_replace($baseDirectory, '', $value)
+ \str_replace($baseDirectory, '', $value)
),
'/\\'
);
});
- return array_unique($ignore);
+ return \array_unique($ignore);
}
/**
@@ -292,4 +297,9 @@ public static function pluginName()
{
return '';
}
+
+ public function setStoreRegistry(StoreRegistry $storeRegistry)
+ {
+ $this->storeRegistry = $storeRegistry;
+ }
}
diff --git a/src/Plugin/Atoum.php b/src/Plugin/Atoum.php
index 3a516f211..571ea265d 100644
--- a/src/Plugin/Atoum.php
+++ b/src/Plugin/Atoum.php
@@ -8,6 +8,11 @@
/**
* Atoum plugin, runs Atoum tests within a project.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Atoum extends Plugin
{
diff --git a/src/Plugin/Behat.php b/src/Plugin/Behat.php
index e8e21573c..bfff90a48 100644
--- a/src/Plugin/Behat.php
+++ b/src/Plugin/Behat.php
@@ -10,14 +10,18 @@
/**
* Behat BDD Plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class Behat extends Plugin
{
/**
* @var string
*/
- protected $features;
+ protected $features = '';
/**
* @return string
@@ -36,8 +40,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->executable = $this->findBinary(['behat', 'behat.phar']);
- $this->features = '';
-
if (!empty($options['features'])) {
$this->features = $options['features'];
}
@@ -49,7 +51,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
public function execute()
{
if (!$this->executable) {
- $this->builder->logFailure(sprintf('Could not find %s', 'behat'));
+ $this->builder->logFailure(\sprintf('Could not find %s', 'behat'));
return false;
}
@@ -73,30 +75,31 @@ public function parseBehatOutput()
{
$output = $this->builder->getLastOutput();
- $parts = explode('---', $output);
+ $parts = \explode('---', $output);
- if (count($parts) <= 1) {
+ if (\count($parts) <= 1) {
return [0, []];
}
- $lines = explode(PHP_EOL, $parts[1]);
+ $lines = \explode(PHP_EOL, $parts[1]);
$storeFailures = false;
$data = [];
foreach ($lines as $line) {
- $line = trim($line);
- if ('Failed scenarios:' == $line) {
+ $line = \trim($line);
+ if ('Failed scenarios:' === $line) {
$storeFailures = true;
+
continue;
}
- if (strpos($line, ':') === false) {
+ if (\strpos($line, ':') === false) {
$storeFailures = false;
}
if ($storeFailures) {
- $lineParts = explode(':', $line);
+ $lineParts = \explode(':', $line);
$data[] = [
'file' => $lineParts[0],
'line' => $lineParts[1],
@@ -108,12 +111,12 @@ public function parseBehatOutput()
'Behat scenario failed.',
BuildError::SEVERITY_HIGH,
$lineParts[0],
- $lineParts[1]
+ (int)$lineParts[1]
);
}
}
- $errorCount = count($data);
+ $errorCount = \count($data);
return [$errorCount, $data];
}
diff --git a/src/Plugin/BitbucketNotify.php b/src/Plugin/BitbucketNotify.php
index f962b7da1..862d53c64 100644
--- a/src/Plugin/BitbucketNotify.php
+++ b/src/Plugin/BitbucketNotify.php
@@ -5,15 +5,20 @@
use Exception;
use GuzzleHttp\Client;
use PHPCensor\Builder;
-use PHPCensor\Database;
+use PHPCensor\Common\Exception\InvalidArgumentException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
use PHPCensor\Plugin\Util\BitbucketNotifyPluginResult;
use PHPCensor\Store\BuildErrorStore;
use PHPCensor\Store\BuildMetaStore;
use PHPCensor\Store\BuildStore;
-use PHPCensor\Store\Factory;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class BitbucketNotify extends Plugin
{
/** @var string */
@@ -45,11 +50,6 @@ class BitbucketNotify extends Plugin
*/
protected $httpClient;
- /**
- * @var Database
- */
- protected $pdo;
-
/**
* @return string
*/
@@ -67,8 +67,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->pdo = Database::getConnection('read');
-
$this->httpClient = new Client();
$this->url = \trim($options['url']);
$this->message = isset($options['message']) ? $options['message'] : '';
@@ -79,7 +77,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->updateBuild = $options['update_build'];
if (\array_key_exists('auth_token', $options)) {
- $this->authToken = $options['auth_token'];
+ $this->authToken = $this->builder->interpolate($options['auth_token'], true);
}
if (empty($this->message)) {
@@ -103,8 +101,8 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$chart = APP_URL . 'artifacts/pdepend/' . $buildDirectory . '/chart.svg';
$pyramid = APP_URL . 'artifacts/pdepend/' . $buildDirectory . '/pyramid.svg';
- $this->message .= sprintf('', $chart);
- $this->message .= sprintf('', $pyramid) . PHP_EOL;
+ $this->message .= \sprintf('', $chart);
+ $this->message .= \sprintf('', $pyramid) . PHP_EOL;
$this->message .= $summary . PHP_EOL;
}
}
@@ -115,7 +113,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
empty($this->projectKey) ||
empty($this->repositorySlug)
) {
- throw new Exception('Please define the url for bitbucket plugin!');
+ throw new InvalidArgumentException('Please define the url for bitbucket plugin!');
}
}
@@ -158,9 +156,9 @@ public function execute()
*/
protected function findPullRequestsByBranch()
{
- $endpoint = sprintf('/projects/%s/repos/%s/pull-requests', $this->projectKey, $this->repositorySlug);
+ $endpoint = \sprintf('/projects/%s/repos/%s/pull-requests', $this->projectKey, $this->repositorySlug);
$response = $this->apiRequest($endpoint)->getBody();
- $response = json_decode($response, true);
+ $response = \json_decode($response, true);
foreach ($response['values'] as $pullRequest) {
if ($pullRequest['fromRef']['displayId'] === $this->getBuild()->getBranch()) {
@@ -173,7 +171,7 @@ protected function findPullRequestsByBranch()
protected function getTargetBranchForPullRequest($pullRequestId)
{
- $endpoint = sprintf(
+ $endpoint = \sprintf(
'/projects/%s/repos/%s/pull-requests/%d',
$this->projectKey,
$this->repositorySlug,
@@ -181,7 +179,7 @@ protected function getTargetBranchForPullRequest($pullRequestId)
);
$response = $this->apiRequest($endpoint)->getBody();
- $response = json_decode($response, true);
+ $response = \json_decode($response, true);
return $response['toRef']['displayId'];
}
@@ -193,7 +191,7 @@ protected function getTargetBranchForPullRequest($pullRequestId)
*/
protected function createCommentInPullRequest($pullRequestId, $message)
{
- $endpoint = sprintf(
+ $endpoint = \sprintf(
'/projects/%s/repos/%s/pull-requests/%s/comments',
$this->projectKey,
$this->repositorySlug,
@@ -201,7 +199,7 @@ protected function createCommentInPullRequest($pullRequestId, $message)
);
$response = $this->apiRequest($endpoint, 'post', ['text' => $message])->getBody();
- $response = json_decode($response, true);
+ $response = \json_decode($response, true);
return (int)$response['id'];
}
@@ -224,7 +222,7 @@ protected function createTaskForCommentInPullRequest($commentId, $message)
protected function updateBuild()
{
- $endpoint = sprintf(
+ $endpoint = \sprintf(
'/commits/%s',
$this->getBuild()->getCommitId()
);
@@ -232,9 +230,11 @@ protected function updateBuild()
switch ($this->getBuild()->getStatus()) {
case Build::STATUS_SUCCESS:
$state = 'SUCCESSFUL';
+
break;
case Build::STATUS_FAILED:
$state = 'FAILED';
+
break;
default:
$state = 'INPROGRESS';
@@ -257,7 +257,7 @@ protected function updateBuild()
protected function prepareResult($targetBranch)
{
/** @var BuildErrorStore $buildErrorStore */
- $buildErrorStore = Factory::getStore('BuildError');
+ $buildErrorStore = $this->storeRegistry->get('BuildError');
$targetBranchBuildStats = $buildErrorStore->getErrorAmountPerPluginForBuild(
$this->findLatestBuild($targetBranch)
@@ -269,8 +269,8 @@ protected function prepareResult($targetBranch)
return [];
}
- $plugins = array_unique(array_merge(array_keys($targetBranchBuildStats), array_keys($currentBranchBuildStats)));
- sort($plugins);
+ $plugins = \array_unique([...\array_keys($targetBranchBuildStats), ...\array_keys($currentBranchBuildStats)]);
+ \sort($plugins);
$result = [];
foreach ($plugins as $plugin) {
@@ -294,9 +294,8 @@ protected function prepareResult($targetBranch)
public function getPhpUnitCoverage($targetBranch)
{
/** @var BuildMetaStore $buildMetaStore */
- $buildMetaStore = Factory::getStore('BuildMeta');
- $latestTargeBuildId = $this->findLatestBuild($targetBranch);
- $latestCurrentBuildId = $this->findLatestBuild($this->build->getBranch());
+ $buildMetaStore = $this->storeRegistry->get('BuildMeta');
+ $latestTargetBuildId = $this->findLatestBuild($targetBranch);
$targetMetaData = $buildMetaStore->getByKey(
$this->findLatestBuild($targetBranch),
@@ -308,13 +307,13 @@ public function getPhpUnitCoverage($targetBranch)
);
$targetBranchCoverage = [];
- if (!is_null($latestTargeBuildId) && !is_null($targetMetaData)) {
- $targetBranchCoverage = json_decode($targetMetaData->getMetaValue(), true);
+ if (!\is_null($latestTargetBuildId) && !\is_null($targetMetaData)) {
+ $targetBranchCoverage = \json_decode($targetMetaData->getMetaValue(), true);
}
$currentBranchCoverage = [];
- if (!is_null($currentMetaData)) {
- $currentBranchCoverage = json_decode($currentMetaData->getMetaValue(), true);
+ if (!\is_null($currentMetaData)) {
+ $currentBranchCoverage = \json_decode($currentMetaData->getMetaValue(), true);
}
return new Plugin\Util\BitbucketNotifyPhpUnitResult(
@@ -332,7 +331,7 @@ protected function buildResultComparator(array $plugins)
{
$maxPluginNameLength = 20;
if (!empty($plugins)) {
- $maxPluginNameLength = max(array_map('strlen', $plugins));
+ $maxPluginNameLength = \max(\array_map('strlen', $plugins));
}
$lines = [];
@@ -345,12 +344,12 @@ protected function buildResultComparator(array $plugins)
protected function reportGenerator(array $stats)
{
- $statsString = trim(implode(PHP_EOL, $stats));
+ $statsString = \trim(\implode(PHP_EOL, $stats));
if (empty($stats)) {
$statsString = 'no changes between your branch and target branch';
}
- $message = str_replace(['%STATS%'], [$statsString], $this->message);
+ $message = \str_replace(['%STATS%'], [$statsString], $this->message);
return $this->builder->interpolate($message);
}
@@ -362,7 +361,7 @@ protected function reportGenerator(array $stats)
protected function findLatestBuild($branchName)
{
/** @var BuildStore $buildStore */
- $buildStore = Factory::getStore('Build');
+ $buildStore = $this->storeRegistry->get('Build');
$build = $buildStore->getLatestBuildByProjectAndBranch($this->getBuild()->getProjectId(), $branchName);
diff --git a/src/Plugin/CampfireNotify.php b/src/Plugin/CampfireNotify.php
index 32b7bfa09..60d5b4503 100644
--- a/src/Plugin/CampfireNotify.php
+++ b/src/Plugin/CampfireNotify.php
@@ -2,22 +2,26 @@
namespace PHPCensor\Plugin;
-use Exception;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\InvalidArgumentException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
/**
* Campfire Plugin - Allows Campfire API actions. Strongly based on icecube (http://labs.mimmin.com/icecube)
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author André Cianfarani
+ * @author Dmitry Khomutov
*/
class CampfireNotify extends Plugin
{
protected $url;
protected $authToken;
protected $userAgent;
- protected $cookie;
+ protected $cookie = 'php-censor-cookie';
protected $verbose = false;
protected $room;
protected $message;
@@ -40,7 +44,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->message = $options['message'];
$version = $this->builder->interpolate('%SYSTEM_VERSION%');
$this->userAgent = 'PHP Censor/' . $version;
- $this->cookie = "php-censor-cookie";
if (isset($options['verbose']) && $options['verbose']) {
$this->verbose = true;
@@ -53,14 +56,14 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->url = $campfire['url'];
if (\array_key_exists('auth_token', $campfire)) {
- $this->authToken = $campfire['auth_token'];
+ $this->authToken = $this->builder->interpolate($campfire['auth_token'], true);
}
if (\array_key_exists('room', $campfire)) {
$this->room = $campfire['room'];
}
} else {
- throw new Exception('No connection parameters given for Campfire plugin');
+ throw new InvalidArgumentException('No connection parameters given for Campfire plugin');
}
}
diff --git a/src/Plugin/CleanBuild.php b/src/Plugin/CleanBuild.php
index 8f6e4390d..738bb0cc4 100644
--- a/src/Plugin/CleanBuild.php
+++ b/src/Plugin/CleanBuild.php
@@ -10,7 +10,11 @@
* Clean build removes Composer related files and allows users to clean up their build directory.
* Useful as a precursor to copy_build.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class CleanBuild extends Plugin
{
@@ -31,7 +35,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->removeFiles = isset($options['remove']) && is_array($options['remove']) ? $options['remove'] : [];
+ $this->removeFiles = isset($options['remove']) && \is_array($options['remove']) ? $options['remove'] : [];
}
/**
diff --git a/src/Plugin/Codeception.php b/src/Plugin/Codeception.php
index 625897b91..8af65569e 100644
--- a/src/Plugin/Codeception.php
+++ b/src/Plugin/Codeception.php
@@ -4,6 +4,7 @@
use Exception;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\InvalidArgumentException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
use PHPCensor\Plugin\Util\TestResultParsers\Codeception as Parser;
@@ -13,9 +14,13 @@
/**
* Codeception Plugin - Enables full acceptance, unit, and functional testing.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Don Gilbert
* @author Igor Timoshenko
* @author Adam Cooper
+ * @author Dmitry Khomutov
*/
class Codeception extends Plugin implements ZeroConfigPluginInterface
{
@@ -65,7 +70,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
}
if (isset($options['output_path'])) {
- array_unshift($this->outputPath, $options['output_path']);
+ \array_unshift($this->outputPath, $options['output_path']);
}
$this->executable = $this->findBinary(['codecept', 'codecept.phar']);
@@ -76,7 +81,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
*/
public static function canExecuteOnStage($stage, Build $build)
{
- return (Build::STAGE_TEST === $stage && !is_null(self::findConfigFile($build->getBuildPath())));
+ return (Build::STAGE_TEST === $stage && !\is_null(self::findConfigFile($build->getBuildPath())));
}
/**
@@ -87,11 +92,11 @@ public static function canExecuteOnStage($stage, Build $build)
*/
public static function findConfigFile($buildPath)
{
- if (file_exists($buildPath . 'codeception.yml')) {
+ if (\file_exists($buildPath . 'codeception.yml')) {
return $buildPath . 'codeception.yml';
}
- if (file_exists($buildPath . 'codeception.dist.yml')) {
+ if (\file_exists($buildPath . 'codeception.dist.yml')) {
return $buildPath . 'codeception.dist.yml';
}
@@ -104,7 +109,7 @@ public static function findConfigFile($buildPath)
public function execute()
{
if (empty($this->ymlConfigFile)) {
- throw new Exception("No configuration file found");
+ throw new InvalidArgumentException("No configuration file found");
}
// Run any config files first. This can be either a single value or an array.
@@ -122,7 +127,7 @@ protected function runConfigFile()
$codeception = $this->executable;
if (!$codeception) {
- $this->builder->logFailure(sprintf('Could not find "%s" binary', 'codecept'));
+ $this->builder->logFailure(\sprintf('Could not find "%s" binary', 'codecept'));
return false;
}
@@ -135,24 +140,24 @@ protected function runConfigFile()
}
$parser = new YamlParser();
- $yaml = file_get_contents($this->ymlConfigFile);
+ $yaml = \file_get_contents($this->ymlConfigFile);
$config = (array)$parser->parse($yaml);
$trueReportXmlPath = null;
if ($config && isset($config['paths']['log'])) {
- $trueReportXmlPath = rtrim($config['paths']['log'], '/\\') . '/';
+ $trueReportXmlPath = \rtrim($config['paths']['log'], '/\\') . '/';
}
- if (!file_exists($trueReportXmlPath . 'report.xml')) {
+ if (!\file_exists($trueReportXmlPath . 'report.xml')) {
foreach ($this->outputPath as $outputPath) {
- $trueReportXmlPath = rtrim($outputPath, '/\\') . '/';
- if (file_exists($trueReportXmlPath . 'report.xml')) {
+ $trueReportXmlPath = \rtrim($outputPath, '/\\') . '/';
+ if (\file_exists($trueReportXmlPath . 'report.xml')) {
break;
}
}
}
- if (!file_exists($trueReportXmlPath . 'report.xml')) {
+ if (!\file_exists($trueReportXmlPath . 'report.xml')) {
$this->builder->logFailure('"report.xml" file can not be found in configured "output_path!"');
return false;
@@ -169,7 +174,7 @@ protected function runConfigFile()
// NOTE: Codeception does not use stderr, so failure can only be detected
// through tests
- $success = $success && (intval($meta['failures']) < 1);
+ $success = $success && (\intval($meta['failures']) < 1);
$this->build->storeMeta((self::pluginName() . '-meta'), $meta);
$this->build->storeMeta((self::pluginName() . '-data'), $output);
diff --git a/src/Plugin/Composer.php b/src/Plugin/Composer.php
index fb91ae454..97852eceb 100644
--- a/src/Plugin/Composer.php
+++ b/src/Plugin/Composer.php
@@ -11,15 +11,19 @@
/**
* Composer Plugin - Provides access to Composer functionality.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class Composer extends Plugin implements ZeroConfigPluginInterface
{
- protected $action;
- protected $preferDist;
- protected $noDev;
- protected $ignorePlatformReqs;
- protected $preferSource;
+ protected $action = 'install';
+ protected $preferDist = false;
+ protected $noDev = false;
+ protected $ignorePlatformReqs = false;
+ protected $preferSource = false;
/**
* @return string
@@ -36,32 +40,26 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->action = 'install';
- $this->preferDist = false;
- $this->preferSource = false;
- $this->noDev = false;
- $this->ignorePlatformReqs = false;
-
$this->executable = $this->findBinary(['composer', 'composer.phar']);
- if (array_key_exists('action', $options)) {
+ if (\array_key_exists('action', $options)) {
$this->action = $options['action'];
}
- if (array_key_exists('prefer_dist', $options)) {
+ if (\array_key_exists('prefer_dist', $options)) {
$this->preferDist = (bool)$options['prefer_dist'];
}
- if (array_key_exists('prefer_source', $options)) {
+ if (\array_key_exists('prefer_source', $options)) {
$this->preferDist = false;
$this->preferSource = (bool)$options['prefer_source'];
}
- if (array_key_exists('no_dev', $options)) {
+ if (\array_key_exists('no_dev', $options)) {
$this->noDev = (bool)$options['no_dev'];
}
- if (array_key_exists('ignore_platform_reqs', $options)) {
+ if (\array_key_exists('ignore_platform_reqs', $options)) {
$this->ignorePlatformReqs = (bool)$options['ignore_platform_reqs'];
}
}
@@ -73,7 +71,7 @@ public static function canExecuteOnStage($stage, Build $build)
{
$path = $build->getBuildPath() . '/composer.json';
- if (file_exists($path) && Build::STAGE_SETUP == $stage) {
+ if (\file_exists($path) && Build::STAGE_SETUP === $stage) {
return true;
}
diff --git a/src/Plugin/CopyBuild.php b/src/Plugin/CopyBuild.php
index a319bdb53..4cedb2bc0 100644
--- a/src/Plugin/CopyBuild.php
+++ b/src/Plugin/CopyBuild.php
@@ -3,14 +3,18 @@
namespace PHPCensor\Plugin;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
-use RuntimeException;
/**
* Copy Build Plugin - Copies the entire build to another directory.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class CopyBuild extends Plugin
{
@@ -52,9 +56,9 @@ public function execute()
$this->wipeExistingDirectory();
- if (is_dir($this->directory)) {
+ if (\is_dir($this->directory)) {
throw new RuntimeException(
- sprintf(
+ \sprintf(
'Directory "%s" already exists! Use "wipe" option if you want to delete directory before copy.',
$this->directory
)
@@ -62,7 +66,7 @@ public function execute()
}
$cmd = 'cd "%s" && mkdir -p "%s" && cp -R %s/. "%s"';
- $success = $this->builder->executeCommand($cmd, $buildPath, $this->directory, rtrim($buildPath, '/'), $this->directory);
+ $success = $this->builder->executeCommand($cmd, $buildPath, $this->directory, \rtrim($buildPath, '/'), $this->directory);
$this->deleteIgnoredFiles();
@@ -76,17 +80,17 @@ public function execute()
*/
protected function wipeExistingDirectory()
{
- if ($this->wipe === true && $this->directory !== '/' && is_dir($this->directory)) {
+ if ($this->wipe === true && $this->directory !== '/' && \is_dir($this->directory)) {
$cmd = 'cd "%s" && rm -Rf "%s"';
$success = $this->builder->executeCommand($cmd, $this->builder->buildPath, $this->directory);
if (!$success) {
throw new RuntimeException(
- sprintf('Failed to wipe existing directory "%s" before copy!', $this->directory)
+ \sprintf('Failed to wipe existing directory "%s" before copy!', $this->directory)
);
}
- clearstatcache();
+ \clearstatcache();
}
}
diff --git a/src/Plugin/Deployer.php b/src/Plugin/Deployer.php
index 0183bccbc..742ad89fa 100644
--- a/src/Plugin/Deployer.php
+++ b/src/Plugin/Deployer.php
@@ -10,12 +10,16 @@
/**
* Integration with Deployer: https://github.com/rebelinblue/deployer
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class Deployer extends Plugin
{
protected $webhookUrl;
- protected $reason;
+ protected $reason = 'PHP Censor Build #%BUILD_ID% - %COMMIT_MESSAGE%';
protected $updateOnly;
/**
@@ -33,7 +37,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->reason = 'PHP Censor Build #%BUILD_ID% - %COMMIT_MESSAGE%';
if (isset($options['webhook_url'])) {
$this->webhookUrl = $options['webhook_url'];
}
@@ -61,11 +64,11 @@ public function execute()
$this->webhookUrl,
[
'form_params' => [
- 'reason' => $this->builder->interpolate($this->reason),
+ 'reason' => $this->builder->interpolate($this->reason, true),
'source' => 'PHP Censor',
- 'url' => $this->builder->interpolate('%BUILD_LINK%'),
- 'branch' => $this->builder->interpolate('%BRANCH%'),
- 'commit' => $this->builder->interpolate('%COMMIT_ID%'),
+ 'url' => $this->builder->interpolate('%BUILD_LINK%', true),
+ 'branch' => $this->builder->interpolate('%BRANCH%', true),
+ 'commit' => $this->builder->interpolate('%COMMIT_ID%', true),
'update_only' => $this->updateOnly,
]
]
diff --git a/src/Plugin/DeployerOrg.php b/src/Plugin/DeployerOrg.php
index 1c7fbdbc6..c8e3b4b94 100644
--- a/src/Plugin/DeployerOrg.php
+++ b/src/Plugin/DeployerOrg.php
@@ -9,7 +9,11 @@
/**
* Deployer plugin for PHPCensor: http://deployer.org
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Alexey Boyko
+ * @author Dmitry Khomutov
*/
class DeployerOrg extends Plugin
{
@@ -105,7 +109,7 @@ protected function getVerbosityOption($verbosity)
'quiet' => 'q'
];
- $verbosity = strtolower(trim($verbosity));
+ $verbosity = \strtolower(\trim($verbosity));
if ($verbosity !== 'normal') {
return '-' . $logLevelList[$verbosity];
} else {
@@ -141,6 +145,6 @@ protected function getOptions($config)
$options[] = '--file=' . $config['file'];
}
- return implode(' ', $options);
+ return \implode(' ', $options);
}
}
diff --git a/src/Plugin/EmailNotify.php b/src/Plugin/EmailNotify.php
index c735367e3..ee8549780 100644
--- a/src/Plugin/EmailNotify.php
+++ b/src/Plugin/EmailNotify.php
@@ -2,18 +2,21 @@
namespace PHPCensor\Plugin;
-use PHPCensor\Config;
use PHPCensor\Exception\HttpException;
use PHPCensor\Helper\Email as EmailHelper;
use PHPCensor\Plugin;
use PHPCensor\View;
use Psr\Log\LogLevel;
-use RuntimeException;
+use PHPCensor\Common\Exception\RuntimeException;
/**
* Email Plugin - Provides simple email capability.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Steve Brazier
+ * @author Dmitry Khomutov
*/
class EmailNotify extends Plugin
{
@@ -38,7 +41,7 @@ public function execute()
// Without some email addresses in the yml file then we
// can't do anything.
- if (count($addresses) == 0) {
+ if (\count($addresses) === 0) {
return false;
}
@@ -49,7 +52,7 @@ public function execute()
$view = $this->getMailTemplate();
} catch (RuntimeException $e) {
$this->builder->log(
- sprintf('Unknown mail template "%s", falling back to default.', $this->options['template']),
+ \sprintf('Unknown mail template "%s", falling back to default.', $this->options['template']),
LogLevel::WARNING
);
$view = $this->getDefaultMailTemplate();
@@ -66,13 +69,13 @@ public function execute()
$sendFailures = $this->sendSeparateEmails(
$addresses,
- sprintf("PHP Censor - %s - %s", $projectName, $buildStatus),
+ \sprintf("PHP Censor - %s - %s", $projectName, $buildStatus),
$body
);
// This is a success if we've not failed to send anything.
- $this->builder->log(sprintf('%d emails sent.', (count($addresses) - $sendFailures)));
- $this->builder->log(sprintf('%d emails failed to send.', $sendFailures));
+ $this->builder->log(\sprintf('%d emails sent.', (\count($addresses) - $sendFailures)));
+ $this->builder->log(\sprintf('%d emails failed to send.', $sendFailures));
return ($sendFailures === 0);
}
@@ -87,16 +90,16 @@ public function execute()
*/
protected function sendEmail($toAddress, $ccList, $subject, $body)
{
- $email = new EmailHelper(Config::getInstance());
+ $email = new EmailHelper($this->builder->getConfiguration());
- $email->setEmailTo($toAddress, $toAddress);
- $email->setSubject($subject);
- $email->setBody($body);
+ $email->setEmailTo($this->builder->interpolate($toAddress), $this->builder->interpolate($toAddress));
+ $email->setSubject($this->builder->interpolate($subject));
+ $email->setBody($this->builder->interpolate($body));
$email->setHtml(true);
- if (is_array($ccList) && count($ccList)) {
+ if (\is_array($ccList) && \count($ccList)) {
foreach ($ccList as $address) {
- $email->addCc($address, $address);
+ $email->addCc($this->builder->interpolate($address), $this->builder->interpolate($address));
}
}
@@ -138,8 +141,8 @@ protected function getEmailAddresses()
$addresses = [];
$committer = $this->build->getCommitterEmail();
- $this->builder->logDebug(sprintf("Committer email: '%s'", $committer));
- $this->builder->logDebug(sprintf(
+ $this->builder->logDebug(\sprintf("Committer email: '%s'", $committer));
+ $this->builder->logDebug(\sprintf(
"Committer option: '%s'",
(!empty($this->options['committer']) && $this->options['committer']) ? 'true' : 'false'
));
@@ -150,18 +153,18 @@ protected function getEmailAddresses()
}
}
- $this->builder->logDebug(sprintf(
+ $this->builder->logDebug(\sprintf(
"Addresses option: '%s'",
- (!empty($this->options['addresses']) && is_array($this->options['addresses'])) ? implode(', ', $this->options['addresses']) : 'false'
+ (!empty($this->options['addresses']) && \is_array($this->options['addresses'])) ? \implode(', ', $this->options['addresses']) : 'false'
));
- if (!empty($this->options['addresses']) && is_array($this->options['addresses'])) {
+ if (!empty($this->options['addresses']) && \is_array($this->options['addresses'])) {
foreach ($this->options['addresses'] as $address) {
$addresses[] = $address;
}
}
- $this->builder->logDebug(sprintf(
+ $this->builder->logDebug(\sprintf(
"Default mailTo option: '%s'",
!empty($this->options['default_mailto_address']) ? $this->options['default_mailto_address'] : 'false'
));
@@ -170,7 +173,7 @@ protected function getEmailAddresses()
$addresses[] = $this->options['default_mailto_address'];
}
- return array_unique($addresses);
+ return \array_unique($addresses);
}
/**
diff --git a/src/Plugin/Env.php b/src/Plugin/Env.php
index cbe547de3..934868044 100644
--- a/src/Plugin/Env.php
+++ b/src/Plugin/Env.php
@@ -7,7 +7,11 @@
/**
* Environment variable plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Steve Kamerman
+ * @author Dmitry Khomutov
*/
class Env extends Plugin
{
@@ -26,15 +30,17 @@ public function execute()
{
$success = true;
foreach ($this->options as $key => $value) {
- if (is_numeric($key)) {
+ if (\is_numeric($key)) {
// This allows the developer to specify env vars like " - FOO=bar" or " - FOO: bar"
- $envVar = is_array($value) ? key($value).'='.current($value) : $value;
+ $envVar = \is_array($value)
+ ? (\key($value) . '=' . \current($value))
+ : $value;
} else {
// This allows the standard syntax: "FOO: bar"
$envVar = "$key=$value";
}
- if (!putenv($this->builder->interpolate($envVar))) {
+ if (!\putenv($this->builder->interpolate($envVar, true))) {
$success = false;
$this->builder->logFailure('Unable to set environment variable');
}
diff --git a/src/Plugin/FlowdockNotify.php b/src/Plugin/FlowdockNotify.php
index 441dfb4e1..fb5e236a5 100644
--- a/src/Plugin/FlowdockNotify.php
+++ b/src/Plugin/FlowdockNotify.php
@@ -6,13 +6,19 @@
use FlowdockClient\Api\Push\Push;
use FlowdockClient\Api\Push\TeamInboxMessage;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\InvalidArgumentException;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
/**
* Flowdock Plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Petr Cervenka
+ * @author Dmitry Khomutov
*/
class FlowdockNotify extends Plugin
{
@@ -38,12 +44,12 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- if (!is_array($options) || (!isset($options['api_key']) && !isset($options['auth_token']))) {
- throw new Exception('Please define the "auth_token" for Flowdock Notify plugin!');
+ if (empty($options['auth_token'])) {
+ throw new InvalidArgumentException('Please define the "auth_token" for Flowdock Notify plugin!');
}
if (\array_key_exists('auth_token', $options)) {
- $this->authToken = $options['auth_token'];
+ $this->authToken = $this->builder->interpolate($options['auth_token'], true);
}
$this->message = isset($options['message']) ? $options['message'] : self::MESSAGE_DEFAULT;
@@ -70,7 +76,7 @@ public function execute()
->setContent($message);
if (!$push->sendTeamInboxMessage($flowMessage, ['connect_timeout' => 5000, 'timeout' => 5000])) {
- throw new Exception(sprintf('Flowdock Failed: %s', $flowMessage->getResponseErrors()));
+ throw new RuntimeException(\sprintf('Flowdock Failed: %s', $flowMessage->getResponseErrors()));
}
return true;
diff --git a/src/Plugin/Git.php b/src/Plugin/Git.php
index 35ed183b9..e7d63f3c2 100644
--- a/src/Plugin/Git.php
+++ b/src/Plugin/Git.php
@@ -9,7 +9,11 @@
/**
* Git plugin.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class Git extends Plugin
{
@@ -40,7 +44,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
public function execute()
{
// Check if there are any actions to be run for the branch we're running on:
- if (!array_key_exists($this->build->getBranch(), $this->actions)) {
+ if (!\array_key_exists($this->build->getBranch(), $this->actions)) {
return true;
}
@@ -48,6 +52,7 @@ public function execute()
foreach ($this->actions[$this->build->getBranch()] as $action => $options) {
if (!$this->runAction($action, $options)) {
$success = false;
+
break;
}
}
@@ -87,7 +92,7 @@ protected function runAction($action, array $options = [])
*/
protected function runMergeAction($options)
{
- if (array_key_exists('branch', $options)) {
+ if (\array_key_exists('branch', $options)) {
$cmd = 'cd "%s" && git checkout %s && git merge "%s"';
$path = $this->builder->buildPath;
@@ -101,15 +106,15 @@ protected function runMergeAction($options)
*/
protected function runTagAction($options)
{
- $tagName = date('Ymd-His');
- $message = sprintf('Tag created by PHP Censor: %s', date('Y-m-d H:i:s'));
+ $tagName = \date('Ymd-His');
+ $message = \sprintf('Tag created by PHP Censor: %s', \date('Y-m-d H:i:s'));
- if (array_key_exists('name', $options)) {
- $tagName = $this->builder->interpolate($options['name']);
+ if (\array_key_exists('name', $options)) {
+ $tagName = $this->builder->interpolate($options['name'], true);
}
- if (array_key_exists('message', $options)) {
- $message = $this->builder->interpolate($options['message']);
+ if (\array_key_exists('message', $options)) {
+ $message = $this->builder->interpolate($options['message'], true);
}
$cmd = 'git tag %s -m "%s"';
@@ -126,12 +131,12 @@ protected function runPullAction($options)
$branch = $this->build->getBranch();
$remote = 'origin';
- if (array_key_exists('branch', $options)) {
- $branch = $this->builder->interpolate($options['branch']);
+ if (\array_key_exists('branch', $options)) {
+ $branch = $this->builder->interpolate($options['branch'], true);
}
- if (array_key_exists('remote', $options)) {
- $remote = $this->builder->interpolate($options['remote']);
+ if (\array_key_exists('remote', $options)) {
+ $remote = $this->builder->interpolate($options['remote'], true);
}
return $this->builder->executeCommand('git pull %s %s', $remote, $branch);
@@ -146,12 +151,12 @@ protected function runPushAction($options)
$branch = $this->build->getBranch();
$remote = 'origin';
- if (array_key_exists('branch', $options)) {
- $branch = $this->builder->interpolate($options['branch']);
+ if (\array_key_exists('branch', $options)) {
+ $branch = $this->builder->interpolate($options['branch'], true);
}
- if (array_key_exists('remote', $options)) {
- $remote = $this->builder->interpolate($options['remote']);
+ if (\array_key_exists('remote', $options)) {
+ $remote = $this->builder->interpolate($options['remote'], true);
}
return $this->builder->executeCommand('git push %s %s', $remote, $branch);
diff --git a/src/Plugin/Grunt.php b/src/Plugin/Grunt.php
index 71dbe00c2..0d49bac7d 100644
--- a/src/Plugin/Grunt.php
+++ b/src/Plugin/Grunt.php
@@ -9,12 +9,16 @@
/**
* Grunt Plugin - Provides access to grunt functionality.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Tobias Tom
+ * @author Dmitry Khomutov
*/
class Grunt extends Plugin
{
- protected $task;
- protected $gruntfile;
+ protected $task = null;
+ protected $gruntfile = 'Gruntfile.js';
/**
* @return string
@@ -31,10 +35,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->task = null;
-
- $this->gruntfile = 'Gruntfile.js';
-
if (isset($options['task'])) {
$this->task = $options['task'];
}
diff --git a/src/Plugin/Gulp.php b/src/Plugin/Gulp.php
index cc3998f61..6aff9411a 100644
--- a/src/Plugin/Gulp.php
+++ b/src/Plugin/Gulp.php
@@ -9,12 +9,16 @@
/**
* Gulp Plugin - Provides access to gulp functionality.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dirk Heilig
+ * @author Dmitry Khomutov
*/
class Gulp extends Plugin
{
- protected $task;
- protected $gulpfile;
+ protected $task = null;
+ protected $gulpfile = 'gulpfile.js';
/**
* @return string
@@ -31,12 +35,8 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->task = null;
-
$this->executable = $this->findBinary('gulp');
- $this->gulpfile = 'gulpfile.js';
-
if (isset($options['task'])) {
$this->task = $options['task'];
}
diff --git a/src/Plugin/HipchatNotify.php b/src/Plugin/HipchatNotify.php
deleted file mode 100644
index f39b848d9..000000000
--- a/src/Plugin/HipchatNotify.php
+++ /dev/null
@@ -1,98 +0,0 @@
-
- */
-class HipchatNotify extends Plugin
-{
- protected $authToken;
- protected $color;
- protected $notify;
- protected $userAgent;
- protected $cookie;
- protected $message;
- protected $room;
-
- /**
- * @return string
- */
- public static function pluginName()
- {
- return 'hipchat_notify';
- }
-
- /**
- * {@inheritDoc}
- */
- public function __construct(Builder $builder, Build $build, array $options = [])
- {
- parent::__construct($builder, $build, $options);
-
- $version = $this->builder->interpolate('%SYSTEM_VERSION%');
- $this->userAgent = 'PHP Censor/' . $version;
- $this->cookie = "php-censor-cookie";
-
- if (!\is_array($options) || !isset($options['room']) || (!isset($options['authToken']) && !isset($options['auth_token']))) {
- throw new Exception('Please define room and authToken for hipchat_notify plugin.');
- }
-
- if (\array_key_exists('auth_token', $options)) {
- $this->authToken = $options['auth_token'];
- }
-
- $this->room = $options['room'];
-
- if (isset($options['message'])) {
- $this->message = $options['message'];
- } else {
- $this->message = '%PROJECT_TITLE% built at %BUILD_LINK%';
- }
-
- if (isset($options['color'])) {
- $this->color = $options['color'];
- } else {
- $this->color = 'yellow';
- }
-
- if (isset($options['notify'])) {
- $this->notify = $options['notify'];
- } else {
- $this->notify = false;
- }
- }
-
- /**
- * Run the HipChat plugin.
- * @return bool
- */
- public function execute()
- {
- $hipChat = new HipChat($this->authToken);
- $message = $this->builder->interpolate($this->message);
-
- $result = true;
- if (is_array($this->room)) {
- foreach ($this->room as $room) {
- if (!$hipChat->message_room($room, 'PHP Censor', $message, $this->notify, $this->color)) {
- $result = false;
- }
- }
- } else {
- if (!$hipChat->message_room($this->room, 'PHP Censor', $message, $this->notify, $this->color)) {
- $result = false;
- }
- }
-
- return $result;
- }
-}
diff --git a/src/Plugin/IrcNotify.php b/src/Plugin/IrcNotify.php
index 177ad5377..84971e602 100644
--- a/src/Plugin/IrcNotify.php
+++ b/src/Plugin/IrcNotify.php
@@ -9,7 +9,11 @@
/**
* IRC Plugin - Sends a notification to an IRC channel
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class IrcNotify extends Plugin
{
@@ -63,8 +67,8 @@ public function execute()
$this->port = 6667;
}
- $sock = fsockopen($this->server, $this->port);
- stream_set_timeout($sock, 1);
+ $sock = \fsockopen($this->server, $this->port);
+ \stream_set_timeout($sock, 1);
$connectCommands = [
'USER ' . $this->nick . ' 0 * :' . $this->nick,
@@ -74,7 +78,7 @@ public function execute()
$this->executeIrcCommand($sock, 'JOIN ' . $this->room);
$this->executeIrcCommand($sock, 'PRIVMSG ' . $this->room . ' :' . $msg);
- fclose($sock);
+ \fclose($sock);
return true;
}
@@ -87,22 +91,22 @@ public function execute()
private function executeIrcCommands($socket, array $commands)
{
foreach ($commands as $command) {
- fputs($socket, $command . "\n");
+ \fputs($socket, $command . "\n");
}
$pingBack = false;
// almost all servers expect pingback!
- while ($response = fgets($socket)) {
+ while ($response = \fgets($socket)) {
$matches = [];
- if (preg_match('/^PING \\:([A-Z0-9]+)/', $response, $matches)) {
+ if (\preg_match('/^PING \\:([A-Z0-9]+)/', $response, $matches)) {
$pingBack = $matches[1];
}
}
if ($pingBack) {
$command = 'PONG :' . $pingBack . "\n";
- fputs($socket, $command);
+ \fputs($socket, $command);
}
}
diff --git a/src/Plugin/Lint.php b/src/Plugin/Lint.php
index 7c1d7ae8d..9a7eb92bf 100644
--- a/src/Plugin/Lint.php
+++ b/src/Plugin/Lint.php
@@ -11,7 +11,11 @@
/**
* PHP Lint Plugin - Provides access to PHP lint functionality.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class Lint extends Plugin
{
@@ -37,20 +41,20 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->directory,
];
- if (!empty($options['directories']) && is_array($options['directories'])) {
+ if (!empty($options['directories']) && \is_array($options['directories'])) {
foreach ($options['directories'] as $index => $directory) {
- $relativePath = preg_replace(
+ $relativePath = \preg_replace(
'#^(\./|/)?(.*)$#',
'$2',
$options['directories'][$index]
);
- $relativePath = rtrim($relativePath, "\//");
+ $relativePath = \rtrim($relativePath, "\//");
$this->directories[] = $this->builder->buildPath . $relativePath . '/';
}
}
- if (array_key_exists('recursive', $options)) {
+ if (\array_key_exists('recursive', $options)) {
$this->recursive = $options['recursive'];
}
}
@@ -81,7 +85,7 @@ protected function lintItem($php, $item, $itemPath)
{
$success = true;
- if ($item->isFile() && $item->getExtension() == 'php' && !$this->lintFile($php, $itemPath)) {
+ if ($item->isFile() && $item->getExtension() === 'php' && !$this->lintFile($php, $itemPath)) {
$success = false;
} elseif ($item->isDir() &&
$this->recursive &&
@@ -108,7 +112,7 @@ protected function lintDirectory($php, $path)
$itemPath = $path . $item->getFilename();
- if (in_array($itemPath, $this->ignore, true)) {
+ if (\in_array($itemPath, $this->ignore, true)) {
continue;
}
diff --git a/src/Plugin/Mage.php b/src/Plugin/Mage.php
index 79a180ce8..c276703b8 100644
--- a/src/Plugin/Mage.php
+++ b/src/Plugin/Mage.php
@@ -1,21 +1,20 @@
*/
class Mage extends Plugin
{
@@ -39,7 +38,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->executable = $this->findBinary(['mage', 'mage.phar']);
if (isset($options['env'])) {
- $this->mageEnv = $builder->interpolate($options['env']);
+ $this->mageEnv = $builder->interpolate($options['env'], true);
}
}
@@ -60,7 +59,7 @@ public function execute()
$this->builder->log('########## MAGE LOG BEGIN ##########');
$this->builder->log($this->getMageLog());
$this->builder->log('########## MAGE LOG END ##########');
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
$this->builder->logFailure($e->getMessage());
}
@@ -75,41 +74,38 @@ public function execute()
protected function getMageLog()
{
$logsDir = $this->build->getBuildPath() . '/.mage/logs';
- if (!is_dir($logsDir)) {
- throw new Exception('Log directory not found');
+ if (!\is_dir($logsDir)) {
+ throw new RuntimeException('Log directory not found');
}
- $list = scandir($logsDir);
+ $list = \scandir($logsDir);
if ($list === false) {
- throw new Exception('Log dir read fail');
+ throw new RuntimeException('Log dir read fail');
}
- $list = array_filter($list, function ($name) {
- return preg_match('/^log-\d+-\d+\.log$/', $name);
- });
+ $list = \array_filter($list, fn ($name) => \preg_match('/^log-\d+-\d+\.log$/', $name));
if (empty($list)) {
- throw new Exception('Log dir filter fail');
+ throw new RuntimeException('Log dir filter fail');
}
- $res = sort($list);
+ $res = \sort($list);
if ($res === false) {
- throw new Exception('Logs sort fail');
+ throw new RuntimeException('Logs sort fail');
}
- $lastLogFile = end($list);
+ $lastLogFile = \end($list);
if ($lastLogFile === false) {
- throw new Exception('Get last Log name fail');
+ throw new RuntimeException('Get last Log name fail');
}
- $logContent = file_get_contents($logsDir . '/' . $lastLogFile);
+ $logContent = \file_get_contents($logsDir . '/' . $lastLogFile);
if ($logContent === false) {
- throw new Exception('Get last Log content fail');
+ throw new RuntimeException('Get last Log content fail');
}
- $lines = explode("\n", $logContent);
- $lines = array_map('trim', $lines);
- $lines = array_filter($lines);
+ $lines = \explode("\n", $logContent);
+ $lines = \array_map('trim', $lines);
- return $lines;
+ return \array_filter($lines);
}
}
diff --git a/src/Plugin/Mage3.php b/src/Plugin/Mage3.php
index b7175266a..c60ab9f47 100644
--- a/src/Plugin/Mage3.php
+++ b/src/Plugin/Mage3.php
@@ -1,21 +1,20 @@
*/
class Mage3 extends Plugin
{
@@ -40,11 +39,11 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->executable = $this->findBinary(['mage', 'mage.phar']);
if (isset($options['env'])) {
- $this->mageEnv = $builder->interpolate($options['env']);
+ $this->mageEnv = $builder->interpolate($options['env'], true);
}
if (isset($options['log_dir'])) {
- $this->mageLogDir = $builder->interpolate($options['log_dir']);
+ $this->mageLogDir = $builder->interpolate($options['log_dir'], true);
}
}
@@ -65,7 +64,7 @@ public function execute()
$this->builder->log('########## MAGE LOG BEGIN ##########');
$this->builder->log($this->getMageLog());
$this->builder->log('########## MAGE LOG END ##########');
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
$this->builder->logFailure($e->getMessage());
}
@@ -80,41 +79,38 @@ public function execute()
protected function getMageLog()
{
$logsDir = $this->build->getBuildPath() . (!empty($this->mageLogDir) ? '/' . $this->mageLogDir : '');
- if (!is_dir($logsDir)) {
- throw new Exception('Log directory not found');
+ if (!\is_dir($logsDir)) {
+ throw new RuntimeException('Log directory not found');
}
- $list = scandir($logsDir);
+ $list = \scandir($logsDir);
if ($list === false) {
- throw new Exception('Log dir read fail');
+ throw new RuntimeException('Log dir read fail');
}
- $list = array_filter($list, function ($name) {
- return preg_match('/^\d+_\d+\.log$/', $name);
- });
+ $list = \array_filter($list, fn ($name) => \preg_match('/^\d+_\d+\.log$/', $name));
if (empty($list)) {
- throw new Exception('Log dir filter fail');
+ throw new RuntimeException('Log dir filter fail');
}
- $res = sort($list);
+ $res = \sort($list);
if ($res === false) {
- throw new Exception('Logs sort fail');
+ throw new RuntimeException('Logs sort fail');
}
- $lastLogFile = end($list);
+ $lastLogFile = \end($list);
if ($lastLogFile === false) {
- throw new Exception('Get last Log name fail');
+ throw new RuntimeException('Get last Log name fail');
}
- $logContent = file_get_contents($logsDir . '/' . $lastLogFile);
+ $logContent = \file_get_contents($logsDir . '/' . $lastLogFile);
if ($logContent === false) {
- throw new Exception('Get last Log content fail');
+ throw new RuntimeException('Get last Log content fail');
}
- $lines = explode("\n", $logContent);
- $lines = array_map('trim', $lines);
- $lines = array_filter($lines);
+ $lines = \explode("\n", $logContent);
+ $lines = \array_map('trim', $lines);
- return $lines;
+ return \array_filter($lines);
}
}
diff --git a/src/Plugin/Mysql.php b/src/Plugin/Mysql.php
index 61f6b3e87..04e469bc5 100644
--- a/src/Plugin/Mysql.php
+++ b/src/Plugin/Mysql.php
@@ -5,15 +5,20 @@
use Exception;
use PDO;
use PHPCensor\Builder;
-use PHPCensor\Database;
+use PHPCensor\Common\Exception\InvalidArgumentException;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
/**
* MySQL Plugin - Provides access to a MySQL database.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
* @author Steve Kamerman
+ * @author Dmitry Khomutov
*/
class Mysql extends Plugin
{
@@ -83,19 +88,19 @@ public function __construct(Builder $builder, Build $build, array $options = [])
}
if (!empty($buildSettings['mysql']['host'])) {
- $this->host = $this->builder->interpolate($buildSettings['mysql']['host']);
+ $this->host = $this->builder->interpolate($buildSettings['mysql']['host'], true);
}
if (!empty($buildSettings['mysql']['port'])) {
- $this->port = (int)$this->builder->interpolate($buildSettings['mysql']['port']);
+ $this->port = (int)$this->builder->interpolate($buildSettings['mysql']['port'], true);
}
if (!empty($buildSettings['mysql']['dbname'])) {
- $this->dbName = $this->builder->interpolate($buildSettings['mysql']['dbname']);
+ $this->dbName = $this->builder->interpolate($buildSettings['mysql']['dbname'], true);
}
if (!empty($buildSettings['mysql']['charset'])) {
- $this->charset = $this->builder->interpolate($buildSettings['mysql']['charset']);
+ $this->charset = $this->builder->interpolate($buildSettings['mysql']['charset'], true);
}
if (!empty($buildSettings['mysql']['options']) && \is_array($buildSettings['mysql']['options'])) {
@@ -103,16 +108,16 @@ public function __construct(Builder $builder, Build $build, array $options = [])
}
if (!empty($buildSettings['mysql']['user'])) {
- $this->user = $this->builder->interpolate($buildSettings['mysql']['user']);
+ $this->user = $this->builder->interpolate($buildSettings['mysql']['user'], true);
}
if (\array_key_exists('password', $buildSettings['mysql'])) {
- $this->password = $this->builder->interpolate($buildSettings['mysql']['password']);
+ $this->password = $this->builder->interpolate($buildSettings['mysql']['password'], true);
}
if (!empty($this->options['queries']) && \is_array($this->options['queries'])) {
foreach ($this->options['queries'] as $query) {
- $this->queries[] = $this->builder->interpolate($query);
+ $this->queries[] = $this->builder->interpolate($query, true);
}
}
@@ -150,7 +155,7 @@ public function execute()
foreach ($this->imports as $import) {
$this->executeFile($import);
}
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$this->builder->logFailure($ex->getMessage());
return false;
@@ -167,19 +172,19 @@ public function execute()
protected function executeFile(array $query)
{
if (!isset($query['file'])) {
- throw new Exception('Import statement must contain a \'file\' key');
+ throw new InvalidArgumentException('Import statement must contain a \'file\' key');
}
- $importFile = $this->builder->buildPath . $this->builder->interpolate($query['file']);
- if (!is_readable($importFile)) {
- throw new Exception(sprintf('Cannot open SQL import file: %s', $importFile));
+ $importFile = $this->builder->buildPath . $this->builder->interpolate($query['file'], true);
+ if (!\is_readable($importFile)) {
+ throw new RuntimeException(\sprintf('Cannot open SQL import file: %s', $importFile));
}
- $database = isset($query['database']) ? $this->builder->interpolate($query['database']) : null;
+ $database = isset($query['database']) ? $this->builder->interpolate($query['database'], true) : null;
$importCommand = $this->getImportCommand($importFile, $database);
if (!$this->builder->executeCommand($importCommand)) {
- throw new Exception('Unable to execute SQL file');
+ throw new RuntimeException('Unable to execute SQL file');
}
return true;
@@ -200,21 +205,21 @@ protected function getImportCommand($importFile, $database = null)
'gz' => '| gzip --decompress',
];
- $extension = strtolower(pathinfo($importFile, PATHINFO_EXTENSION));
+ $extension = \strtolower(\pathinfo($importFile, PATHINFO_EXTENSION));
$decompressionCmd = '';
- if (array_key_exists($extension, $decompression)) {
+ if (\array_key_exists($extension, $decompression)) {
$decompressionCmd = $decompression[$extension];
}
$args = [
- ':import_file' => escapeshellarg($importFile),
+ ':import_file' => \escapeshellarg($importFile),
':decomp_cmd' => $decompressionCmd,
- ':host' => escapeshellarg($this->host),
- ':user' => escapeshellarg($this->user),
- ':pass' => (!$this->password) ? '' : '-p' . escapeshellarg($this->password),
- ':database' => ($database === null) ? '' : escapeshellarg($database),
+ ':host' => \escapeshellarg($this->host),
+ ':user' => \escapeshellarg($this->user),
+ ':pass' => (!$this->password) ? '' : '-p' . \escapeshellarg($this->password),
+ ':database' => ($database === null) ? '' : \escapeshellarg($database),
];
- return strtr('cat :import_file :decomp_cmd | mysql -h:host -u:user :pass :database', $args);
+ return \strtr('cat :import_file :decomp_cmd | mysql -h:host -u:user :pass :database', $args);
}
}
diff --git a/src/Plugin/Option/PhpUnitOptions.php b/src/Plugin/Option/PhpUnitOptions.php
index 5de0312a8..4bbe70e42 100644
--- a/src/Plugin/Option/PhpUnitOptions.php
+++ b/src/Plugin/Option/PhpUnitOptions.php
@@ -2,39 +2,32 @@
namespace PHPCensor\Plugin\Option;
-use PHPCensor\Builder;
-use PHPCensor\Config;
+use PHPCensor\Common\Application\ConfigurationInterface;
/**
* Class PhpUnitOptions validates and parse the option for the PhpUnitV2 plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Pablo Tejada
+ * @author Dmitry Khomutov
*/
class PhpUnitOptions
{
- /**
- * @var array
- */
- protected $options;
+ protected array $options;
- /**
- * @var string
- */
- protected $location;
+ protected string $location;
- /**
- * @var array
- */
- protected $arguments = [];
+ protected array $arguments = [];
- /**
- * @param array $options
- * @param string $location
- */
- public function __construct($options, $location)
+ protected ConfigurationInterface $configuration;
+
+ public function __construct(ConfigurationInterface $configuration, array $options, string $location)
{
- $this->options = $options;
- $this->location = $location;
+ $this->configuration = $configuration;
+ $this->options = $options;
+ $this->location = $location;
}
/**
@@ -59,9 +52,9 @@ public function buildArgumentString()
{
$argumentString = '';
foreach ($this->getCommandArguments() as $argumentName => $argumentValues) {
- $prefix = $argumentName[0] == '-' ? '' : '--';
+ $prefix = $argumentName[0] === '-' ? '' : '--';
- if (!is_array($argumentValues)) {
+ if (!\is_array($argumentValues)) {
$argumentValues = [$argumentValues];
}
@@ -103,15 +96,15 @@ private function parseArguments()
*/
if (isset($this->options['args'])) {
$rawArgs = $this->options['args'];
- if (is_array($rawArgs)) {
+ if (\is_array($rawArgs)) {
$this->arguments = $rawArgs;
} else {
/*
* Try to parse old arguments in a single string
*/
- preg_match_all('@--([a-z\-]+)([\s=]+)?[\'"]?((?!--)[-\w/.,\\\]+)?[\'"]?@', (string)$rawArgs, $argsMatch);
+ \preg_match_all('@--([a-z\-]+)([\s=]+)?[\'"]?((?!--)[-\w/.,\\\]+)?[\'"]?@', (string)$rawArgs, $argsMatch);
- if (!empty($argsMatch) && sizeof($argsMatch) > 2) {
+ if (!empty($argsMatch) && \sizeof($argsMatch) > 2) {
foreach ($argsMatch[1] as $index => $argName) {
$this->addArgument($argName, $argsMatch[3][$index]);
}
@@ -123,7 +116,7 @@ private function parseArguments()
* Handles command aliases outside of the args option
*/
if (isset($this->options['coverage']) && $this->options['coverage']) {
- $allowPublicArtifacts = (bool)Config::getInstance()->get(
+ $allowPublicArtifacts = (bool)$this->configuration->get(
'php-censor.build.allow_public_artifacts',
false
);
@@ -155,7 +148,7 @@ private function parseArguments()
public function addArgument($argumentName, $argumentValue = null)
{
if (isset($this->arguments[$argumentName])) {
- if (!is_array($this->arguments[$argumentName])) {
+ if (!\is_array($this->arguments[$argumentName])) {
// Convert existing argument values into an array
$this->arguments[$argumentName] = [$this->arguments[$argumentName]];
}
@@ -177,15 +170,15 @@ public function getDirectories()
{
$directories = $this->getOption('directories');
- if (is_string($directories)) {
+ if (\is_string($directories)) {
$directories = [$directories];
} else {
- if (is_null($directories)) {
+ if (\is_null($directories)) {
$directories = [];
}
}
- return is_array($directories) ? $directories : [$directories];
+ return \is_array($directories) ? $directories : [$directories];
}
/**
@@ -254,7 +247,7 @@ public function getArgument($argumentName)
$this->parseArguments();
if (isset($this->arguments[$argumentName])) {
- return is_array(
+ return \is_array(
$this->arguments[$argumentName]
) ? $this->arguments[$argumentName] : [$this->arguments[$argumentName]];
}
@@ -281,7 +274,7 @@ public static function findConfigFile($buildPath)
];
foreach ($files as $file) {
- if (file_exists($buildPath . $file)) {
+ if (\file_exists($buildPath . $file)) {
return $file;
}
}
diff --git a/src/Plugin/PackageBuild.php b/src/Plugin/PackageBuild.php
index 1b0b1652c..e69fc7ad2 100644
--- a/src/Plugin/PackageBuild.php
+++ b/src/Plugin/PackageBuild.php
@@ -9,7 +9,11 @@
/**
* Create a ZIP or TAR.GZ archive of the entire build.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class PackageBuild extends Plugin
{
@@ -46,9 +50,9 @@ public function execute()
return false;
}
- $filename = preg_replace('/([^a-zA-Z0-9_-]+)/', '', $this->filename);
+ $filename = \preg_replace('/([^a-zA-Z0-9_-]+)/', '', $this->filename);
- if (!is_array($this->format)) {
+ if (!\is_array($this->format)) {
$this->format = [$this->format];
}
@@ -57,17 +61,19 @@ public function execute()
switch ($format) {
case 'tar':
$cmd = 'tar cfz "%s/%s.tar.gz" ./*';
+
break;
default:
case 'zip':
$cmd = 'zip -rq "%s/%s.zip" ./*';
+
break;
}
$success = $this->builder->executeCommand(
$cmd,
$this->directory,
- $this->builder->interpolate($filename)
+ $this->builder->interpolate($filename, true)
);
}
diff --git a/src/Plugin/Pahout.php b/src/Plugin/Pahout.php
index 24f38cb71..a997ff785 100644
--- a/src/Plugin/Pahout.php
+++ b/src/Plugin/Pahout.php
@@ -10,8 +10,12 @@
use PHPCensor\Plugin;
/**
- * A pair programming partner for writing better PHP.
- * https://github.com/wata727/pahout
+ * A pair programming partner for writing better PHP. https://github.com/wata727/pahout
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Pahout extends Plugin
{
@@ -33,13 +37,13 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->executable = $this->findBinary(['pahout', 'pahout.phar']);
- if (!empty($options['directory']) && is_string($options['directory'])) {
+ if (!empty($options['directory']) && \is_string($options['directory'])) {
$this->directory = $options['directory'];
} else {
$this->directory = './src';
}
- if (isset($options['allowed_warnings']) && is_int($options['allowed_warnings'])) {
+ if (isset($options['allowed_warnings']) && \is_int($options['allowed_warnings'])) {
$this->allowedWarnings = $options['allowed_warnings'];
} else {
$this->allowedWarnings = -1;
@@ -69,8 +73,8 @@ public function execute()
list($files, $hints) = $this->processReport($this->builder->getLastOutput());
- if (0 < count($hints)) {
- if (-1 !== $this->allowedWarnings && count($hints) > $this->allowedWarnings) {
+ if (0 < \count($hints)) {
+ if (-1 !== $this->allowedWarnings && \count($hints) > $this->allowedWarnings) {
$success = false;
}
@@ -83,7 +87,7 @@ public function execute()
$hint['message'],
BuildError::SEVERITY_LOW,
$hint['file'],
- $hint['line_from']
+ (int)$hint['line_from']
);
}
}
@@ -92,7 +96,7 @@ public function execute()
$this->builder->logSuccess('Awesome! There is nothing from me to teach you!');
}
- $this->builder->log(sprintf('%d files checked, %d hints detected.', count($files), count($hints)));
+ $this->builder->log(\sprintf('%d files checked, %d hints detected.', \count($files), \count($hints)));
return $success;
}
@@ -121,17 +125,17 @@ public static function canExecuteOnStage($stage, Build $build)
*/
protected function processReport($output)
{
- $data = json_decode(trim($output), true);
+ $data = \json_decode(\trim($output), true);
$hints = [];
$files = [];
- if (!empty($data) && is_array($data) && isset($data['hints'])) {
+ if (!empty($data) && \is_array($data) && isset($data['hints'])) {
$files = $data['files'];
foreach ($data['hints'] as $hint) {
$hints[] = [
- 'full_message' => vsprintf('%s:%d' . PHP_EOL . self::TAB . '%s: %s [%s]', [
+ 'full_message' => \vsprintf('%s:%d' . PHP_EOL . self::TAB . '%s: %s [%s]', [
$hint['filename'],
$hint['lineno'],
$hint['type'],
diff --git a/src/Plugin/Pdepend.php b/src/Plugin/Pdepend.php
index 03b921990..74964c0b9 100644
--- a/src/Plugin/Pdepend.php
+++ b/src/Plugin/Pdepend.php
@@ -2,9 +2,8 @@
namespace PHPCensor\Plugin;
-use Exception;
use PHPCensor\Builder;
-use PHPCensor\Config;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
use Symfony\Component\Filesystem\Filesystem;
@@ -12,7 +11,11 @@
/**
* Pdepend Plugin - Allows Pdepend report
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Johan van der Heide
+ * @author Dmitry Khomutov
*/
class Pdepend extends Plugin
{
@@ -31,17 +34,17 @@ class Pdepend extends Plugin
/**
* @var string File where the summary.xml is stored
*/
- protected $summary;
+ protected $summary = 'summary.xml';
/**
* @var string File where the chart.svg is stored
*/
- protected $chart;
+ protected $chart = 'chart.svg';
/**
* @var string File where the pyramid.svg is stored
*/
- protected $pyramid;
+ protected $pyramid = 'pyramid.svg';
/**
* @var string
@@ -68,10 +71,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->summary = 'summary.xml';
- $this->pyramid = 'pyramid.svg';
- $this->chart = 'chart.svg';
-
$this->executable = $this->findBinary(['pdepend', 'pdepend.phar']);
$this->buildDirectory = $build->getBuildDirectory();
@@ -86,7 +85,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
*/
public function execute()
{
- $allowPublicArtifacts = (bool)Config::getInstance()->get(
+ $allowPublicArtifacts = (bool)$this->builder->getConfiguration()->get(
'php-censor.build.allow_public_artifacts',
false
);
@@ -94,11 +93,11 @@ public function execute()
$fileSystem = new Filesystem();
if (!$fileSystem->exists($this->buildLocation)) {
- $fileSystem->mkdir($this->buildLocation, (0777 & ~umask()));
+ $fileSystem->mkdir($this->buildLocation, (0777 & ~\umask()));
}
- if (!is_writable($this->buildLocation)) {
- throw new Exception(sprintf(
+ if (!\is_writable($this->buildLocation)) {
+ throw new RuntimeException(\sprintf(
'The location %s is not writable or does not exist.',
$this->buildLocation
));
@@ -108,8 +107,8 @@ public function execute()
$cmd = 'cd "%s" && ' . $pdepend . ' --summary-xml="%s" --jdepend-chart="%s" --overview-pyramid="%s" %s "%s"';
$ignore = '';
- if (count($this->ignore)) {
- $ignore = sprintf(' --ignore="%s"', implode(',', $this->ignore));
+ if (\count($this->ignore)) {
+ $ignore = \sprintf(' --ignore="%s"', \implode(',', $this->ignore));
}
$success = $this->builder->executeCommand(
@@ -125,14 +124,14 @@ public function execute()
if (!$allowPublicArtifacts) {
$fileSystem->remove($this->buildLocation);
}
- if ($allowPublicArtifacts && file_exists($this->buildLocation)) {
+ if ($allowPublicArtifacts && \file_exists($this->buildLocation)) {
$fileSystem->remove($this->buildBranchLocation);
$fileSystem->mirror($this->buildLocation, $this->buildBranchLocation);
}
if ($allowPublicArtifacts && $success) {
$this->builder->logSuccess(
- sprintf(
+ \sprintf(
"\nPdepend successful build report.\nYou can use report for this build for inclusion in the readme.md file:\n%s,\n and\n\n\nOr report for last build in the branch:\n%s,\n and\n\n",
APP_URL . 'artifacts/pdepend/' . $this->buildDirectory . '/' . $this->summary,
APP_URL . 'artifacts/pdepend/' . $this->buildDirectory . '/' . $this->chart,
diff --git a/src/Plugin/Pgsql.php b/src/Plugin/Pgsql.php
index fb7e02478..88a6f6e1c 100644
--- a/src/Plugin/Pgsql.php
+++ b/src/Plugin/Pgsql.php
@@ -11,7 +11,11 @@
/**
* PgSQL Plugin - Provides access to a PgSQL database.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class Pgsql extends Plugin
{
@@ -68,15 +72,15 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$buildSettings = $this->builder->getConfig('build_settings');
if (!empty($buildSettings['pgsql']['host'])) {
- $this->host = $this->builder->interpolate($buildSettings['pgsql']['host']);
+ $this->host = $this->builder->interpolate($buildSettings['pgsql']['host'], true);
}
if (!empty($buildSettings['pgsql']['port'])) {
- $this->port = (int)$this->builder->interpolate($buildSettings['pgsql']['port']);
+ $this->port = (int)$this->builder->interpolate($buildSettings['pgsql']['port'], true);
}
if (!empty($buildSettings['pgsql']['dbname'])) {
- $this->dbName = $this->builder->interpolate($buildSettings['pgsql']['dbname']);
+ $this->dbName = $this->builder->interpolate($buildSettings['pgsql']['dbname'], true);
}
if (!empty($buildSettings['pgsql']['options']) && \is_array($buildSettings['pgsql']['options'])) {
@@ -84,16 +88,16 @@ public function __construct(Builder $builder, Build $build, array $options = [])
}
if (!empty($buildSettings['pgsql']['user'])) {
- $this->user = $this->builder->interpolate($buildSettings['pgsql']['user']);
+ $this->user = $this->builder->interpolate($buildSettings['pgsql']['user'], true);
}
- if (array_key_exists('password', $buildSettings['pgsql'])) {
- $this->password = $this->builder->interpolate($buildSettings['pgsql']['password']);
+ if (\array_key_exists('password', $buildSettings['pgsql'])) {
+ $this->password = $this->builder->interpolate($buildSettings['pgsql']['password'], true);
}
if (!empty($this->options['queries']) && \is_array($this->options['queries'])) {
foreach ($this->options['queries'] as $query) {
- $this->queries[] = $this->builder->interpolate($query);
+ $this->queries[] = $this->builder->interpolate($query, true);
}
}
}
@@ -105,10 +109,10 @@ public function __construct(Builder $builder, Build $build, array $options = [])
public function execute()
{
try {
- $pdoOptions = array_merge([
+ $pdoOptions = \array_merge([
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
], $this->pdoOptions);
- $dsn = sprintf('pgsql:host=%s;port=%s', $this->host, $this->port);
+ $dsn = \sprintf('pgsql:host=%s;port=%s', $this->host, $this->port);
if (null !== $this->dbName) {
$dsn .= ';dbname=' . $this->dbName;
@@ -119,7 +123,7 @@ public function execute()
foreach ($this->queries as $query) {
$pdo->query($query);
}
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$this->builder->logFailure($ex->getMessage());
return false;
diff --git a/src/Plugin/Phan.php b/src/Plugin/Phan.php
index 2755f292a..f3eeefe9c 100644
--- a/src/Plugin/Phan.php
+++ b/src/Plugin/Phan.php
@@ -4,12 +4,18 @@
use Exception;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model\Build;
use PHPCensor\Model\BuildError;
use PHPCensor\Plugin;
/**
* Launch Phan.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Phan extends Plugin
{
@@ -50,12 +56,12 @@ public function __construct(Builder $builder, Build $build, array $options = [])
*/
public function execute()
{
- if (!file_exists($this->location)) {
- mkdir($this->location, (0777 & ~umask()), true);
+ if (!\file_exists($this->location)) {
+ \mkdir($this->location, (0777 & ~\umask()), true);
}
- if (!is_writable($this->location)) {
- throw new Exception(sprintf('The location %s is not writable or does not exist.', $this->location));
+ if (!\is_writable($this->location)) {
+ throw new RuntimeException(\sprintf('The location %s is not writable or does not exist.', $this->location));
}
// Find PHP files in a file
@@ -76,7 +82,7 @@ public function execute()
$this->builder->executeCommand($cmd, $this->location . '/phan.in', $this->location . '/phan.out');
- $warningCount = $this->processReport(file_get_contents($this->location . '/phan.out'));
+ $warningCount = $this->processReport(\file_get_contents($this->location . '/phan.out'));
$this->build->storeMeta((self::pluginName() . '-warnings'), $warningCount);
@@ -100,12 +106,12 @@ public function execute()
*/
protected function processReport($jsonString)
{
- $json = json_decode($jsonString, true);
+ $json = \json_decode($jsonString, true);
- if ($json === false || !is_array($json)) {
+ if ($json === false || !\is_array($json)) {
$this->builder->log($jsonString);
- throw new Exception('Could not process the report generated by Phan.');
+ throw new RuntimeException('Could not process the report generated by Phan.');
}
$warnings = 0;
@@ -117,8 +123,8 @@ protected function processReport($jsonString)
$data['check_name']."\n\n".$data['description'],
$this->severity($data['severity']),
isset($data['location']['path']) ? $data['location']['path'] : '??',
- isset($data['location']['lines']['begin']) ? $data['location']['lines']['begin'] : '??',
- isset($data['location']['lines']['end']) ? $data['location']['lines']['end'] : '??'
+ isset($data['location']['lines']['begin']) ? (int)$data['location']['lines']['begin'] : null,
+ isset($data['location']['lines']['end']) ? (int)$data['location']['lines']['end'] : null
);
$warnings++;
@@ -136,11 +142,11 @@ protected function processReport($jsonString)
*/
protected function severity($severity)
{
- if ($severity == 10) {
+ if ($severity === 10) {
return BuildError::SEVERITY_CRITICAL;
}
- if ($severity == 5) {
+ if ($severity === 5) {
return BuildError::SEVERITY_NORMAL;
}
diff --git a/src/Plugin/Phar.php b/src/Plugin/Phar.php
index 8c8d4ffc9..de79d390b 100644
--- a/src/Plugin/Phar.php
+++ b/src/Plugin/Phar.php
@@ -10,6 +10,11 @@
/**
* Phar Plugin
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Phar extends Plugin
{
@@ -148,7 +153,7 @@ public function getStubContent()
$content = '';
$filename = $this->getStub();
if ($filename) {
- $content = file_get_contents($this->builder->buildPath . $this->getStub());
+ $content = \file_get_contents($this->builder->buildPath . $this->getStub());
}
return $content;
@@ -172,7 +177,7 @@ public function execute()
}
$success = true;
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
$this->builder->logFailure('Phar Plugin Internal Error. Exception: ' . $e->getMessage());
}
diff --git a/src/Plugin/Phing.php b/src/Plugin/Phing.php
index f8325b83d..231dadbe4 100644
--- a/src/Plugin/Phing.php
+++ b/src/Plugin/Phing.php
@@ -4,13 +4,18 @@
use Exception;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
/**
* Phing Plugin - Provides access to Phing functionality.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Pavel Pavlov
+ * @author Dmitry Khomutov
*/
class Phing extends Plugin
{
@@ -75,7 +80,7 @@ public function execute()
$cmd[] = $this->targetsToString();
$cmd[] = '2>&1';
- return $this->builder->executeCommand(implode(' ', $cmd), $this->directory, $this->targets);
+ return $this->builder->executeCommand(\implode(' ', $cmd), $this->directory, $this->targets);
}
/**
@@ -92,7 +97,7 @@ public function getTargets()
*/
private function targetsToString()
{
- return implode(' ', $this->targets);
+ return \implode(' ', $this->targets);
}
/**
@@ -102,7 +107,7 @@ private function targetsToString()
*/
public function setTargets($targets)
{
- if (is_string($targets)) {
+ if (\is_string($targets)) {
$targets = [$targets];
}
@@ -125,8 +130,8 @@ public function getBuildFile()
*/
public function setBuildFile($buildFile)
{
- if (!file_exists($this->directory . $buildFile)) {
- throw new Exception('Specified build file does not exist.');
+ if (!\file_exists($this->directory . $buildFile)) {
+ throw new RuntimeException('Specified build file does not exist.');
}
$this->buildFile = $buildFile;
@@ -168,7 +173,7 @@ public function propertiesToString()
$propertiesString[] = '-D' . $name . '="' . $value . '"';
}
- return implode(' ', $propertiesString);
+ return \implode(' ', $propertiesString);
}
/**
@@ -178,7 +183,7 @@ public function propertiesToString()
*/
public function setProperties($properties)
{
- if (is_string($properties)) {
+ if (\is_string($properties)) {
$properties = [$properties];
}
@@ -201,8 +206,8 @@ public function getPropertyFile()
*/
public function setPropertyFile($propertyFile)
{
- if (!file_exists($this->directory . '/' . $propertyFile)) {
- throw new Exception('Specified property file does not exist.');
+ if (!\file_exists($this->directory . '/' . $propertyFile)) {
+ throw new RuntimeException('Specified property file does not exist.');
}
$this->propertyFile = $propertyFile;
diff --git a/src/Plugin/Phlint.php b/src/Plugin/Phlint.php
index f2c105c75..91501e8a0 100644
--- a/src/Plugin/Phlint.php
+++ b/src/Plugin/Phlint.php
@@ -14,6 +14,11 @@
* issues. It focuses on how the code works rather than how the code looks. Phlint is designed from the start to do
* deep semantic analysis rather than doing only shallow or stylistic analysis.
* https://gitlab.com/phlint/phlint
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Phlint extends Plugin
{
@@ -29,7 +34,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->executable = $this->findBinary(['phlint', 'phlint.phar']);
- if (array_key_exists('allowed_errors', $options) && is_int($options['allowed_errors'])) {
+ if (\array_key_exists('allowed_errors', $options) && \is_int($options['allowed_errors'])) {
$this->allowedErrors = $options['allowed_errors'];
}
}
@@ -50,8 +55,8 @@ public function execute()
$errors = $this->processReport($this->builder->getLastOutput());
- if (0 < count($errors)) {
- if (-1 !== $this->allowedErrors && count($errors) > $this->allowedErrors) {
+ if (0 < \count($errors)) {
+ if (-1 !== $this->allowedErrors && \count($errors) > $this->allowedErrors) {
$success = false;
}
@@ -62,7 +67,7 @@ public function execute()
$error['message'],
BuildError::SEVERITY_HIGH,
$error['file'],
- $error['line_from']
+ (int)$error['line_from']
);
}
}
@@ -84,19 +89,19 @@ public static function pluginName()
*/
protected function processReport($output)
{
- $data = explode(chr(226), preg_replace('#\\x1b[[][^A-Za-z\n]*[A-Za-z]#', '', trim($output)));
- array_pop($data);
- array_shift($data);
+ $data = \explode(\chr(226), \preg_replace('#\\x1b[[][^A-Za-z\n]*[A-Za-z]#', '', \trim($output)));
+ \array_pop($data);
+ \array_shift($data);
$errors = [];
- if (0 < count($data)) {
+ if (0 < \count($data)) {
foreach ($data as $error) {
- $error = explode(PHP_EOL, $error);
- $header = substr(trim(array_shift($error)), 3);
- $file = strstr(substr(strstr($header, 'in '), 3), ':', true);
- $line = substr(strrchr($header, ':'), 1);
- $message = ltrim($error[0]) . PHP_EOL . ltrim($error[1]);
+ $error = \explode(PHP_EOL, $error);
+ $header = \substr(\trim(\array_shift($error)), 3);
+ $file = \strstr(\substr(\strstr($header, 'in '), 3), ':', true);
+ $line = \substr(\strrchr($header, ':'), 1);
+ $message = \ltrim($error[0]) . PHP_EOL . \ltrim($error[1]);
$errors[] = [
'message' => $message,
diff --git a/src/Plugin/PhpCodeSniffer.php b/src/Plugin/PhpCodeSniffer.php
index a18f4f588..082e221c3 100644
--- a/src/Plugin/PhpCodeSniffer.php
+++ b/src/Plugin/PhpCodeSniffer.php
@@ -9,43 +9,48 @@
use PHPCensor\Model\BuildError;
use PHPCensor\Plugin;
use PHPCensor\ZeroConfigPluginInterface;
+use PHPCensor\Common\Exception\RuntimeException;
/**
* PHP Code Sniffer Plugin - Allows PHP Code Sniffer testing.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class PhpCodeSniffer extends Plugin implements ZeroConfigPluginInterface
{
/**
* @var array
*/
- protected $suffixes;
+ protected $suffixes = ['php'];
/**
* @var string
*/
- protected $standard;
+ protected $standard = 'PSR2';
/**
* @var string
*/
- protected $tabWidth;
+ protected $tabWidth = '';
/**
* @var string
*/
- protected $encoding;
+ protected $encoding = '';
/**
* @var int
*/
- protected $allowedErrors;
+ protected $allowedErrors = 0;
/**
* @var int
*/
- protected $allowedWarnings;
+ protected $allowedWarnings = 0;
/**
* @var int
@@ -77,13 +82,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->suffixes = ['php'];
- $this->standard = 'PSR2';
- $this->tabWidth = '';
- $this->encoding = '';
- $this->allowedWarnings = 0;
- $this->allowedErrors = 0;
-
$this->executable = $this->findBinary(['phpcs', 'phpcs.phar']);
if (isset($options['zero_config']) && $options['zero_config']) {
@@ -91,11 +89,11 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->allowedErrors = -1;
}
- if (!empty($options['allowed_errors']) && is_int($options['allowed_errors'])) {
+ if (!empty($options['allowed_errors']) && \is_int($options['allowed_errors'])) {
$this->allowedErrors = $options['allowed_errors'];
}
- if (!empty($options['allowed_warnings']) && is_int($options['allowed_warnings'])) {
+ if (!empty($options['allowed_warnings']) && \is_int($options['allowed_warnings'])) {
$this->allowedWarnings = $options['allowed_warnings'];
}
@@ -115,15 +113,15 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->standard = $options['standard'];
}
- if (isset($options['severity']) && is_int($options['severity'])) {
+ if (isset($options['severity']) && \is_int($options['severity'])) {
$this->severity = $options['severity'];
}
- if (isset($options['error_severity']) && is_int($options['error_severity'])) {
+ if (isset($options['error_severity']) && \is_int($options['error_severity'])) {
$this->errorSeverity = $options['error_severity'];
}
- if (isset($options['warning_severity']) && is_int($options['warning_severity'])) {
+ if (isset($options['warning_severity']) && \is_int($options['warning_severity'])) {
$this->warningSeverity = $options['warning_severity'];
}
}
@@ -177,11 +175,11 @@ public function execute()
$this->build->storeMeta((self::pluginName() . '-warnings'), $warnings);
$this->build->storeMeta((self::pluginName() . '-errors'), $errors);
- if (-1 != $this->allowedWarnings && $warnings > $this->allowedWarnings) {
+ if (-1 !== $this->allowedWarnings && $warnings > $this->allowedWarnings) {
$success = false;
}
- if (-1 != $this->allowedErrors && $errors > $this->allowedErrors) {
+ if (-1 !== $this->allowedErrors && $errors > $this->allowedErrors) {
$success = false;
}
@@ -195,20 +193,20 @@ public function execute()
protected function getFlags()
{
$ignore = '';
- if (count($this->ignore)) {
- $ignore = sprintf(' --ignore="%s"', implode(',', $this->ignore));
+ if (\count($this->ignore)) {
+ $ignore = \sprintf(' --ignore="%s"', \implode(',', $this->ignore));
}
$standardPath = $this->normalizePath($this->standard);
- if (file_exists($standardPath)) {
+ if (\file_exists($standardPath)) {
$standard = ' --standard=' . $standardPath;
} else {
$standard = ' --standard=' . $this->standard;
}
$suffixes = '';
- if (count($this->suffixes)) {
- $suffixes = ' --extensions=' . implode(',', $this->suffixes);
+ if (\count($this->suffixes)) {
+ $suffixes = ' --extensions=' . \implode(',', $this->suffixes);
}
$severity = '';
@@ -236,28 +234,28 @@ protected function getFlags()
*/
protected function processReport($output)
{
- $data = json_decode(trim($output), true);
+ $data = \json_decode(\trim($output), true);
- if (!is_array($data)) {
+ if (!\is_array($data)) {
$this->builder->log($output);
- throw new Exception('Could not process the report generated by PHP Code Sniffer.');
+ throw new RuntimeException('Could not process the report generated by PHP Code Sniffer.');
}
$errors = $data['totals']['errors'];
$warnings = $data['totals']['warnings'];
foreach ($data['files'] as $fileName => $file) {
- $fileName = str_replace($this->builder->buildPath, '', $fileName);
+ $fileName = \str_replace($this->builder->buildPath, '', $fileName);
foreach ($file['messages'] as $message) {
$this->build->reportError(
$this->builder,
self::pluginName(),
'PHPCS: ' . $message['message'],
- 'ERROR' == $message['type'] ? BuildError::SEVERITY_HIGH : BuildError::SEVERITY_LOW,
+ 'ERROR' === $message['type'] ? BuildError::SEVERITY_HIGH : BuildError::SEVERITY_LOW,
$fileName,
- $message['line']
+ (int)$message['line']
);
}
}
diff --git a/src/Plugin/PhpCpd.php b/src/Plugin/PhpCpd.php
index e03dc5db2..8ea652081 100644
--- a/src/Plugin/PhpCpd.php
+++ b/src/Plugin/PhpCpd.php
@@ -4,6 +4,7 @@
use Exception;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Model\Build;
use PHPCensor\Model\BuildError;
use PHPCensor\Plugin;
@@ -12,7 +13,11 @@
/**
* PHP Copy / Paste Detector - Allows PHP Copy / Paste Detector testing.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class PhpCpd extends Plugin implements ZeroConfigPluginInterface
{
@@ -104,19 +109,19 @@ public function execute()
*/
protected function processReport($xmlString)
{
- $xml = simplexml_load_string($xmlString);
+ $xml = \simplexml_load_string($xmlString);
if (false === $xml) {
$this->builder->log($xmlString);
- throw new Exception('Could not process the report generated by PHPCpd.');
+ throw new RuntimeException('Could not process the report generated by PHPCpd.');
}
$warnings = 0;
foreach ($xml->duplication as $duplication) {
foreach ($duplication->file as $file) {
$fileName = (string)$file['path'];
- $fileName = str_replace($this->builder->buildPath, '', $fileName);
+ $fileName = \str_replace($this->builder->buildPath, '', $fileName);
$message = <<
+ * @author Dmitry Khomutov
*/
class PhpCsFixer extends Plugin
{
@@ -64,7 +69,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
if (isset($options['config']) && $options['config']) {
$this->config = true;
- $this->args .= ' --config=' . $builder->interpolate($options['config']);
+ $this->args .= ' --config=' . $builder->interpolate($options['config'], true);
}
if (isset($options['errors']) && $options['errors']) {
@@ -139,7 +144,7 @@ public function execute()
$this->build->storeMeta((self::pluginName() . '-warnings'), $warningCount);
- if (-1 != $this->allowedWarnings && $warningCount > $this->allowedWarnings) {
+ if (-1 !== $this->allowedWarnings && $warningCount > $this->allowedWarnings) {
$success = false;
}
}
@@ -158,12 +163,12 @@ public function execute()
*/
protected function processReport($output)
{
- $data = json_decode(trim($output), true);
+ $data = \json_decode(\trim($output), true);
- if (!is_array($data)) {
+ if (!\is_array($data)) {
$this->builder->log($output);
- throw new Exception('Could not process the report generated by PHP CS Fixer.');
+ throw new RuntimeException('Could not process the report generated by PHP CS Fixer.');
}
$warnings = 0;
@@ -190,12 +195,15 @@ protected function processReport($output)
switch ($line->getType()) {
case Line::ADDED:
$symbol = '+';
+
break;
case Line::REMOVED:
$symbol = '-';
+
break;
default:
$symbol = ' ';
+
break;
}
$chunkDiff[] = $symbol . $line->getContent();
@@ -204,6 +212,7 @@ protected function processReport($output)
}
if (Line::UNCHANGED === $line->getType()) {
++$firstModifiedLine;
+
continue;
}
@@ -216,7 +225,7 @@ protected function processReport($output)
$this->build->reportError(
$this->builder,
self::pluginName(),
- "PHP CS Fixer suggestion:\r\n```diff\r\n" . implode("\r\n", $chunkDiff) . "\r\n```",
+ "PHP CS Fixer suggestion:\r\n```diff\r\n" . \implode("\r\n", $chunkDiff) . "\r\n```",
BuildError::SEVERITY_LOW,
$filename,
$firstModifiedLine
@@ -228,7 +237,7 @@ protected function processReport($output)
$this->build->reportError(
$this->builder,
self::pluginName(),
- 'PHP CS Fixer failed fixers: ' . implode(', ', $appliedFixers),
+ 'PHP CS Fixer failed fixers: ' . \implode(', ', $appliedFixers),
BuildError::SEVERITY_LOW,
$filename
);
diff --git a/src/Plugin/PhpDocblockChecker.php b/src/Plugin/PhpDocblockChecker.php
index 4e828b422..516a75d2c 100644
--- a/src/Plugin/PhpDocblockChecker.php
+++ b/src/Plugin/PhpDocblockChecker.php
@@ -12,7 +12,11 @@
/**
* PHP Docblock Checker Plugin - Checks your PHP files for appropriate uses of Docblocks
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class PhpDocblockChecker extends Plugin implements ZeroConfigPluginInterface
{
@@ -22,7 +26,7 @@ class PhpDocblockChecker extends Plugin implements ZeroConfigPluginInterface
/**
* @var int
*/
- protected $allowedWarnings;
+ protected $allowedWarnings = 0;
/**
* @return string
@@ -39,25 +43,23 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->allowedWarnings = 0;
-
if (isset($options['zero_config']) && $options['zero_config']) {
$this->allowedWarnings = -1;
}
- if (array_key_exists('skip_classes', $options)) {
+ if (\array_key_exists('skip_classes', $options)) {
$this->skipClasses = true;
}
- if (array_key_exists('skip_methods', $options)) {
+ if (\array_key_exists('skip_methods', $options)) {
$this->skipMethods = true;
}
- if (array_key_exists('skip_signatures', $options)) {
+ if (\array_key_exists('skip_signatures', $options)) {
$this->skipSignatures = true;
}
- if (array_key_exists('allowed_warnings', $options)) {
+ if (\array_key_exists('allowed_warnings', $options)) {
$this->allowedWarnings = (int)$options['allowed_warnings'];
}
@@ -89,8 +91,8 @@ public function execute()
// Build ignore string:
$ignore = '';
- if (is_array($this->ignore)) {
- $ignore = sprintf(' --exclude="%s"', implode(',', $this->ignore));
+ if (\is_array($this->ignore)) {
+ $ignore = \sprintf(' --exclude="%s"', \implode(',', $this->ignore));
}
// Are we skipping any checks?
@@ -122,11 +124,11 @@ public function execute()
);
$this->builder->logExecOutput(true);
- $output = json_decode($this->builder->getLastOutput(), true);
+ $output = \json_decode($this->builder->getLastOutput(), true);
$errors = 0;
- if ($output && is_array($output)) {
- $errors = count($output);
+ if ($output && \is_array($output)) {
+ $errors = \count($output);
$this->builder->logWarning("Number of error : " . $errors);
$this->reportErrors($output);
@@ -135,7 +137,7 @@ public function execute()
$success = true;
- if (-1 != $this->allowedWarnings && $errors > $this->allowedWarnings) {
+ if (-1 !== $this->allowedWarnings && $errors > $this->allowedWarnings) {
$success = false;
}
@@ -152,38 +154,45 @@ protected function reportErrors(array $output)
case 'class':
$message = 'Class ' . $error['class'] . ' is missing a docblock.';
$severity = BuildError::SEVERITY_NORMAL;
+
break;
case 'method':
$message = 'Method ' . $error['class'] . '::' . $error['method'] . ' is missing a docblock.';
$severity = BuildError::SEVERITY_NORMAL;
+
break;
case 'param-missing':
$message = $error['class'] . '::' . $error['method'] . ' @param ' . $error['param'] . ' missing.';
$severity = BuildError::SEVERITY_LOW;
+
break;
case 'param-mismatch':
$message = $error['class'] . '::' . $error['method'] . ' @param ' . $error['param'] .
'(' . $error['doc-type'] . ') does not match method signature (' . $error['param-type'] . ')';
$severity = BuildError::SEVERITY_LOW;
+
break;
case 'return-missing':
$message = $error['class'] . '::' . $error['method'] . ' @return missing.';
$severity = BuildError::SEVERITY_LOW;
+
break;
case 'return-mismatch':
$message = $error['class'] . '::' . $error['method'] . ' @return ' . $error['doc-type'] .
' does not match method signature (' . $error['return-type'] . ')';
$severity = BuildError::SEVERITY_LOW;
+
break;
default:
$message = 'Class ' . $error['class'] . ' invalid/missing a docblock.';
$severity = BuildError::SEVERITY_LOW;
+
break;
}
diff --git a/src/Plugin/PhpLoc.php b/src/Plugin/PhpLoc.php
index 07af92691..0529cc3bf 100644
--- a/src/Plugin/PhpLoc.php
+++ b/src/Plugin/PhpLoc.php
@@ -5,13 +5,18 @@
use PHPCensor;
use PHPCensor\Builder;
use PHPCensor\Model\Build;
+use PHPCensor\Model\User;
use PHPCensor\Plugin;
use PHPCensor\ZeroConfigPluginInterface;
/**
* PHP Loc - Allows PHP Copy / Lines of Code testing.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Johan van der Heide
+ * @author Dmitry Khomutov
*/
class PhpLoc extends Plugin implements ZeroConfigPluginInterface
{
@@ -51,21 +56,19 @@ public function __construct(Builder $builder, Build $build, array $options = [])
public function execute()
{
$ignore = '';
- if (is_array($this->ignore)) {
- $map = function ($item) {
- return sprintf(' --exclude="%s"', $item);
- };
+ if (\is_array($this->ignore)) {
+ $map = fn ($item) => \sprintf(' --exclude="%s"', $item);
- $ignore = array_map($map, $this->ignore);
- $ignore = implode('', $ignore);
+ $ignore = \array_map($map, $this->ignore);
+ $ignore = \implode('', $ignore);
}
$phploc = $this->executable;
- $success = $this->builder->executeCommand('cd "%s" && php -d xdebug.mode=0 -d error_reporting=0 ' . $phploc . ' %s %s', $this->builder->buildPath, $ignore, $this->directory);
+ $success = $this->builder->executeCommand('cd "%s" && php -d xdebug.mode=off -d error_reporting=0 ' . $phploc . ' %s %s', $this->builder->buildPath, $ignore, $this->directory);
$output = $this->builder->getLastOutput();
- if (preg_match_all('/\((LOC|CLOC|NCLOC|LLOC)\)\s+([0-9]+)/', $output, $matches)) {
+ if (\preg_match_all('/\((LOC|CLOC|NCLOC|LLOC)\)\s+([0-9]+)/', $output, $matches)) {
$data = [];
foreach ($matches[1] as $k => $v) {
$data[$v] = (int)$matches[2][$k];
diff --git a/src/Plugin/PhpMessDetector.php b/src/Plugin/PhpMessDetector.php
index 5e7269499..afa99af93 100644
--- a/src/Plugin/PhpMessDetector.php
+++ b/src/Plugin/PhpMessDetector.php
@@ -8,26 +8,31 @@
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
use PHPCensor\ZeroConfigPluginInterface;
+use PHPCensor\Common\Exception\RuntimeException;
/**
* PHP Mess Detector Plugin - Allows PHP Mess Detector testing.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class PhpMessDetector extends Plugin implements ZeroConfigPluginInterface
{
/**
* @var array
*/
- protected $suffixes;
+ protected $suffixes = ['php'];
/**
* Array of PHPMD rules. Can be one of the builtins (codesize, unusedcode, naming, design, controversial)
* or a filename (detected by checking for a / in it), either absolute or relative to the project root.
* @var array
*/
- protected $rules;
- protected $allowedWarnings;
+ protected $rules = ['codesize', 'unusedcode', 'naming'];
+ protected $allowedWarnings = 0;
/**
* @return string
@@ -44,15 +49,11 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->suffixes = ['php'];
- $this->rules = ['codesize', 'unusedcode', 'naming'];
- $this->allowedWarnings = 0;
-
if (isset($options['zero_config']) && $options['zero_config']) {
$this->allowedWarnings = -1;
}
- if (array_key_exists('allowed_warnings', $options)) {
+ if (\array_key_exists('allowed_warnings', $options)) {
$this->allowedWarnings = (int)$options['allowed_warnings'];
}
@@ -88,7 +89,7 @@ public function execute()
$this->executePhpMd($phpmdBinaryPath);
- $errorCount = $this->processReport(trim($this->builder->getLastOutput()));
+ $errorCount = $this->processReport(\trim($this->builder->getLastOutput()));
$this->build->storeMeta((self::pluginName() . '-warnings'), $errorCount);
return $this->wasLastExecSuccessful($errorCount);
@@ -99,7 +100,7 @@ public function execute()
*/
protected function overrideSetting($options, $key)
{
- if (isset($options[$key]) && is_array($options[$key])) {
+ if (isset($options[$key]) && \is_array($options[$key])) {
$this->{$key} = $options[$key];
}
}
@@ -114,19 +115,19 @@ protected function overrideSetting($options, $key)
*/
protected function processReport($xmlString)
{
- $xml = simplexml_load_string($xmlString);
+ $xml = \simplexml_load_string($xmlString);
if (false === $xml) {
$this->builder->log($xmlString);
- throw new Exception('Could not process PHPMD report XML.');
+ throw new RuntimeException('Could not process PHPMD report XML.');
}
$warnings = 0;
foreach ($xml->file as $file) {
$fileName = (string)$file['name'];
- $fileName = str_replace($this->builder->buildPath, '', $fileName);
+ $fileName = \str_replace($this->builder->buildPath, '', $fileName);
foreach ($file->violation as $violation) {
$warnings++;
@@ -152,14 +153,14 @@ protected function processReport($xmlString)
*/
protected function tryAndProcessRules()
{
- if (!empty($this->rules) && !is_array($this->rules)) {
+ if (!empty($this->rules) && !\is_array($this->rules)) {
$this->builder->logFailure('The "rules" option must be an array.');
return false;
}
foreach ($this->rules as &$rule) {
- if (strpos($rule, '/') !== false) {
+ if (\strpos($rule, '/') !== false) {
$rule = $this->builder->buildPath . $rule;
}
}
@@ -175,18 +176,18 @@ protected function executePhpMd($binaryPath)
$cmd = 'cd "%s" && ' . $binaryPath . ' "%s" xml %s %s %s';
$ignore = '';
- if (is_array($this->ignore) && count($this->ignore) > 0) {
+ if (\is_array($this->ignore) && \count($this->ignore) > 0) {
$ignoreArray = [];
foreach ($this->ignore as $ignoreItem) {
$ignoreArray[] = /*$this->builder->buildPath .*/ $ignoreItem;
}
- $ignore = sprintf(' --exclude "%s"', implode(',', $ignoreArray));
+ $ignore = \sprintf(' --exclude "%s"', \implode(',', $ignoreArray));
}
$suffixes = '';
- if (is_array($this->suffixes) && count($this->suffixes) > 0) {
- $suffixes = ' --suffixes ' . implode(',', $this->suffixes);
+ if (\is_array($this->suffixes) && \count($this->suffixes) > 0) {
+ $suffixes = ' --suffixes ' . \implode(',', $this->suffixes);
}
if (!$this->build->isDebug()) {
@@ -198,7 +199,7 @@ protected function executePhpMd($binaryPath)
$cmd,
$this->builder->buildPath,
$this->directory,
- implode(',', $this->rules),
+ \implode(',', $this->rules),
$ignore,
$suffixes
);
@@ -215,14 +216,10 @@ protected function executePhpMd($binaryPath)
*/
protected function wasLastExecSuccessful($errorCount)
{
- $success = true;
-
- if (-1 != $this->allowedWarnings && $errorCount > $this->allowedWarnings) {
- $success = false;
-
- return $success;
+ if (-1 !== $this->allowedWarnings && $errorCount > $this->allowedWarnings) {
+ return false;
}
- return $success;
+ return true;
}
}
diff --git a/src/Plugin/PhpParallelLint.php b/src/Plugin/PhpParallelLint.php
index 3745e5df5..4ec480d77 100644
--- a/src/Plugin/PhpParallelLint.php
+++ b/src/Plugin/PhpParallelLint.php
@@ -10,19 +10,23 @@
/**
* Php Parallel Lint Plugin - Provides access to PHP lint functionality.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Vaclav Makes
+ * @author Dmitry Khomutov
*/
class PhpParallelLint extends Plugin implements ZeroConfigPluginInterface
{
/**
* @var string - comma separated list of file extensions
*/
- protected $extensions;
+ protected $extensions = 'php';
/**
* @var bool - enable short tags
*/
- protected $shortTag;
+ protected $shortTag = false;
/**
* @return string
@@ -43,9 +47,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->extensions = 'php';
- $this->shortTag = false;
-
$this->executable = $this->findBinary(['parallel-lint', 'parallel-lint.phar']);
if (isset($options['shorttags'])) {
@@ -56,8 +57,8 @@ public function __construct(Builder $builder, Build $build, array $options = [])
// Only use if this is a comma delimited list
$pattern = '/^([a-z]+)(,\ *[a-z]*)*$/';
- if (preg_match($pattern, $options['extensions'])) {
- $this->extensions = str_replace(' ', '', $options['extensions']);
+ if (\preg_match($pattern, $options['extensions'])) {
+ $this->extensions = \str_replace(' ', '', $options['extensions']);
}
}
}
@@ -95,8 +96,8 @@ public function execute()
$output = $this->builder->getLastOutput();
$matches = [];
- if (preg_match_all('/Parse error\:/', $output, $matches)) {
- $this->build->storeMeta((self::pluginName() . '-errors'), count($matches[0]));
+ if (\preg_match_all('/Parse error\:/', $output, $matches)) {
+ $this->build->storeMeta((self::pluginName() . '-errors'), \count($matches[0]));
}
return $success;
@@ -110,10 +111,10 @@ protected function getFlags()
{
$ignoreFlags = [];
foreach ($this->ignore as $ignoreDir) {
- $ignoreFlags[] = sprintf(' --exclude "%s"', $this->builder->buildPath . $ignoreDir);
+ $ignoreFlags[] = \sprintf(' --exclude "%s"', $this->builder->buildPath . $ignoreDir);
}
- $ignore = implode(' ', $ignoreFlags);
+ $ignore = \implode(' ', $ignoreFlags);
return [$ignore];
}
diff --git a/src/Plugin/PhpSpec.php b/src/Plugin/PhpSpec.php
index 84a245cad..c285dcdbe 100644
--- a/src/Plugin/PhpSpec.php
+++ b/src/Plugin/PhpSpec.php
@@ -10,7 +10,11 @@
/**
* PHP Spec Plugin - Allows PHP Spec testing.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
+ * @author Dmitry Khomutov
*/
class PhpSpec extends Plugin
{
@@ -88,7 +92,7 @@ public function execute()
'status' => (string)$attr['status'],
];
- if ('failed' == $case['status']) {
+ if ('failed' === $case['status']) {
$error = [];
/*
* ok, sad, we had an error
diff --git a/src/Plugin/PhpStan.php b/src/Plugin/PhpStan.php
index 79091bcb0..270efe20e 100644
--- a/src/Plugin/PhpStan.php
+++ b/src/Plugin/PhpStan.php
@@ -14,6 +14,11 @@
* before you write tests for the code. It moves PHP closer to compiled languages in the sense that the correctness of
* each line of the code can be checked before you run the actual line.
* https://github.com/phpstan/phpstan
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class PhpStan extends Plugin
{
@@ -62,7 +67,7 @@ public function execute()
$this->builder->executeCommand(
'cd "%s" && ' . $phpStan . ' analyze --error-format=json %s',
$this->builder->buildPath,
- implode(' ', $this->directories)
+ \implode(' ', $this->directories)
);
$this->builder->logExecOutput(true);
@@ -78,18 +83,18 @@ public function execute()
foreach ($files as $file => $payload) {
if (0 < $payload['errors']) {
- $file = str_replace($this->build->getBuildPath(), '', $file);
- $len = strlen($file);
+ $file = \str_replace($this->build->getBuildPath(), '', $file);
+ $len = \strlen($file);
$out = '';
- $filename = (false !== strpos($file, ' (')) ? strstr($file, ' (', true) : $file;
+ $filename = (false !== \strpos($file, ' (')) ? \strstr($file, ' (', true) : $file;
foreach ($payload['messages'] as $message) {
- if (strlen($message['message']) > $len) {
- $len = strlen($message['message']);
+ if (\strlen($message['message']) > $len) {
+ $len = \strlen($message['message']);
}
- $out .= vsprintf(' %d%s %s' . PHP_EOL, [
+ $out .= \vsprintf(' %d%s %s' . PHP_EOL, [
$message['line'],
- str_repeat(' ', 6 - strlen($message['line'])),
+ \str_repeat(' ', 6 - \strlen($message['line'])),
$message['message']
]);
@@ -99,12 +104,12 @@ public function execute()
$message['message'],
BuildError::SEVERITY_NORMAL,
$filename,
- $message['line']
+ (int)$message['line']
);
}
- $separator = str_repeat('-', 6) . ' ' . str_repeat('-', $len + 2) . PHP_EOL;
+ $separator = \str_repeat('-', 6) . ' ' . \str_repeat('-', $len + 2) . PHP_EOL;
- $this->builder->logFailure(vsprintf('%s Line %s' . PHP_EOL . '%s', [
+ $this->builder->logFailure(\vsprintf('%s Line %s' . PHP_EOL . '%s', [
$separator,
$file,
$separator . $out . $separator
@@ -116,7 +121,7 @@ public function execute()
if ($success) {
$this->builder->logSuccess('[OK] No errors');
} else {
- $this->builder->log(sprintf('[ERROR] Found %d errors', $total_errors));
+ $this->builder->log(\sprintf('[ERROR] Found %d errors', $total_errors));
}
return $success;
@@ -146,12 +151,12 @@ public static function canExecuteOnStage($stage, Build $build)
*/
protected function processReport($output)
{
- $data = json_decode(trim($output), true);
+ $data = \json_decode(\trim($output), true);
$totalErrors = 0;
$files = [];
- if (!empty($data) && is_array($data) && (0 < $data['totals']['file_errors'])) {
+ if (!empty($data) && \is_array($data) && (0 < $data['totals']['file_errors'])) {
$totalErrors = $data['totals']['file_errors'];
$files = $data['files'];
}
diff --git a/src/Plugin/PhpTalLint.php b/src/Plugin/PhpTalLint.php
index 7d2d43a9e..61e549fdd 100644
--- a/src/Plugin/PhpTalLint.php
+++ b/src/Plugin/PhpTalLint.php
@@ -11,7 +11,11 @@
/**
* PHPTAL Lint Plugin - Provides access to PHPTAL lint functionality.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Stephen Ball
+ * @author Dmitry Khomutov
*/
class PhpTalLint extends Plugin
{
@@ -49,11 +53,11 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- if (!empty($options['allowed_errors']) && is_int($options['allowed_errors'])) {
+ if (!empty($options['allowed_errors']) && \is_int($options['allowed_errors'])) {
$this->allowedErrors = $options['allowed_errors'];
}
- if (!empty($options['allowed_warnings']) && is_int($options['allowed_warnings'])) {
+ if (!empty($options['allowed_warnings']) && \is_int($options['allowed_warnings'])) {
$this->allowedWarnings = $options['allowed_warnings'];
}
@@ -73,7 +77,7 @@ public function execute()
$warnings = 0;
foreach ($this->failedPaths as $path) {
- if ($path['type'] == 'error') {
+ if ($path['type'] === 'error') {
$errors++;
} else {
$warnings++;
@@ -105,7 +109,7 @@ protected function lintItem($item, $itemPath)
{
$success = true;
- if ($item->isFile() && in_array(strtolower($item->getExtension()), $this->suffixes, true)) {
+ if ($item->isFile() && \in_array(\strtolower($item->getExtension()), $this->suffixes, true)) {
if (!$this->lintFile($itemPath)) {
$success = false;
}
@@ -132,7 +136,7 @@ protected function lintDirectory($path)
$itemPath = $path . $item->getFilename();
- if (in_array($itemPath, $this->ignore, true)) {
+ if (\in_array($itemPath, $this->ignore, true)) {
continue;
}
@@ -162,8 +166,8 @@ protected function lintFile($path)
$output = $this->builder->getLastOutput();
- if (preg_match('/Found (.+?) (error|warning)/i', $output, $matches)) {
- $rows = explode(PHP_EOL, $output);
+ if (\preg_match('/Found (.+?) (error|warning)/i', $output, $matches)) {
+ $rows = \explode(PHP_EOL, $output);
unset($rows[0]);
unset($rows[1]);
@@ -171,15 +175,15 @@ protected function lintFile($path)
unset($rows[3]);
foreach ($rows as $row) {
- $name = basename($path);
+ $name = \basename($path);
- $row = str_replace('(use -i to include your custom modifier functions)', '', $row);
- $message = str_replace($name . ': ', '', $row);
+ $row = \str_replace('(use -i to include your custom modifier functions)', '', $row);
+ $message = \str_replace($name . ': ', '', $row);
- $parts = explode(' (line ', $message);
+ $parts = \explode(' (line ', $message);
- $message = trim($parts[0]);
- $line = str_replace(')', '', $parts[1]);
+ $message = \trim($parts[0]);
+ $line = \str_replace(')', '', $parts[1]);
$this->failedPaths[] = [
'file' => $path,
diff --git a/src/Plugin/PhpUnit.php b/src/Plugin/PhpUnit.php
index 8b741f949..aa8aad285 100644
--- a/src/Plugin/PhpUnit.php
+++ b/src/Plugin/PhpUnit.php
@@ -5,7 +5,6 @@
use Exception;
use PHPCensor;
use PHPCensor\Builder;
-use PHPCensor\Config;
use PHPCensor\Model\Build;
use PHPCensor\Model\BuildError;
use PHPCensor\Plugin;
@@ -14,12 +13,17 @@
use PHPCensor\Plugin\Util\PhpUnitResultJunit;
use PHPCensor\ZeroConfigPluginInterface;
use Symfony\Component\Filesystem\Filesystem;
+use PHPCensor\Common\Exception\RuntimeException;
/**
* PHP Unit Plugin - A rewrite of the original PHP Unit plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dan Cryer
* @author Pablo Tejada
+ * @author Dmitry Khomutov
*/
class PhpUnit extends Plugin implements ZeroConfigPluginInterface
{
@@ -79,7 +83,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->buildLocation = PUBLIC_DIR . 'artifacts/phpunit/' . $this->buildDirectory;
$this->buildBranchLocation = PUBLIC_DIR . 'artifacts/phpunit/' . $this->buildBranchDirectory;
- $this->options = new PhpUnitOptions($options, $this->buildLocation);
+ $this->options = new PhpUnitOptions($this->builder->getConfiguration(), $options, $this->buildLocation);
$this->executable = $this->findBinary(['phpunit', 'phpunit.phar']);
}
@@ -89,7 +93,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
*/
public static function canExecuteOnStage($stage, Build $build)
{
- if (Build::STAGE_TEST === $stage && !is_null(PhpUnitOptions::findConfigFile($build->getBuildPath()))) {
+ if (Build::STAGE_TEST === $stage && !\is_null(PhpUnitOptions::findConfigFile($build->getBuildPath()))) {
return true;
}
@@ -112,8 +116,8 @@ public function execute()
}
$cmd = $this->executable;
- $lastLine = exec($cmd . ' --log-json . --version');
- if (false !== strpos($lastLine, '--log-json')) {
+ $lastLine = \exec($cmd . ' --log-json . --version');
+ if (false !== \strpos($lastLine, '--log-json')) {
$logFormat = 'junit'; // --log-json is not supported
} else {
$logFormat = 'json';
@@ -135,7 +139,7 @@ public function execute()
}
}
- return !in_array(false, $success, true);
+ return !\in_array(false, $success, true);
}
/**
@@ -151,7 +155,7 @@ public function execute()
*/
protected function runConfig($directory, $configFile, $logFormat)
{
- $allowPublicArtifacts = (bool)Config::getInstance()->get(
+ $allowPublicArtifacts = (bool)$this->builder->getConfiguration()->get(
'php-censor.build.allow_public_artifacts',
false
);
@@ -162,7 +166,7 @@ protected function runConfig($directory, $configFile, $logFormat)
$buildPath = $this->build->getBuildPath();
// Save the results into a log file
- $logFile = tempnam(sys_get_temp_dir(), 'jlog_');
+ $logFile = \tempnam(\sys_get_temp_dir(), 'jlog_');
$options->addArgument('log-' . $logFormat, $logFile);
// Removes any current configurations files
@@ -174,19 +178,24 @@ protected function runConfig($directory, $configFile, $logFormat)
if ($options->getOption('coverage') && $allowPublicArtifacts) {
if (!$fileSystem->exists($this->buildLocation)) {
- $fileSystem->mkdir($this->buildLocation, (0777 & ~umask()));
+ $fileSystem->mkdir($this->buildLocation, (0777 & ~\umask()));
}
- if (!is_writable($this->buildLocation)) {
- throw new Exception(sprintf(
+ if (!\is_writable($this->buildLocation)) {
+ throw new RuntimeException(\sprintf(
'The location %s is not writable or does not exist.',
$this->buildLocation
));
}
}
- $arguments = $this->builder->interpolate($options->buildArgumentString());
+ $arguments = $this->builder->interpolate($options->buildArgumentString(), true);
$cmd = $this->executable . ' %s %s';
+
+ if ($options->getOption('coverage')) {
+ $cmd = 'XDEBUG_MODE=coverage ' . $cmd;
+ }
+
$success = $this->executePhpUnitCommand($cmd, $arguments, $directory);
$output = $this->builder->getLastOutput();
$covHtmlOk = false;
@@ -208,7 +217,7 @@ protected function runConfig($directory, $configFile, $logFormat)
if ($covHtmlOk) {
$this->builder->logSuccess(
- sprintf(
+ \sprintf(
"\nPHPUnit successful build coverage report.\nYou can use coverage report for this build: %s\nOr coverage report for last build in the branch: %s",
APP_URL . 'artifacts/phpunit/' . $this->buildDirectory . '/index.html',
APP_URL . 'artifacts/phpunit/' . $this->buildBranchDirectory . '/index.html'
@@ -216,7 +225,7 @@ protected function runConfig($directory, $configFile, $logFormat)
);
} elseif ($allowPublicArtifacts) {
$this->builder->logFailure(
- sprintf(
+ \sprintf(
"\nPHPUnit could not build coverage report.\nmissing: %s\nlast of this branch: %s",
APP_URL . 'artifacts/phpunit/' . $this->buildDirectory . '/index.html',
APP_URL . 'artifacts/phpunit/' . $this->buildBranchDirectory . '/index.html'
@@ -239,7 +248,7 @@ protected function runConfig($directory, $configFile, $logFormat)
*/
protected function extractCoverage($output)
{
- preg_match(
+ \preg_match(
'#Classes:[\s]*(.*?)%[^M]*?Methods:[\s]*(.*?)%[^L]*?Lines:[\s]*(.*?)\%#s',
$output,
$matches
@@ -274,8 +283,8 @@ protected function executePhpUnitCommand($cmd, $arguments, $directory)
protected function checkRequiredCoverage($coverage)
{
foreach ($coverage as $key => $currentValue) {
- if ($requiredValue = $this->options->getOption(implode('_', ['required', $key, 'coverage']))) {
- if (bccomp($requiredValue, $currentValue) === 1) {
+ if ($requiredValue = $this->options->getOption(\implode('_', ['required', $key, 'coverage']))) {
+ if (\bccomp($requiredValue, $currentValue) === 1) {
return false;
}
}
@@ -294,7 +303,7 @@ protected function checkRequiredCoverage($coverage)
*/
protected function processResults($logFile, $logFormat)
{
- if (file_exists($logFile)) {
+ if (\file_exists($logFile)) {
if ('json' === $logFormat) {
$parser = new PhpUnitResultJson($logFile, $this->build->getBuildPath());
} else {
@@ -305,22 +314,22 @@ protected function processResults($logFile, $logFormat)
$this->build->storeMeta((self::pluginName() . '-errors'), $parser->getFailures());
foreach ($parser->getErrors() as $error) {
- $severity = $error['severity'] ==
- $parser::SEVERITY_ERROR ?
- BuildError::SEVERITY_CRITICAL :
- BuildError::SEVERITY_HIGH;
+ $severity = $error['severity'] === $parser::SEVERITY_ERROR
+ ? BuildError::SEVERITY_CRITICAL
+ : BuildError::SEVERITY_HIGH;
+
$this->build->reportError(
$this->builder,
self::pluginName(),
$error['message'],
$severity,
$error['file'],
- $error['line']
+ (int)$error['line']
);
}
- unlink($logFile);
+ \unlink($logFile);
} else {
- throw new Exception('log output file does not exist: ' . $logFile);
+ throw new RuntimeException('log output file does not exist: ' . $logFile);
}
}
}
diff --git a/src/Plugin/Psalm.php b/src/Plugin/Psalm.php
index 0b5d8ef05..257add7d7 100644
--- a/src/Plugin/Psalm.php
+++ b/src/Plugin/Psalm.php
@@ -11,6 +11,11 @@
/**
* A static analysis tool for finding errors in PHP applications https://getpsalm.org
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Psalm extends Plugin
{
@@ -29,13 +34,13 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->executable = $this->findBinary(['psalm', 'psalm.phar']);
- if (isset($options['allowed_errors']) && is_int($options['allowed_errors'])) {
+ if (isset($options['allowed_errors']) && \is_int($options['allowed_errors'])) {
$this->allowedErrors = $options['allowed_errors'];
} else {
$this->allowedErrors = 0;
}
- if (isset($options['allowed_warnings']) && is_int($options['allowed_warnings'])) {
+ if (isset($options['allowed_warnings']) && \is_int($options['allowed_warnings'])) {
$this->allowedWarnings = $options['allowed_warnings'];
} else {
$this->allowedWarnings = 0;
@@ -61,8 +66,8 @@ public function execute()
list($errors, $infos) = $this->processReport($this->builder->getLastOutput());
- if (0 < count($errors)) {
- if (-1 !== $this->allowedErrors && count($errors) > $this->allowedErrors) {
+ if (0 < \count($errors)) {
+ if (-1 !== $this->allowedErrors && \count($errors) > $this->allowedErrors) {
$success = false;
}
@@ -75,14 +80,14 @@ public function execute()
$error['message'],
BuildError::SEVERITY_HIGH,
$error['file'],
- $error['line_from'],
- $error['line_to']
+ (int)$error['line_from'],
+ (int)$error['line_to']
);
}
}
- if (0 < count($infos)) {
- if (-1 !== $this->allowedWarnings && count($infos) > $this->allowedWarnings) {
+ if (0 < \count($infos)) {
+ if (-1 !== $this->allowedWarnings && \count($infos) > $this->allowedWarnings) {
$success = false;
}
@@ -95,8 +100,8 @@ public function execute()
$info['message'],
BuildError::SEVERITY_LOW,
$info['file'],
- $info['line_from'],
- $info['line_to']
+ (int)$info['line_from'],
+ (int)$info['line_to']
);
}
}
@@ -122,19 +127,19 @@ public static function pluginName()
*/
protected function processReport($output)
{
- $data = json_decode(trim($output), true);
+ $data = \json_decode(\trim($output), true);
$errors = [];
$infos = [];
- if (!empty($data) && is_array($data)) {
+ if (!empty($data) && \is_array($data)) {
foreach ($data as $value) {
- if (!in_array($value['severity'], ['error','info'], true)) {
+ if (!\in_array($value['severity'], ['error','info'], true)) {
continue;
}
${$value['severity'].'s'}[] = [
- 'full_message' => vsprintf('%s - %s:%d:%d - %s' . PHP_EOL . '%s', [
+ 'full_message' => \vsprintf('%s - %s:%d:%d - %s' . PHP_EOL . '%s', [
$value['type'],
$value['file_name'],
$value['line_from'],
diff --git a/src/Plugin/SecurityChecker.php b/src/Plugin/SecurityChecker.php
index 53fc786b7..53bfeebe2 100644
--- a/src/Plugin/SecurityChecker.php
+++ b/src/Plugin/SecurityChecker.php
@@ -8,10 +8,14 @@
use PHPCensor\Model\BuildError;
use PHPCensor\Plugin;
use PHPCensor\ZeroConfigPluginInterface;
+use PHPCensor\Common\Exception\RuntimeException;
/**
* SensioLabs Security Checker Plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dmitry Khomutov
*/
class SecurityChecker extends Plugin implements ZeroConfigPluginInterface
@@ -19,7 +23,7 @@ class SecurityChecker extends Plugin implements ZeroConfigPluginInterface
/**
* @var int
*/
- protected $allowedWarnings;
+ protected $allowedWarnings = 0;
/**
* @var string
@@ -49,8 +53,6 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->allowedWarnings = 0;
-
if (isset($options['zero_config']) && $options['zero_config']) {
$this->allowedWarnings = -1;
}
@@ -74,7 +76,7 @@ public static function canExecuteOnStage($stage, Build $build)
{
$path = $build->getBuildPath() . 'composer.lock';
- if (file_exists($path) && $stage === Build::STAGE_TEST) {
+ if (\file_exists($path) && $stage === Build::STAGE_TEST) {
return true;
}
@@ -85,7 +87,7 @@ public function execute()
{
$composerLockFile = $this->builder->buildPath . 'composer.lock';
if (!\is_file($composerLockFile)) {
- throw new \RuntimeException('Lock file does not exist.');
+ throw new RuntimeException('Lock file does not exist.');
}
if ('symfony' === $this->binaryType) {
@@ -107,7 +109,7 @@ public function execute()
$builder->logExecOutput(true);
$success = true;
- $result = (string)$builder->getLastOutput();
+ $result = $builder->getLastOutput();
$warnings = \json_decode($result, true);
if ($warnings) {
@@ -117,18 +119,16 @@ public function execute()
$this->builder,
self::pluginName(),
$library . ' (' . $warning['version'] . ")\n" . $data['cve'] . ': ' . $data['title'] . "\n" . $data['link'],
- BuildError::SEVERITY_CRITICAL,
- '-',
- '-'
+ BuildError::SEVERITY_CRITICAL
);
}
}
- if ($this->allowedWarnings != -1 && (\count($warnings) > $this->allowedWarnings)) {
+ if ($this->allowedWarnings !== -1 && (\count($warnings) > $this->allowedWarnings)) {
$success = false;
}
} elseif (null === $warnings && $result) {
- throw new \RuntimeException('invalid json: '.$result);
+ throw new RuntimeException('invalid json: '.$result);
}
return $success;
diff --git a/src/Plugin/SensiolabsInsight.php b/src/Plugin/SensiolabsInsight.php
index ab79cb690..4bd7790c0 100644
--- a/src/Plugin/SensiolabsInsight.php
+++ b/src/Plugin/SensiolabsInsight.php
@@ -7,12 +7,16 @@
use PHPCensor\Builder;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
-use RuntimeException;
+use PHPCensor\Common\Exception\RuntimeException;
/**
* Sensiolabs Insight Plugin - Allows Sensiolabs Insight testing.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Eugen Ganshorn
+ * @author Dmitry Khomutov
*/
class SensiolabsInsight extends Plugin
{
@@ -34,7 +38,7 @@ class SensiolabsInsight extends Plugin
/**
* @var int
*/
- protected $allowedWarnings;
+ protected $allowedWarnings = 0;
/**
* @return string
@@ -50,21 +54,19 @@ public static function pluginName()
public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
-
- $this->allowedWarnings = 0;
- if (array_key_exists('allowed_warnings', $options)) {
+ if (\array_key_exists('allowed_warnings', $options)) {
$this->allowedWarnings = (int)$options['allowed_warnings'];
}
- if (array_key_exists('user_uuid', $options)) {
+ if (\array_key_exists('user_uuid', $options)) {
$this->userUuid = $options['user_uuid'];
}
if (\array_key_exists('auth_token', $options)) {
- $this->authToken = $options['auth_token'];
+ $this->authToken = $this->builder->interpolate($options['auth_token'], true);
}
- if (array_key_exists('project_uuid', $options)) {
+ if (\array_key_exists('project_uuid', $options)) {
$this->projectUuid = $options['project_uuid'];
}
@@ -82,7 +84,7 @@ public function execute()
$this->executeSensiolabsInsight($insightBinaryPath);
- $errorCount = $this->processReport(trim($this->builder->getLastOutput()));
+ $errorCount = $this->processReport(\trim($this->builder->getLastOutput()));
$this->build->storeMeta((self::pluginName() . '-warnings'), $errorCount);
return $this->wasLastExecSuccessful($errorCount);
@@ -98,7 +100,7 @@ public function execute()
*/
protected function processReport($xmlString)
{
- $xml = simplexml_load_string($xmlString);
+ $xml = \simplexml_load_string($xmlString);
if ($xml === false) {
$this->builder->log($xmlString);
@@ -110,7 +112,7 @@ protected function processReport($xmlString)
foreach ($xml->file as $file) {
$fileName = (string)$file['name'];
- $fileName = str_replace($this->builder->buildPath, '', $fileName);
+ $fileName = \str_replace($this->builder->buildPath, '', $fileName);
foreach ($file->violation as $violation) {
$warnings++;
@@ -166,14 +168,10 @@ protected function executeSensiolabsInsight($binaryPath)
*/
protected function wasLastExecSuccessful($errorCount)
{
- $success = true;
-
if ($this->allowedWarnings !== -1 && $errorCount > $this->allowedWarnings) {
- $success = false;
-
- return $success;
+ return false;
}
- return $success;
+ return true;
}
}
diff --git a/src/Plugin/Shell.php b/src/Plugin/Shell.php
index ba6e260a0..debc07193 100644
--- a/src/Plugin/Shell.php
+++ b/src/Plugin/Shell.php
@@ -9,7 +9,11 @@
/**
* Shell Plugin - Allows execute shell commands.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Kinn Coelho Julião
+ * @author Dmitry Khomutov
*/
class Shell extends Plugin
{
@@ -35,11 +39,11 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- if (array_key_exists('execute_all', $options) && $options['execute_all']) {
+ if (\array_key_exists('execute_all', $options) && $options['execute_all']) {
$this->executeAll = true;
}
- if (isset($options['commands']) && is_array($options['commands'])) {
+ if (isset($options['commands']) && \is_array($options['commands'])) {
$this->commands = $options['commands'];
return;
diff --git a/src/Plugin/SlackNotify.php b/src/Plugin/SlackNotify.php
index 5b4abbb94..0b69bf9ae 100644
--- a/src/Plugin/SlackNotify.php
+++ b/src/Plugin/SlackNotify.php
@@ -2,18 +2,22 @@
namespace PHPCensor\Plugin;
-use Exception;
use Maknz\Slack\Attachment;
use Maknz\Slack\AttachmentField;
use Maknz\Slack\Client;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\InvalidArgumentException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
/**
* Slack Plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Stephen Ball
+ * @author Dmitry Khomutov
*/
class SlackNotify extends Plugin
{
@@ -39,8 +43,8 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- if (is_array($options) && isset($options['webhook_url'])) {
- $this->webHook = trim($options['webhook_url']);
+ if (\is_array($options) && isset($options['webhook_url'])) {
+ $this->webHook = \trim($options['webhook_url']);
if (isset($options['message'])) {
$this->message = $options['message'];
@@ -72,7 +76,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->icon = $options['icon'];
}
} else {
- throw new Exception('Please define the webhook_url for slack_notify plugin!');
+ throw new InvalidArgumentException('Please define the webhook_url for slack_notify plugin!');
}
}
diff --git a/src/Plugin/Sqlite.php b/src/Plugin/Sqlite.php
index 5b9d41ed4..9da80f889 100644
--- a/src/Plugin/Sqlite.php
+++ b/src/Plugin/Sqlite.php
@@ -11,6 +11,9 @@
/**
* SQLite Plugin — Provides access to a SQLite database.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Dmitry Khomutov
*/
class Sqlite extends Plugin
@@ -62,7 +65,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
if (!empty($this->options['queries']) && \is_array($this->options['queries'])) {
foreach ($this->options['queries'] as $query) {
- $this->queries[] = $this->builder->interpolate($query);
+ $this->queries[] = $this->builder->interpolate($query, true);
}
}
}
@@ -74,7 +77,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
public function execute()
{
try {
- $pdoOptions = array_merge([
+ $pdoOptions = \array_merge([
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
], $this->pdoOptions);
@@ -83,7 +86,7 @@ public function execute()
foreach ($this->queries as $query) {
$pdo->query($query);
}
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$this->builder->logFailure($ex->getMessage());
return false;
diff --git a/src/Plugin/TechnicalDebt.php b/src/Plugin/TechnicalDebt.php
index 41ed031a5..8c19f77ec 100644
--- a/src/Plugin/TechnicalDebt.php
+++ b/src/Plugin/TechnicalDebt.php
@@ -14,24 +14,28 @@
/**
* Technical Debt Plugin - Checks for existence of "TODO", "FIXME", etc.
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author James Inman
+ * @author Dmitry Khomutov
*/
class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface
{
/**
* @var array
*/
- protected $suffixes;
+ protected $suffixes = ['php'];
/**
* @var int
*/
- protected $allowedErrors;
+ protected $allowedErrors = 0;
/**
* @var array - terms to search for
*/
- protected $searches;
+ protected $searches = ['TODO', 'FIXME', 'TO DO', 'FIX ME'];
/**
* @var array - lines of . and X to visualize errors
@@ -96,10 +100,10 @@ protected function returnResult()
$string = '';
$fileNumber = 0;
foreach ($this->errorPerFile as $oneLine) {
- $fileNumber += strlen($oneLine);
- $string .= str_pad($oneLine, 60, ' ', STR_PAD_RIGHT);
- $string .= str_pad($fileNumber, 4, ' ', STR_PAD_LEFT);
- $string .= "/" . $this->numberOfAnalysedFile . " (" . floor($fileNumber * 100 / $this->numberOfAnalysedFile) . " %)\n";
+ $fileNumber += \strlen($oneLine);
+ $string .= \str_pad($oneLine, 60, ' ', STR_PAD_RIGHT);
+ $string .= \str_pad($fileNumber, 4, ' ', STR_PAD_LEFT);
+ $string .= "/" . $this->numberOfAnalysedFile . " (" . \floor($fileNumber * 100 / $this->numberOfAnalysedFile) . " %)\n";
}
$string .= "Checked {$fileNumber} files\n";
@@ -113,15 +117,11 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->suffixes = ['php'];
- $this->allowedErrors = 0;
- $this->searches = ['TODO', 'FIXME', 'TO DO', 'FIX ME'];
-
- if (!empty($options['suffixes']) && is_array($options['suffixes'])) {
+ if (!empty($options['suffixes']) && \is_array($options['suffixes'])) {
$this->suffixes = $options['suffixes'];
}
- if (!empty($options['searches']) && is_array($options['searches'])) {
+ if (!empty($options['searches']) && \is_array($options['searches'])) {
$this->searches = $options['searches'];
}
@@ -129,7 +129,7 @@ public function __construct(Builder $builder, Build $build, array $options = [])
$this->allowedErrors = -1;
}
- if (array_key_exists('allowed_errors', $options) && $options['allowed_errors']) {
+ if (\array_key_exists('allowed_errors', $options) && $options['allowed_errors']) {
$this->allowedErrors = (int)$options['allowed_errors'];
}
}
@@ -154,7 +154,7 @@ public function execute()
$success = true;
$errorCount = $this->getErrorList();
- $this->builder->log($this->returnResult() . "Found $errorCount instances of " . implode(', ', $this->searches));
+ $this->builder->log($this->returnResult() . "Found $errorCount instances of " . \implode(', ', $this->searches));
$this->build->storeMeta((self::pluginName() . '-warnings'), $errorCount);
@@ -175,7 +175,7 @@ protected function getErrorList()
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->directory));
$this->builder->logDebug("Directory: " . $this->directory);
- $this->builder->logDebug("Ignored path: ".json_encode($this->ignore, true));
+ $this->builder->logDebug("Ignored path: " . \json_encode($this->ignore, true));
$errorCount = 0;
/** @var SplFileInfo $file */
@@ -187,6 +187,7 @@ protected function getErrorList()
foreach ($this->suffixes as $suffix) {
if ($suffix !== $extension) {
$ignored = true;
+
break;
}
}
@@ -195,23 +196,24 @@ protected function getErrorList()
$ignoreAbsolute = $this->builder->buildPath . $ignore;
if ('/' === $ignoreAbsolute[0]) {
- if (0 === strpos($filePath, $ignoreAbsolute)) {
+ if (0 === \strpos($filePath, $ignoreAbsolute)) {
$ignored = true;
+
break;
}
}
}
if (!$ignored) {
- $handle = fopen($filePath, "r");
+ $handle = \fopen($filePath, "r");
$lineNumber = 1;
$errorInFile = false;
- while (false === feof($handle)) {
- $line = fgets($handle);
+ while (false === \feof($handle)) {
+ $line = \fgets($handle);
foreach ($this->searches as $search) {
- if ($technicalDebtLine = trim(strstr($line, $search))) {
- $fileName = str_replace($this->directory, '', $filePath);
+ if ($technicalDebtLine = \trim(\strstr($line, $search))) {
+ $fileName = \str_replace($this->directory, '', $filePath);
$this->build->reportError(
$this->builder,
@@ -228,7 +230,7 @@ protected function getErrorList()
}
$lineNumber++;
}
- fclose($handle);
+ \fclose($handle);
if ($errorInFile === true) {
$this->buildLogString('X');
diff --git a/src/Plugin/TelegramNotify.php b/src/Plugin/TelegramNotify.php
index d6ddc100f..dbbb0bb58 100644
--- a/src/Plugin/TelegramNotify.php
+++ b/src/Plugin/TelegramNotify.php
@@ -5,13 +5,18 @@
use Exception;
use GuzzleHttp\Client;
use PHPCensor\Builder;
+use PHPCensor\Common\Exception\InvalidArgumentException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
/**
* Telegram Plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author LEXASOFT
+ * @author Dmitry Khomutov
*/
class TelegramNotify extends Plugin
{
@@ -38,16 +43,16 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- if (empty($options['auth_token']) && empty($options['api_key'])) {
- throw new Exception("Not setting telegram 'auth_token'");
+ if (empty($options['auth_token'])) {
+ throw new InvalidArgumentException("Not setting telegram 'auth_token'");
}
if (empty($options['recipients'])) {
- throw new Exception("Not setting recipients");
+ throw new InvalidArgumentException("Not setting recipients");
}
if (\array_key_exists('auth_token', $options)) {
- $this->authToken = $options['auth_token'];
+ $this->authToken = $this->builder->interpolate($options['auth_token'], true);
}
$this->message = '[%ICON_BUILD%] [%PROJECT_TITLE%](%PROJECT_LINK%)' .
@@ -60,9 +65,9 @@ public function __construct(Builder $builder, Build $build, array $options = [])
}
$this->recipients = [];
- if (is_string($options['recipients'])) {
+ if (\is_string($options['recipients'])) {
$this->recipients = [$options['recipients']];
- } elseif (is_array($options['recipients'])) {
+ } elseif (\is_array($options['recipients'])) {
$this->recipients = $options['recipients'];
}
@@ -77,14 +82,22 @@ public function execute()
{
$message = $this->buildMessage();
$client = new Client();
- $url = '/bot'. $this->authToken . '/sendMessage';
+ $url = '/bot' . $this->authToken . '/sendMessage';
foreach ($this->recipients as $chatId) {
+ $chatId = $this->builder->interpolate($chatId, true);
+ [$chatId, $topicId] = $this->splitChatIdAndTopicId($chatId);
+
$params = [
'chat_id' => $chatId,
'text' => $message,
'parse_mode' => 'Markdown',
];
+
+ if ($topicId !== null) {
+ $params['message_thread_id'] = $topicId;
+ }
+
$client->post(('https://api.telegram.org' . $url), [
'headers' => [
'Content-Type' => 'application/json',
@@ -98,6 +111,11 @@ public function execute()
'text' => $this->buildMsg,
'parse_mode' => 'Markdown',
];
+
+ if ($topicId !== null) {
+ $params['message_thread_id'] = $topicId;
+ }
+
$client->post(('https://api.telegram.org' . $url), [
'headers' => [
'Content-Type' => 'application/json',
@@ -119,22 +137,36 @@ private function buildMessage()
$this->buildMsg = '';
$buildIcon = $this->build->isSuccessful() ? '✅' : '❌';
$buildLog = $this->build->getLog();
- $buildLog = str_replace(['[0;32m', '[0;31m', '[0m', '/[0m'], '', $buildLog);
- $buildMessages = explode('RUNNING PLUGIN: ', $buildLog);
+ $buildLog = \str_replace(['[0;32m', '[0;31m', '[0m', '/[0m'], '', $buildLog);
+ $buildMessages = \explode('RUNNING PLUGIN: ', $buildLog);
foreach ($buildMessages as $bm) {
- $pos = mb_strpos($bm, "\n");
- $firstRow = mb_substr($bm, 0, $pos);
+ $pos = \mb_strpos($bm, "\n");
+ $firstRow = \mb_substr($bm, 0, $pos);
//skip long outputs
- if (in_array($firstRow, ['slack_notify', 'php_loc', 'telegram_notify'], true)) {
+ if (\in_array($firstRow, ['slack_notify', 'php_loc', 'telegram_notify'], true)) {
continue;
}
$this->buildMsg .= '*RUNNING PLUGIN: ' . $firstRow . "*\n";
- $this->buildMsg .= $firstRow == 'composer' ? '' : ('```' . mb_substr($bm, $pos) . '```');
+ $this->buildMsg .= $firstRow === 'composer' ? '' : ('```' . \mb_substr($bm, $pos) . '```');
}
- return $this->builder->interpolate(str_replace(['%ICON_BUILD%'], [$buildIcon], $this->message));
+ return $this->builder->interpolate(\str_replace(['%ICON_BUILD%'], [$buildIcon], $this->message));
+ }
+
+ /**
+ * Split chat group id to chat id and topic id
+ *
+ * @param int|string $chatId
+ * @return array{string, string|null}
+ */
+ protected function splitChatIdAndTopicId($chatId)
+ {
+ $parts = \explode('/', \trim((string) $chatId) . '/');
+ $topicId = $parts[1] !== '' ? $parts[1] : null;
+
+ return [$parts[0], $topicId];
}
}
diff --git a/src/Plugin/Util/BitbucketNotifyPhpUnitResult.php b/src/Plugin/Util/BitbucketNotifyPhpUnitResult.php
index e5352d5ac..b30f70738 100644
--- a/src/Plugin/Util/BitbucketNotifyPhpUnitResult.php
+++ b/src/Plugin/Util/BitbucketNotifyPhpUnitResult.php
@@ -2,6 +2,12 @@
namespace PHPCensor\Plugin\Util;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class BitbucketNotifyPhpUnitResult extends BitbucketNotifyPluginResult
{
public function __construct($plugin, $left, $right)
diff --git a/src/Plugin/Util/BitbucketNotifyPluginResult.php b/src/Plugin/Util/BitbucketNotifyPluginResult.php
index 2682b0104..8157dcdb6 100644
--- a/src/Plugin/Util/BitbucketNotifyPluginResult.php
+++ b/src/Plugin/Util/BitbucketNotifyPluginResult.php
@@ -2,6 +2,12 @@
namespace PHPCensor\Plugin\Util;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
+ */
class BitbucketNotifyPluginResult
{
public const DEFAULT_PLUGIN_OUTPUT_FORMAT = "%s | %d\t=> %d\t%s";
@@ -16,14 +22,13 @@ class BitbucketNotifyPluginResult
protected $right;
/** @var string $outputFormat */
- protected $outputFormat;
+ protected $outputFormat = self::DEFAULT_PLUGIN_OUTPUT_FORMAT;
public function __construct($plugin, $left, $right)
{
$this->plugin = $plugin;
$this->left = $left;
$this->right = $right;
- $this->outputFormat = self::DEFAULT_PLUGIN_OUTPUT_FORMAT;
}
public function getPlugin()
@@ -79,9 +84,9 @@ public function isUnchanged()
public function generateFormattedOutput($maxPluginNameLength)
{
- return trim(sprintf(
+ return \trim(\sprintf(
$this->outputFormat,
- str_pad($this->plugin, $maxPluginNameLength),
+ \str_pad($this->plugin, $maxPluginNameLength),
$this->left,
$this->right,
$this->generateComment()
@@ -94,7 +99,7 @@ public function generateTaskDescription()
return '';
}
- return sprintf(
+ return \sprintf(
$this->getTaskDescriptionMessage(),
$this->plugin,
$this->left,
diff --git a/src/Plugin/Util/Executor.php b/src/Plugin/Util/Executor.php
index 5f0d721c2..e4ff1b2ba 100644
--- a/src/Plugin/Util/Executor.php
+++ b/src/Plugin/Util/Executor.php
@@ -3,15 +3,21 @@
namespace PHPCensor\Plugin\Util;
use Exception;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Helper\Lang;
use PHPCensor\Logging\BuildLogger;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
use PHPCensor\Store\BuildStore;
-use PHPCensor\Store\Factory as StoreFactory;
+use PHPCensor\StoreRegistry;
/**
* Plugin Executor - Runs the configured plugins for a given build stage.
+ *
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Dmitry Khomutov
*/
class Executor
{
@@ -30,11 +36,18 @@ class Executor
*/
protected $store;
- public function __construct(Factory $pluginFactory, BuildLogger $logger, BuildStore $store = null)
- {
+ protected StoreRegistry $storeRegistry;
+
+ public function __construct(
+ StoreRegistry $storeRegistry,
+ Factory $pluginFactory,
+ BuildLogger $logger,
+ BuildStore $store = null
+ ) {
+ $this->storeRegistry = $storeRegistry;
$this->pluginFactory = $pluginFactory;
- $this->logger = $logger;
- $this->store = $store ?: StoreFactory::getStore('Build');
+ $this->logger = $logger;
+ $this->store = $store;
}
/**
@@ -51,7 +64,7 @@ public function executePlugins($config, $stage)
$pluginsToExecute = [];
// If we have global plugins to execute for this stage, add them to the list to be executed:
- if (array_key_exists($stage, $config) && is_array($config[$stage])) {
+ if (\array_key_exists($stage, $config) && \is_array($config[$stage])) {
$pluginsToExecute[] = $config[$stage];
}
@@ -74,17 +87,17 @@ public function executePlugins($config, $stage)
*/
public function getBranchSpecificConfig($config, $branch)
{
- $configSections = array_keys($config);
+ $configSections = \array_keys($config);
foreach ($configSections as $configSection) {
- if (0 === strpos($configSection, 'branch-')) {
+ if (0 === \strpos($configSection, 'branch-')) {
if ($configSection === ('branch-' . $branch)) {
return $config[$configSection];
}
- if (0 === strpos($configSection, 'branch-regex:')) {
- $pattern = '#' . substr($configSection, 13) . '#u';
- preg_match($pattern, $branch, $matches);
+ if (0 === \strpos($configSection, 'branch-regex:')) {
+ $pattern = '#' . \substr($configSection, 13) . '#u';
+ \preg_match($pattern, $branch, $matches);
if (!empty($matches[0])) {
return $config[$configSection];
}
@@ -106,8 +119,7 @@ public function getBranchSpecificConfig($config, $branch)
*/
protected function getBranchSpecificPlugins($config, $stage, $pluginsToExecute)
{
- /** @var Build $build */
- $build = $this->pluginFactory->getResourceFor('PHPCensor\Model\Build');
+ $build = $this->pluginFactory->getBuild();
$branch = $build->getBranch();
$branchConfig = $this->getBranchSpecificConfig($config, $branch);
if (!$branchConfig) {
@@ -126,20 +138,20 @@ protected function getBranchSpecificPlugins($config, $stage, $pluginsToExecute)
case 'replace':
$pluginsToExecute = [];
$pluginsToExecute[] = $plugins;
+
break;
// Run branch-specific plugins before standard plugins:
case 'before':
- array_unshift($pluginsToExecute, $plugins);
+ \array_unshift($pluginsToExecute, $plugins);
+
break;
// Run branch-specific plugins after standard plugins:
case 'after':
- array_push($pluginsToExecute, $plugins);
- break;
-
default:
- array_push($pluginsToExecute, $plugins);
+ \array_push($pluginsToExecute, $plugins);
+
break;
}
@@ -154,21 +166,24 @@ protected function getBranchSpecificPlugins($config, $stage, $pluginsToExecute)
protected function doExecutePlugins($plugins, $stage)
{
$success = true;
+ foreach ($plugins as $step => $options) {
+ $plugin = $step;
+ if (isset($options['plugin'])) {
+ $plugin = $options['plugin'];
+ }
- foreach ($plugins as $plugin => $options) {
$this->logger->log('');
$this->logger->logSuccess(
- sprintf('RUNNING PLUGIN: %s', Lang::get($plugin)) . ' (' .
- 'Stage' . ': ' . ucfirst($stage) . ')'
+ \sprintf('RUNNING PLUGIN: %s (Step: %s) (Stage: %s)', Lang::get($plugin), $step, \ucfirst($stage))
);
- $this->setPluginStatus($stage, $plugin, Plugin::STATUS_RUNNING);
+ $this->setPluginStatus($stage, $step, $plugin, Plugin::STATUS_RUNNING);
// Try and execute it
if ($this->executePlugin($plugin, $options)) {
// Execution was successful
$this->logger->logSuccess('PLUGIN: SUCCESS');
- $this->setPluginStatus($stage, $plugin, Plugin::STATUS_SUCCESS);
+ $this->setPluginStatus($stage, $step, $plugin, Plugin::STATUS_SUCCESS);
} else {
$status = Plugin::STATUS_FAILED;
@@ -177,7 +192,8 @@ protected function doExecutePlugins($plugins, $stage)
// If we're in the "setup" stage, execution should not continue after
// a plugin has failed:
- throw new Exception('Plugin failed: ' . $plugin);
+
+ throw new RuntimeException('Plugin failed: ' . $plugin . ' (Step: ' . $step . ')');
} elseif ($stage === Build::STAGE_DEPLOY) {
$this->logger->logFailure('PLUGIN: FAILED');
$success = false;
@@ -194,7 +210,7 @@ protected function doExecutePlugins($plugins, $stage)
}
}
- $this->setPluginStatus($stage, $plugin, $status);
+ $this->setPluginStatus($stage, $step, $plugin, $status);
}
}
@@ -207,13 +223,13 @@ protected function doExecutePlugins($plugins, $stage)
public function executePlugin($plugin, $options)
{
$class = $plugin;
- if (!class_exists($class)) {
- $class = str_replace('_', ' ', $plugin);
- $class = ucwords($class);
- $class = 'PHPCensor\\Plugin\\' . str_replace(' ', '', $class);
+ if (!\class_exists($class)) {
+ $class = \str_replace('_', ' ', $plugin);
+ $class = \ucwords($class);
+ $class = 'PHPCensor\Plugin\\' . \str_replace(' ', '', $class);
- if (!class_exists($class)) {
- $this->logger->logFailure(sprintf('Plugin does not exist: %s', $plugin));
+ if (!\class_exists($class)) {
+ $this->logger->logFailure(\sprintf('Plugin does not exist: %s', $plugin));
return false;
}
@@ -221,10 +237,11 @@ public function executePlugin($plugin, $options)
try {
// Build and run it
- $obj = $this->pluginFactory->buildPlugin($class, (is_null($options) ? [] : $options));
+ $obj = $this->pluginFactory->buildPlugin($class, (\is_null($options) ? [] : $options));
+ $obj->setStoreRegistry($this->storeRegistry);
return $obj->execute();
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$this->logger->logFailure('Exception: ' . $ex->getMessage(), $ex);
return false;
@@ -235,23 +252,26 @@ public function executePlugin($plugin, $options)
* Change the status of a plugin for a given stage.
*
* @param string $stage The builder stage.
+ * @param string $step The name of the step
* @param string $plugin The plugin name.
* @param int $status The new status.
*/
- protected function setPluginStatus($stage, $plugin, $status)
+ protected function setPluginStatus($stage, $step, $plugin, $status)
{
$summary = $this->getBuildSummary();
- if (!isset($summary[$stage][$plugin])) {
- $summary[$stage][$plugin] = [];
+ if (!isset($summary[$stage][$step])) {
+ $summary[$stage][$step] = [
+ 'plugin' => $plugin
+ ];
}
- $summary[$stage][$plugin]['status'] = $status;
+ $summary[$stage][$step]['status'] = $status;
if ($status === Plugin::STATUS_RUNNING) {
- $summary[$stage][$plugin]['started'] = time();
+ $summary[$stage][$step]['started'] = \time();
} elseif ($status >= Plugin::STATUS_SUCCESS) {
- $summary[$stage][$plugin]['ended'] = time();
+ $summary[$stage][$step]['ended'] = \time();
}
$this->setBuildSummary($summary);
@@ -264,8 +284,7 @@ protected function setPluginStatus($stage, $plugin, $status)
*/
private function getBuildSummary()
{
- /** @var Build $build */
- $build = $this->pluginFactory->getResourceFor('PHPCensor\Model\Build');
+ $build = $this->pluginFactory->getBuild();
$metas = $this->store->getMeta('plugin-summary', $build->getProjectId(), $build->getId());
return isset($metas[0]['meta_value']) ? $metas[0]['meta_value'] : [];
@@ -278,8 +297,7 @@ private function getBuildSummary()
*/
private function setBuildSummary($summary)
{
- /** @var Build $build */
- $build = $this->pluginFactory->getResourceFor('PHPCensor\Model\Build');
- $this->store->setMeta($build->getId(), 'plugin-summary', json_encode($summary));
+ $build = $this->pluginFactory->getBuild();
+ $this->store->setMeta($build->getId(), 'plugin-summary', \json_encode($summary));
}
}
diff --git a/src/Plugin/Util/Factory.php b/src/Plugin/Util/Factory.php
index 8d6dca903..e04210e0c 100644
--- a/src/Plugin/Util/Factory.php
+++ b/src/Plugin/Util/Factory.php
@@ -1,222 +1,40 @@
*/
class Factory
{
- public const TYPE_ARRAY = "array";
- public const TYPE_CALLABLE = "callable";
- public const INTERFACE_PLUGIN = '\PHPCensor\Plugin';
-
- private $currentPluginOptions;
-
- /**
- * @var Container
- */
- private $container;
-
- /**
- */
- public function __construct(Container $container = null)
- {
- if ($container) {
- $this->container = $container;
- } else {
- $this->container = new Container();
- }
- }
-
- /**
- * Trys to get a function from the file path specified. If the
- * file returns a function then $this will be passed to it.
- * This enables the config file to call any public methods.
- *
- * @return bool - true if the function exists else false.
- */
- public function addConfigFromFile($configPath)
- {
- // The file is expected to return a function which can
- // act on the pluginFactory to register any resources needed.
- if (file_exists($configPath)) {
- $configFunction = require($configPath);
- if (is_callable($configFunction)) {
- $configFunction($this);
-
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Get most recently used factory options.
- * @return mixed
- */
- public function getLastOptions()
- {
- return $this->currentPluginOptions;
- }
-
- /**
- * Builds an instance of plugin of class $className. $options will
- * be passed along with any resources registered with the factory.
- *
- * @param string $className
- * @param array|null $options
- *
- * @return Plugin
- */
- public function buildPlugin($className, $options = [])
- {
- $this->currentPluginOptions = $options;
-
- $reflectedPlugin = new ReflectionClass($className);
-
- $constructor = $reflectedPlugin->getConstructor();
+ private Builder $builder;
- if ($constructor) {
- $argsToUse = [];
- foreach ($constructor->getParameters() as $param) {
- if ('options' === $param->getName()) {
- $argsToUse[] = $options;
- } else {
- $argsToUse = $this->addArgFromParam($argsToUse, $param);
- }
- }
- /** @var Plugin $plugin */
- $plugin = $reflectedPlugin->newInstanceArgs($argsToUse);
- } else {
- /** @var Plugin $plugin */
- $plugin = $reflectedPlugin->newInstance();
- }
+ private Build $build;
- return $plugin;
- }
-
- /**
- * @param callable $loader
- * @param string|null $name
- * @param string|null $type
- *
- * @throws InvalidArgumentException
- *
- * @internal param mixed $resource
- */
- public function registerResource(
- $loader,
- $name = null,
- $type = null
+ public function __construct(
+ Builder $builder,
+ Build $build
) {
- if ($name === null && $type === null) {
- throw new InvalidArgumentException(
- "Type or Name must be specified"
- );
- }
-
- if (!($loader instanceof Closure)) {
- throw new InvalidArgumentException(
- '$loader is expected to be a function'
- );
- }
-
- $resourceID = $this->getInternalID($type, $name);
-
- $this->container[$resourceID] = $loader;
- }
-
- /**
- * Get an internal resource ID.
- * @param null $type
- * @param null $name
- * @return string
- */
- private function getInternalID($type = null, $name = null)
- {
- $type = $type ?: "";
- $name = $name ?: "";
-
- return $type . "-" . $name;
+ $this->builder = $builder;
+ $this->build = $build;
}
- /**
- * @param string $type
- * @param string $name
- * @return mixed
- */
- public function getResourceFor($type = null, $name = null)
+ public function buildPlugin(string $className, array $options = []): Plugin
{
- $fullId = $this->getInternalID($type, $name);
- if (isset($this->container[$fullId])) {
- return $this->container[$fullId];
- }
-
- $typeOnlyID = $this->getInternalID($type, null);
- if (isset($this->container[$typeOnlyID])) {
- return $this->container[$typeOnlyID];
- }
-
- $nameOnlyID = $this->getInternalID(null, $name);
- if (isset($this->container[$nameOnlyID])) {
- return $this->container[$nameOnlyID];
- }
-
- return null;
+ return new $className($this->builder, $this->build, $options);
}
- /**
- * @return string|null
- */
- private function getParamType(ReflectionParameter $param)
+ public function getBuild(): Build
{
- $class = $param->getType() && !$param->getType()->isBuiltin()
- ? new ReflectionClass($param->getType()->getName())
- : null;
-
- if ($class) {
- return $class->getName();
- } elseif ($param->getType() && $param->getType()->getName() === 'array') {
- return self::TYPE_ARRAY;
- } elseif (is_callable($param)) {
- return self::TYPE_CALLABLE;
- } else {
- return null;
- }
- }
-
- /**
- *
- * @return array
- *
- * @throws DomainException
- */
- private function addArgFromParam($existingArgs, ReflectionParameter $param)
- {
- $name = $param->getName();
- $type = $this->getParamType($param);
- $arg = $this->getResourceFor($type, $name);
-
- if ($arg !== null) {
- $existingArgs[] = $arg;
- } elseif ($arg === null && $param->isOptional()) {
- $existingArgs[] = $param->getDefaultValue();
- } else {
- throw new DomainException(
- "Unsatisfied dependency: " . $param->getName()
- );
- }
-
- return $existingArgs;
+ return $this->build;
}
}
diff --git a/src/Plugin/Util/PhpUnitResult.php b/src/Plugin/Util/PhpUnitResult.php
index a1832b4b7..e90788cb8 100644
--- a/src/Plugin/Util/PhpUnitResult.php
+++ b/src/Plugin/Util/PhpUnitResult.php
@@ -7,7 +7,11 @@
/**
* Class PhpUnitResult parses the results for the PhpUnitV2 plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Pablo Tejada
+ * @author Dmitry Khomutov
*/
abstract class PhpUnitResult
{
@@ -38,26 +42,23 @@ public function __construct($outputFile, $buildPath = '')
*/
abstract public function parse();
- abstract protected function getSeverity($testcase);
+ abstract protected function getSeverity($testCase);
- abstract protected function buildMessage($testcase);
+ abstract protected function buildMessage($testCase);
- abstract protected function buildTrace($testcase);
+ abstract protected function buildTrace($testCase);
- protected function getFileAndLine($testcase)
- {
- return $testcase;
- }
+ abstract protected function getFileAndLine($testCase);
- protected function getOutput($testcase)
+ protected function getOutput($testCase)
{
- return $testcase['output'];
+ return $testCase['output'];
}
protected function parseTestcase($testcase)
{
$severity = $this->getSeverity($testcase);
- $pass = isset(array_fill_keys([self::SEVERITY_PASS, self::SEVERITY_SKIPPED], true)[$severity]);
+ $pass = isset(\array_fill_keys([self::SEVERITY_PASS, self::SEVERITY_SKIPPED], true)[$severity]);
$data = [
'pass' => $pass,
'severity' => $severity,
diff --git a/src/Plugin/Util/PhpUnitResultJson.php b/src/Plugin/Util/PhpUnitResultJson.php
index 8b6c8a31e..da47d4088 100644
--- a/src/Plugin/Util/PhpUnitResultJson.php
+++ b/src/Plugin/Util/PhpUnitResultJson.php
@@ -3,11 +3,16 @@
namespace PHPCensor\Plugin\Util;
use Exception;
+use PHPCensor\Common\Exception\RuntimeException;
/**
* Class PhpUnitResult parses the results for the PhpUnitV2 plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Pablo Tejada
+ * @author Dmitry Khomutov
*/
class PhpUnitResultJson extends PhpUnitResult
{
@@ -26,14 +31,14 @@ class PhpUnitResultJson extends PhpUnitResult
*/
public function parse()
{
- $rawResults = file_get_contents($this->outputFile);
+ $rawResults = \file_get_contents($this->outputFile);
$events = [];
- if ($rawResults && $rawResults[0] == '{') {
- $fixedJson = '[' . str_replace('}{', '},{', $rawResults) . ']';
- $events = json_decode($fixedJson, true);
+ if ($rawResults && $rawResults[0] === '{') {
+ $fixedJson = '[' . \str_replace('}{', '},{', $rawResults) . ']';
+ $events = \json_decode($fixedJson, true);
} elseif ($rawResults) {
- $events = json_decode($rawResults, true);
+ $events = \json_decode($rawResults, true);
}
// Reset the parsing variables
@@ -44,10 +49,10 @@ public function parse()
if ($events) {
$started = null;
foreach ($events as $event) {
- if (isset($event['event']) && $event['event'] == self::EVENT_TEST) {
+ if (isset($event['event']) && $event['event'] === self::EVENT_TEST) {
$this->parseTestcase($event);
$started = null;
- } elseif (isset($event['event']) && $event['event'] == self::EVENT_TEST_START) {
+ } elseif (isset($event['event']) && $event['event'] === self::EVENT_TEST_START) {
$started = $event;
}
}
@@ -67,33 +72,34 @@ public function parse()
/**
* Build the severity of the event
*
+ * @param $testCase
*
* @return string The severity flags
* @throws Exception
*/
- protected function getSeverity($event)
+ protected function getSeverity($testCase)
{
- $status = $event['status'];
+ $status = $testCase['status'];
switch ($status) {
case 'fail':
$severity = self::SEVERITY_FAIL;
+
break;
case 'error':
- if (strpos($event['message'], 'Skipped') === 0 || strpos($event['message'], 'Incomplete') === 0) {
+ if (\strpos($testCase['message'], 'Skipped') === 0 || \strpos($testCase['message'], 'Incomplete') === 0) {
$severity = self::SEVERITY_SKIPPED;
} else {
$severity = self::SEVERITY_ERROR;
}
+
break;
case 'pass':
- $severity = self::SEVERITY_PASS;
- break;
case 'warning':
$severity = self::SEVERITY_PASS;
+
break;
default:
- throw new Exception("Unexpected PHPUnit test status: {$status}");
- break;
+ throw new RuntimeException("Unexpected PHPUnit test status: {$status}");
}
return $severity;
@@ -102,16 +108,16 @@ protected function getSeverity($event)
/**
* Build the message string for an event
*
- * @param array $event
+ * @param array $testCase
*
* @return string
*/
- protected function buildMessage($event)
+ protected function buildMessage($testCase)
{
- $message = $event['test'];
+ $message = $testCase['test'];
- if ($event['message']) {
- $message .= PHP_EOL . $event ['message'];
+ if ($testCase['message']) {
+ $message .= PHP_EOL . $testCase ['message'];
}
return $message;
@@ -120,17 +126,17 @@ protected function buildMessage($event)
/**
* Build a string base trace of the failure
*
- * @param array $event
+ * @param array $testCase
*
* @return string[]
*/
- protected function buildTrace($event)
+ protected function buildTrace($testCase)
{
$formattedTrace = [];
- if (!empty($event['trace'])) {
- foreach ($event['trace'] as $step) {
- $line = str_replace($this->buildPath, '', $step['file']) . ':' . $step['line'];
+ if (!empty($testCase['trace'])) {
+ foreach ($testCase['trace'] as $step) {
+ $line = \str_replace($this->buildPath, '', $step['file']) . ':' . $step['line'];
$formattedTrace[] = $line;
}
}
@@ -141,23 +147,23 @@ protected function buildTrace($event)
/**
* Saves additional info for a failing test
*
- * @param array $event
+ * @param array $testCase
*
* @return array
*/
- protected function getFileAndLine($event)
+ protected function getFileAndLine($testCase)
{
- if (empty($event['trace'])) {
+ if (empty($testCase['trace'])) {
return [
'file' => '',
'line' => '',
];
}
- $firstTrace = end($event['trace']);
- reset($event['trace']);
+ $firstTrace = \end($testCase['trace']);
+ \reset($testCase['trace']);
return [
- 'file' => str_replace($this->buildPath, '', $firstTrace['file']),
+ 'file' => \str_replace($this->buildPath, '', $firstTrace['file']),
'line' => $firstTrace['line']
];
}
diff --git a/src/Plugin/Util/PhpUnitResultJunit.php b/src/Plugin/Util/PhpUnitResultJunit.php
index f29a327aa..003ad5874 100644
--- a/src/Plugin/Util/PhpUnitResultJunit.php
+++ b/src/Plugin/Util/PhpUnitResultJunit.php
@@ -3,14 +3,18 @@
namespace PHPCensor\Plugin\Util;
use Exception;
+use PHPCensor\Common\Exception\RuntimeException;
use PHPCensor\Helper\Xml;
-use RuntimeException;
use SimpleXMLElement;
/**
* Class PhpUnitResultJunit parses the results for the PhpUnitV2 plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Simon Heimberg
+ * @author Dmitry Khomutov
*/
class PhpUnitResultJunit extends PhpUnitResult
{
@@ -45,20 +49,24 @@ protected function getSeverity($testCase)
switch ($child->getName()) {
case 'failure':
$severity = self::SEVERITY_FAIL;
+
break 2;
case 'error':
- if ('PHPUnit\Framework\RiskyTestError' == $child['type']) { // == because convertion to string is desired
+ if ('PHPUnit\Framework\RiskyTestError' === (string)$child['type']) { // == because conversion to string is desired
$severity = self::SEVERITY_RISKY;
} else {
$severity = self::SEVERITY_ERROR;
}
+
break 2;
case 'skipped':
// skipped and ignored, can not distinguish
$severity = self::SEVERITY_SKIPPED;
+
break 2;
case 'warning':
$severity = self::SEVERITY_WARN;
+
break 2;
case 'system-out':
case 'system-err':
@@ -66,6 +74,7 @@ protected function getSeverity($testCase)
continue 2;
default:
$severity = 'UNKNOWN RESULT TYPE: '.$child->getName();
+
break 2;
}
}
@@ -79,15 +88,15 @@ protected function buildMessage($testCase)
$msg = $this->getMessageTrace($testCase);
if ('' !== $msg) {
//strip trace
- $trPos = strrpos($msg, "\n\n");
+ $trPos = \strrpos($msg, "\n\n");
if (false !== $trPos) {
$tracePos = $trPos;
- $msg = substr($msg, 0, $trPos);
+ $msg = \substr($msg, 0, $trPos);
}
}
if ('' === $msg) {
$msg = $testCase['class'].'::'.$testCase['name'];
- };
+ }
$testCase['_tracePos'] = $tracePos; // will be converted to string
return $msg;
@@ -100,13 +109,13 @@ protected function getOutput($testCase)
protected function buildTrace($testCase)
{
- if (!is_int($testCase['_tracePos'])) {
+ if (!\is_int($testCase['_tracePos'])) {
$this->buildMessage($testCase);
}
if ($testCase['_tracePos'] >= 0) {
- $stackStr = substr($this->getMessageTrace($testCase), (int)$testCase['_tracePos'] + 2, -1);
- $trace = explode("\n", str_replace($this->buildPath, '.', $stackStr));
+ $stackStr = \substr($this->getMessageTrace($testCase), (int)$testCase['_tracePos'] + 2, -1);
+ $trace = \explode("\n", \str_replace($this->buildPath, '.', $stackStr));
} else {
$trace = [];
}
@@ -128,6 +137,7 @@ private function getMessageTrace($testCase)
if ('' === $msg) {
$msg = (string)$child;
}
+
break 2;
}
}
@@ -140,7 +150,7 @@ private function getMessageTrace($testCase)
*/
private function loadResultFile()
{
- if (!file_exists($this->outputFile) || 0 === filesize($this->outputFile)) {
+ if (!\file_exists($this->outputFile) || 0 === \filesize($this->outputFile)) {
$this->internalProblem('empty output file');
return new SimpleXMLElement(''); // new empty element
@@ -156,4 +166,14 @@ private function internalProblem($description)
{
throw new RuntimeException($description);
}
+
+ protected function getFileAndLine($testCase)
+ {
+ $attributes = $testCase->attributes();
+
+ return [
+ 'file' => \str_replace($this->buildPath, '', $attributes['file']),
+ 'line' => (int) $attributes['line']
+ ];
+ }
}
diff --git a/src/Plugin/Util/TestResultParsers/Codeception.php b/src/Plugin/Util/TestResultParsers/Codeception.php
index 2387d0f60..b64c57cb5 100644
--- a/src/Plugin/Util/TestResultParsers/Codeception.php
+++ b/src/Plugin/Util/TestResultParsers/Codeception.php
@@ -8,7 +8,11 @@
/**
* Class Codeception
*
- * @author Adam Cooper
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Adam Cooper
+ * @author Dmitry Khomutov
*/
class Codeception implements ParserInterface
{
@@ -74,7 +78,7 @@ public function parse()
foreach ($testSuite->testcase as $testCase) {
$testResult = [
'suite' => (string)$testSuite['name'],
- 'file' => str_replace($this->builder->buildPath, '/', (string)$testCase['file']),
+ 'file' => \str_replace($this->builder->buildPath, '/', (string)$testCase['file']),
'name' => (string)$testCase['name'],
'feature' => (string)$testCase['feature'],
'assertions' => (int)$testCase['assertions'],
@@ -87,7 +91,7 @@ public function parse()
// PHPUnit testcases does not have feature field. Use class::method instead
if (!$testResult['feature']) {
- $testResult['feature'] = sprintf('%s::%s', $testResult['class'], $testResult['name']);
+ $testResult['feature'] = \sprintf('%s::%s', $testResult['class'], $testResult['name']);
}
if (isset($testCase->failure) || isset($testCase->error)) {
diff --git a/src/Plugin/Util/TestResultParsers/ParserInterface.php b/src/Plugin/Util/TestResultParsers/ParserInterface.php
index ccd2d1eac..ecb08c977 100644
--- a/src/Plugin/Util/TestResultParsers/ParserInterface.php
+++ b/src/Plugin/Util/TestResultParsers/ParserInterface.php
@@ -2,6 +2,13 @@
namespace PHPCensor\Plugin\Util\TestResultParsers;
+/**
+ * @package PHP Censor
+ * @subpackage Application
+ *
+ * @author Adam Cooper
+ * @author Dmitry Khomutov
+ */
interface ParserInterface
{
/**
diff --git a/src/Plugin/WebhookNotify.php b/src/Plugin/WebhookNotify.php
index c8331625f..eb0e7a0fe 100644
--- a/src/Plugin/WebhookNotify.php
+++ b/src/Plugin/WebhookNotify.php
@@ -7,20 +7,25 @@
use GuzzleHttp\Exception\GuzzleException;
use PHPCensor\Builder;
use PHPCensor\Exception\HttpException;
+use PHPCensor\Common\Exception\InvalidArgumentException;
use PHPCensor\Model\Build;
use PHPCensor\Plugin;
/**
* Webhook notify Plugin
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Lee Willis (Ademti Software) : https://www.ademti-software.co.uk
+ * @author Dmitry Khomutov
*/
class WebhookNotify extends Plugin
{
/**
* @var string The URL to send the webhook to.
*/
- private $url;
+ private string $url;
/**
* @return string
@@ -39,14 +44,14 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- if (!is_array($options)) {
- throw new Exception('Please configure the options for the webhook_notify plugin!');
+ if (!\is_array($options)) {
+ throw new InvalidArgumentException('Please configure the options for the webhook_notify plugin!');
}
if (!isset($options['url'])) {
- throw new Exception('Please define the url for webhook_notify plugin!');
+ throw new InvalidArgumentException('Please define the url for webhook_notify plugin!');
}
- $this->url = trim($options['url']);
+ $this->url = \trim($options['url']);
}
/**
@@ -62,7 +67,7 @@ public function execute()
'project_title' => $this->build->getProjectTitle(),
'build_id' => $this->build->getId(),
'commit_id' => $this->build->getCommitId(),
- 'short_commit_id' => substr($this->build->getCommitId(), 0, 7),
+ 'short_commit_id' => \substr($this->build->getCommitId(), 0, 7),
'branch' => $this->build->getBranch(),
'branch_link' => $this->build->getBranchLink(),
'committer_email' => $this->build->getCommitterEmail(),
@@ -100,18 +105,22 @@ private function getReadableStatus($statusId)
switch ($statusId) {
case self::STATUS_PENDING:
return 'Pending';
+
break;
case self::STATUS_RUNNING:
return 'Running';
+
break;
case self::STATUS_SUCCESS:
return 'Successful';
+
break;
case self::STATUS_FAILED:
return 'Failed';
+
break;
}
- return sprintf('Unknown (%d)', $statusId);
+ return \sprintf('Unknown (%d)', $statusId);
}
}
diff --git a/src/Plugin/Wipe.php b/src/Plugin/Wipe.php
index 764faa90e..590f2f025 100644
--- a/src/Plugin/Wipe.php
+++ b/src/Plugin/Wipe.php
@@ -9,7 +9,11 @@
/**
* Wipe Plugin - Wipes a folder
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Claus Due
+ * @author Dmitry Khomutov
*/
class Wipe extends Plugin
{
@@ -40,7 +44,7 @@ public function execute()
return true;
}
- if (is_dir($this->directory)) {
+ if (\is_dir($this->directory)) {
$cmd = 'rm -Rf "%s"';
return $this->builder->executeCommand($cmd, $this->directory);
diff --git a/src/Plugin/XmppNotify.php b/src/Plugin/XmppNotify.php
index 8d63156b3..1601728e0 100644
--- a/src/Plugin/XmppNotify.php
+++ b/src/Plugin/XmppNotify.php
@@ -9,44 +9,48 @@
/**
* XMPP Notification - Send notification for successful or failure build
*
+ * @package PHP Censor
+ * @subpackage Application
+ *
* @author Alexandre Russo
+ * @author Dmitry Khomutov
*/
class XmppNotify extends Plugin
{
/**
* @var string, username of sender account xmpp
*/
- protected $username;
+ protected $username = '';
/**
* @var string, alias server of sender account xmpp
*/
- protected $server;
+ protected $server = '';
/**
* @var string, password of sender account xmpp
*/
- protected $password;
+ protected $password = '';
/**
* @var string, alias for sender
*/
- protected $alias;
+ protected $alias = '';
/**
* @var string, use tls
*/
- protected $tls;
+ protected $tls = false;
/**
* @var array, list of recipients xmpp accounts
*/
- protected $recipients;
+ protected $recipients = [];
/**
* @var string, mask to format date
*/
- protected $dateFormat;
+ protected $dateFormat = '%c';
/**
* @return string
@@ -63,23 +67,15 @@ public function __construct(Builder $builder, Build $build, array $options = [])
{
parent::__construct($builder, $build, $options);
- $this->username = '';
- $this->password = '';
- $this->server = '';
- $this->alias = '';
- $this->recipients = [];
- $this->tls = false;
- $this->dateFormat = '%c';
-
$this->executable = $this->findBinary('sendxmpp');
/*
* Set recipients list
*/
if (!empty($options['recipients'])) {
- if (is_string($options['recipients'])) {
+ if (\is_string($options['recipients'])) {
$this->recipients = [$options['recipients']];
- } elseif (is_array($options['recipients'])) {
+ } elseif (\is_array($options['recipients'])) {
$this->recipients = $options['recipients'];
}
}
@@ -111,9 +107,9 @@ protected function getConfigFormat()
*/
public function findConfigFile()
{
- if (file_exists($this->builder->buildPath . '.sendxmpprc')) {
- if (md5(file_get_contents($this->builder->buildPath . '.sendxmpprc'))
- !== md5($this->getConfigFormat())) {
+ if (\file_exists($this->builder->buildPath . '.sendxmpprc')) {
+ if (\md5(\file_get_contents($this->builder->buildPath . '.sendxmpprc'))
+ !== \md5($this->getConfigFormat())) {
return null;
}
@@ -133,7 +129,7 @@ public function execute()
/*
* Without recipients we can't send notification
*/
- if (!is_array($this->recipients) || count($this->recipients) == 0) {
+ if (!\is_array($this->recipients) || \count($this->recipients) === 0) {
return false;
}
@@ -141,9 +137,9 @@ public function execute()
* Try to build conf file
*/
$configFile = $this->builder->buildPath . '.sendxmpprc';
- if (is_null($this->findConfigFile())) {
- file_put_contents($configFile, $this->getConfigFormat());
- chmod($configFile, 0600);
+ if (\is_null($this->findConfigFile())) {
+ \file_put_contents($configFile, $this->getConfigFormat());
+ \chmod($configFile, 0600);
}
/*
@@ -154,7 +150,7 @@ public function execute()
$tls = ' -t';
}
- $messageFile = $this->builder->buildPath . uniqid('xmppmessage');
+ $messageFile = $this->builder->buildPath . \uniqid('xmppmessage');
if ($this->buildMessage($messageFile) === false) {
return false;
}
@@ -163,7 +159,7 @@ public function execute()
* Send XMPP notification for all recipients
*/
$cmd = $sendxmpp . "%s -f %s -m %s %s";
- $recipients = implode(' ', $this->recipients);
+ $recipients = \implode(' ', $this->recipients);
$success = $this->builder->executeCommand($cmd, $tls, $configFile, $messageFile, $recipients);
@@ -188,8 +184,8 @@ protected function buildMessage($messageFile)
$message = "✘ [" . $this->build->getProjectTitle() . "] Build #" . $this->build->getId() . " failure";
}
- $message .= ' (' . strftime($this->dateFormat) . ')';
+ $message .= ' (' . \strftime($this->dateFormat) . ')';
- return file_put_contents($messageFile, $message);
+ return \file_put_contents($messageFile, $message);
}
}
diff --git a/src/ProcessControl/Factory.php b/src/ProcessControl/Factory.php
deleted file mode 100644
index 19c89ac60..000000000
--- a/src/ProcessControl/Factory.php
+++ /dev/null
@@ -1,55 +0,0 @@
-
- */
-class Factory
-{
- /**
- * ProcessControl singleton.
- *
- * @var ProcessControlInterface
- */
- protected static $instance = null;
-
- /**
- * Returns the ProcessControl singleton.
- *
- * @return ProcessControlInterface
- */
- public static function getInstance()
- {
- if (static::$instance === null) {
- static::$instance = static::createProcessControl();
- }
-
- return static::$instance;
- }
-
- /**
- * Create a ProcessControl depending on available extensions and the underlying OS.
- *
- * Check PosixProcessControl, WindowsProcessControl and UnixProcessControl, in that order.
- *
- * @return ProcessControlInterface
- *
- * @throws Exception
- */
- public static function createProcessControl()
- {
- switch (true) {
- case PosixProcessControl::isAvailable():
- return new PosixProcessControl();
- case UnixProcessControl::isAvailable():
- return new UnixProcessControl();
- }
-
- throw new Exception("No ProcessControl implementation available.");
- }
-}
diff --git a/src/ProcessControl/PosixProcessControl.php b/src/ProcessControl/PosixProcessControl.php
deleted file mode 100644
index 4677dada8..000000000
--- a/src/ProcessControl/PosixProcessControl.php
+++ /dev/null
@@ -1,42 +0,0 @@
-
- */
-class PosixProcessControl implements ProcessControlInterface
-{
- /**
- * @param int $pid
- *
- * @return bool
- */
- public function isRunning($pid)
- {
- // Signal "0" is not sent to the process, but posix_kill checks the process anyway;
- return posix_kill($pid, 0);
- }
-
- /**
- * {@inheritDoc}
- */
- public function kill($pid, $forcefully = false)
- {
- return posix_kill($pid, $forcefully ? 9 : 15);
- }
-
- /**
- * Check whether this posix_kill is available.
- *
- * @return bool
- *
- * @internal
- */
- public static function isAvailable()
- {
- return function_exists('posix_kill');
- }
-}
diff --git a/src/ProcessControl/ProcessControlInterface.php b/src/ProcessControl/ProcessControlInterface.php
deleted file mode 100644
index e3fce8c89..000000000
--- a/src/ProcessControl/ProcessControlInterface.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
- */
-interface ProcessControlInterface
-{
- /**
- * Checks if a process exists.
- *
- * @param int $pid The process identifier.
- *
- * @return bool true is the process is running, else false.
- */
- public function isRunning($pid);
-
- /**
- * Terminate a running process.
- *
- * @param int $pid The process identifier.
- * @param bool $forcefully Whether to gently (false) or forcefully (true) terminate the process.
- *
- * @return bool
- */
- public function kill($pid, $forcefully = false);
-}
diff --git a/src/ProcessControl/UnixProcessControl.php b/src/ProcessControl/UnixProcessControl.php
deleted file mode 100644
index 5f36bd117..000000000
--- a/src/ProcessControl/UnixProcessControl.php
+++ /dev/null
@@ -1,51 +0,0 @@
-
- */
-class UnixProcessControl implements ProcessControlInterface
-{
- /**
- * Check process using the "ps" command.
- *
- * @param int $pid
- *
- * @return bool
- */
- public function isRunning($pid)
- {
- $output = $exitCode = null;
- exec(sprintf("ps %d", $pid), $output, $exitCode);
-
- return $exitCode === 0;
- }
-
- /**
- * {@inheritDoc}
- */
- public function kill($pid, $forcefully = false)
- {
- $output = [];
- $result = 1;
-
- exec(sprintf("kill -%d %d", $forcefully ? 9 : 15, $pid), $output, $result);
-
- return !$result;
- }
-
- /**
- * Check whether the commands "ps" and "kill" are available.
- *
- * @return bool
- *
- * @internal
- */
- public static function isAvailable()
- {
- return DIRECTORY_SEPARATOR === '/' && exec("which ps") && exec("which kill");
- }
-}
diff --git a/src/Security/Authentication/LoginPasswordProviderInterface.php b/src/Security/Authentication/LoginPasswordProviderInterface.php
index 9a46132ea..5e5d1c6f6 100644
--- a/src/Security/Authentication/LoginPasswordProviderInterface.php
+++ b/src/Security/Authentication/LoginPasswordProviderInterface.php
@@ -1,13 +1,19 @@
+ * @author Dmitry Khomutov
*/
interface LoginPasswordProviderInterface extends UserProviderInterface
{
diff --git a/src/Security/Authentication/Service.php b/src/Security/Authentication/Service.php
index 54369b10a..58b7ff901 100644
--- a/src/Security/Authentication/Service.php
+++ b/src/Security/Authentication/Service.php
@@ -1,30 +1,33 @@
+ * @author Dmitry Khomutov
*/
class Service
{
/**
- * @var Service
+ * The table of providers.
*/
- private static $instance;
+ private array $providers;
- /**
- * Return the service singleton.
- *
- * @return Service
- */
- public static function getInstance()
- {
- if (self::$instance === null) {
- $config = Config::getInstance()->get(
+ public function __construct(
+ ConfigurationInterface $configuration,
+ StoreRegistry $storeRegistry,
+ array $providers = []
+ ) {
+ if (!$providers) {
+ $config = $configuration->get(
'php-censor.security.auth_providers',
[
'internal' => [
@@ -35,45 +38,21 @@ public static function getInstance()
$providers = [];
foreach ($config as $key => $providerConfig) {
- $providers[$key] = self::buildProvider($key, $providerConfig);
+ $providers[$key] = self::buildProvider($storeRegistry, $key, $providerConfig);
}
- self::$instance = new self($providers);
}
- return self::$instance;
+ $this->providers = $providers;
}
- /**
- * Create a provider from a given configuration.
- *
- * @param string $key
- * @param array|string $config
- *
- * @return UserProviderInterface
- */
- public static function buildProvider($key, $config)
+ public static function buildProvider(StoreRegistry $storeRegistry, string $key, array $config): UserProviderInterface
{
- $class = ucfirst($config['type']);
- if (class_exists('\\PHPCensor\\Security\\Authentication\\UserProvider\\' . $class)) {
+ $class = \ucfirst($config['type']);
+ if (\class_exists('\\PHPCensor\\Security\\Authentication\\UserProvider\\' . $class)) {
$class = '\\PHPCensor\\Security\\Authentication\\UserProvider\\' . $class;
}
- return new $class($key, $config);
- }
-
- /**
- * The table of providers.
- *
- * @var array
- */
- private $providers;
-
- /**
- * Initialize the service.
- */
- public function __construct(array $providers)
- {
- $this->providers = $providers;
+ return new $class($storeRegistry, $key, $config);
}
/**
@@ -81,7 +60,7 @@ public function __construct(array $providers)
*
* @return UserProviderInterface[]
*/
- public function getProviders()
+ public function getProviders(): array
{
return $this->providers;
}
@@ -91,7 +70,7 @@ public function getProviders()
*
* @return LoginPasswordProviderInterface[]
*/
- public function getLoginPasswordProviders()
+ public function getLoginPasswordProviders(): array
{
$providers = [];
foreach ($this->providers as $key => $provider) {
diff --git a/src/Security/Authentication/UserProvider/AbstractProvider.php b/src/Security/Authentication/UserProvider/AbstractProvider.php
index a5b17e91b..683a49663 100644
--- a/src/Security/Authentication/UserProvider/AbstractProvider.php
+++ b/src/Security/Authentication/UserProvider/AbstractProvider.php
@@ -1,13 +1,18 @@
+ * @author Dmitry Khomutov
*/
abstract class AbstractProvider implements UserProviderInterface
{
@@ -15,13 +20,16 @@ abstract class AbstractProvider implements UserProviderInterface
protected array $config;
- /**
- * AbstractProvider constructor
- */
- public function __construct(string $key, array $config)
- {
- $this->key = $key;
- $this->config = $config;
+ protected StoreRegistry $storeRegistry;
+
+ public function __construct(
+ StoreRegistry $storeRegistry,
+ string $key,
+ array $config
+ ) {
+ $this->key = $key;
+ $this->config = $config;
+ $this->storeRegistry = $storeRegistry;
}
public function getKey(): string
diff --git a/src/Security/Authentication/UserProvider/Internal.php b/src/Security/Authentication/UserProvider/Internal.php
index 169c49ba7..71f70b14b 100644
--- a/src/Security/Authentication/UserProvider/Internal.php
+++ b/src/Security/Authentication/UserProvider/Internal.php
@@ -1,31 +1,31 @@
+ * @author Dmitry Khomutov
*/
class Internal extends AbstractProvider implements LoginPasswordProviderInterface
{
public function verifyPassword(User $user, string $password): bool
{
- return password_verify($password, $user->getHash());
+ return \password_verify($password, $user->getHash());
}
- public function checkRequirements()
+ public function checkRequirements(): void
{
// Always fine
}
- /**
- *
- * @return null
- */
public function provisionUser(?string $identifier): ?User
{
return null;
diff --git a/src/Security/Authentication/UserProvider/Ldap.php b/src/Security/Authentication/UserProvider/Ldap.php
index 7461f804d..ed8bd81b0 100644
--- a/src/Security/Authentication/UserProvider/Ldap.php
+++ b/src/Security/Authentication/UserProvider/Ldap.php
@@ -1,17 +1,20 @@
*/
class Ldap extends AbstractProvider implements LoginPasswordProviderInterface
{
@@ -54,21 +57,21 @@ public function verifyPassword(User $user, string $password): bool
return false;
}
- public function checkRequirements()
+ public function checkRequirements(): void
{
// Always fine
}
/**
- *
+ * @throws \PHPCensor\Common\Exception\RuntimeException
*/
public function provisionUser(?string $identifier): ?User
{
/** @var UserStore $user */
- $user = Factory::getStore('User');
- $userService = new UserService($user);
+ $user = $this->storeRegistry->get('User');
+ $userService = new UserService($this->storeRegistry, $user);
- $parts = explode("@", $identifier);
+ $parts = \explode("@", $identifier);
$username = $parts[0];
return $userService->createUser($username, $identifier, $this->key, $this->config, '', false);
diff --git a/src/Security/Authentication/UserProviderInterface.php b/src/Security/Authentication/UserProviderInterface.php
index cfab243db..f89fca3a4 100644
--- a/src/Security/Authentication/UserProviderInterface.php
+++ b/src/Security/Authentication/UserProviderInterface.php
@@ -1,14 +1,18 @@
+ * @author Dmitry Khomutov
*/
interface UserProviderInterface
{
@@ -17,12 +21,12 @@ interface UserProviderInterface
*
* @throws Exception
*/
- public function checkRequirements();
+ public function checkRequirements(): void;
/**
* Provision an new user for the given identifier.
*
- * @param string $identifier The user identifier.
+ * @param string|null $identifier The user identifier.
*
* @return User|null The new user or null if the provider does not know the user.
*/
diff --git a/src/Service/BuildService.php b/src/Service/BuildService.php
index 69936288d..ac12d10a1 100644
--- a/src/Service/BuildService.php
+++ b/src/Service/BuildService.php
@@ -1,5 +1,7 @@
+ * @author Dmitry Khomutov
*/
class BuildService
{
- /**
- * @var BuildStore
- */
- protected $buildStore;
+ private BuildStore $buildStore;
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ private ProjectStore $projectStore;
- /**
- * @var bool
- */
- public $queueError = false;
+ private ConfigurationInterface $configuration;
+
+ private StoreRegistry $storeRegistry;
+
+ private BuildFactory $buildFactory;
+
+ public bool $queueError = false;
public function __construct(
+ ConfigurationInterface $configuration,
+ StoreRegistry $storeRegistry,
+ BuildFactory $buildFactory,
BuildStore $buildStore,
ProjectStore $projectStore
) {
- $this->buildStore = $buildStore;
- $this->projectStore = $projectStore;
+ $this->configuration = $configuration;
+ $this->storeRegistry = $storeRegistry;
+ $this->buildStore = $buildStore;
+ $this->projectStore = $projectStore;
+ $this->buildFactory = $buildFactory;
}
- /**
- * @param int|null $environmentId
- * @param string $commitId
- * @param string|null $branch
- * @param string|null $tag
- * @param string|null $committerEmail
- * @param string|null $commitMessage
- * @param int $source
- * @param int $userId
- * @param array|null $extra
- *
- * @return Build
- */
public function createBuild(
Project $project,
- $environmentId = null,
- $commitId = '',
- $branch = null,
- $tag = null,
- $committerEmail = null,
- $commitMessage = null,
- $source = Build::SOURCE_UNKNOWN,
- $userId = null,
- $extra = null
- ) {
- $build = new Build();
+ ?int $environmentId = null,
+ string $commitId = '',
+ ?string $branch = null,
+ ?string $tag = null,
+ ?string $committerEmail = null,
+ ?string $commitMessage = null,
+ int $source = Build::SOURCE_UNKNOWN,
+ ?int $userId = null,
+ ?array $extra = null
+ ): Build {
+ $build = new Build($this->storeRegistry);
$build->setCreateDate(new DateTime());
$build->setProjectId($project->getId());
$build->setStatusPending();
$build->setEnvironmentid($environmentId);
- if (!is_null($extra)) {
+ if (!\is_null($extra)) {
$build->setExtra($extra);
}
@@ -92,7 +92,7 @@ public function createBuild(
$userId = null;
}
$build->setUserId($userId);
- $build->setCommitId((string)$commitId);
+ $build->setCommitId($commitId);
if (!empty($branch)) {
$build->setBranch($branch);
@@ -118,7 +118,7 @@ public function createBuild(
if (!empty($buildId)) {
$project = $build->getProject();
- $build = BuildFactory::getBuild($build);
+ $build = $this->buildFactory->getBuild($build);
$build->sendStatusPostback();
$this->addBuildToQueue(
$build,
@@ -132,17 +132,17 @@ public function createBuild(
/**
* @throws HttpException
*/
- public function createPeriodicalBuilds(Logger $logger)
+ public function createPeriodicalBuilds(LoggerInterface $logger): void
{
$periodicalConfig = null;
- if (file_exists(APP_DIR . 'periodical.yml')) {
+ if (\file_exists(APP_DIR . 'periodical.yml')) {
try {
$periodicalConfig = (new Yaml())->parse(
- file_get_contents(APP_DIR . 'periodical.yml')
+ \file_get_contents(APP_DIR . 'periodical.yml')
);
} catch (ParseException $e) {
$logger->error(
- sprintf(
+ \sprintf(
'Invalid periodical builds config ("app/periodical.yml")! Exception: %s',
$e->getMessage()
),
@@ -155,7 +155,7 @@ public function createPeriodicalBuilds(Logger $logger)
if (empty($periodicalConfig) ||
empty($periodicalConfig['projects']) ||
- !is_array($periodicalConfig['projects'])) {
+ !\is_array($periodicalConfig['projects'])) {
$logger->warning('Empty periodical builds config ("app/periodical.yml")!');
return;
@@ -163,14 +163,15 @@ public function createPeriodicalBuilds(Logger $logger)
$buildsCount = 0;
foreach ($periodicalConfig['projects'] as $projectId => $projectConfig) {
+ /** @var Project $project */
$project = $this->projectStore->getById((int)$projectId);
if (!$project ||
empty($projectConfig['interval']) ||
empty($projectConfig['branches']) ||
- !is_array($projectConfig['branches'])) {
+ !\is_array($projectConfig['branches'])) {
$logger->warning(
- sprintf(
+ \sprintf(
'Invalid/empty section for project #%s ("app/periodical.yml")!',
$projectId
)
@@ -183,14 +184,14 @@ public function createPeriodicalBuilds(Logger $logger)
try {
$interval = new DateInterval($projectConfig['interval']);
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
$logger->error(
- sprintf(
+ \sprintf(
'Invalid datetime interval for project #%s! Exception: %s',
$projectId,
$e->getMessage()
),
- $e
+ [$e]
);
return;
@@ -228,24 +229,20 @@ public function createPeriodicalBuilds(Logger $logger)
}
$logger->notice(
- sprintf(
+ \sprintf(
'Created %d periodical builds for %d projects.',
$buildsCount,
- count($periodicalConfig['projects'])
+ \count($periodicalConfig['projects'])
)
);
}
/**
- * @param int $source
- *
- * @return Build
- *
* @throws Exception
*/
- public function createDuplicateBuild(Build $originalBuild, $source)
+ public function createDuplicateBuild(Build $originalBuild, int $source): Build
{
- $build = new Build();
+ $build = new Build($this->storeRegistry);
$build->setParentId($originalBuild->getId());
$build->setProjectId($originalBuild->getProjectId());
$build->setCommitId($originalBuild->getCommitId());
@@ -265,7 +262,7 @@ public function createDuplicateBuild(Build $originalBuild, $source)
$buildId = $build->getId();
if (!empty($buildId)) {
- $build = BuildFactory::getBuild($build);
+ $build = $this->buildFactory->getBuild($build);
$project = $build->getProject();
$build->sendStatusPostback();
$this->addBuildToQueue(
@@ -278,13 +275,11 @@ public function createDuplicateBuild(Build $originalBuild, $source)
}
/**
- * @param int $projectId
- *
* @throws HttpException
*/
- public function deleteOldByProject($projectId)
+ public function deleteOldByProject(int $projectId): void
{
- $keepBuilds = (int)Config::getInstance()->get('php-censor.build.keep_builds', 100);
+ $keepBuilds = (int)$this->configuration->get('php-censor.build.keep_builds', 100);
$builds = $this->buildStore->getOldByProject((int)$projectId, $keepBuilds);
/** @var Build $build */
@@ -294,10 +289,7 @@ public function deleteOldByProject($projectId)
}
}
- /**
- * @param int $projectId
- */
- public function deleteAllByProject($projectId)
+ public function deleteAllByProject(int $projectId): void
{
$this->buildStore->deleteAllByProject((int)$projectId);
@@ -311,24 +303,26 @@ public function deleteAllByProject($projectId)
$fileSystem = new Filesystem();
foreach ($projectPaths as $projectPath) {
- if (is_link($projectPath)) {
+ if (\is_link($projectPath)) {
// Remove the symlink without using recursive.
- exec(sprintf('rm "%s"', $projectPath));
+ \exec(\sprintf('rm "%s"', $projectPath));
} else {
$fileSystem->remove($projectPath);
}
}
- } catch (Exception $e) {
+ } catch (\Throwable $e) {
}
}
/**
* Delete a given build.
- *
- * @return bool
*/
- public function deleteBuild(Build $build)
+ public function deleteBuild(Build $build): bool
{
+ if (!$build->getId()) {
+ return false;
+ }
+
$build->removeBuildDirectory(true);
return $this->buildStore->delete($build);
@@ -337,9 +331,9 @@ public function deleteBuild(Build $build)
/**
* Takes a build and puts it into the queue to be run (if using a queue)
*
- * @param int $buildPriority priority in queue relative to default
+ * @param int $buildPriority priority in queue relative to default
*/
- public function addBuildToQueue(Build $build, $buildPriority = Project::DEFAULT_BUILD_PRIORITY)
+ public function addBuildToQueue(Build $build, int $buildPriority = Project::DEFAULT_BUILD_PRIORITY): void
{
$buildId = $build->getId();
@@ -354,31 +348,25 @@ public function addBuildToQueue(Build $build, $buildPriority = Project::DEFAULT_
$this->addJobToQueue(BuildWorker::JOB_TYPE_BUILD, $jobData, ($buildPriority + Project::OFFSET_BETWEEN_BUILD_AND_QUEUE));
}
- /**
- * @param string $jobType
- * @param int $queuePriority
- */
- public function addJobToQueue($jobType, array $jobData, $queuePriority = PheanstalkInterface::DEFAULT_PRIORITY)
+ public function addJobToQueue(string $jobType, array $jobData, int $queuePriority = PheanstalkInterface::DEFAULT_PRIORITY): void
{
- $config = Config::getInstance();
- $settings = $config->get('php-censor.queue', []);
-
+ $settings = $this->configuration->get('php-censor.queue', []);
if (!empty($settings['host']) && !empty($settings['name'])) {
$jobData['type'] = $jobType;
try {
$pheanstalk = Pheanstalk::create(
$settings['host'],
- $config->get('php-censor.queue.port', PheanstalkInterface::DEFAULT_PORT)
+ (int)$this->configuration->get('php-censor.queue.port', PheanstalkInterface::DEFAULT_PORT)
);
$pheanstalk->useTube($settings['name']);
$pheanstalk->put(
- json_encode($jobData),
+ \json_encode($jobData),
$queuePriority,
PheanstalkInterface::DEFAULT_DELAY,
- $config->get('php-censor.queue.lifetime', 600)
+ $this->configuration->get('php-censor.queue.lifetime', 600)
);
- } catch (Exception $ex) {
+ } catch (\Throwable $ex) {
$this->queueError = true;
}
}
diff --git a/src/Service/BuildStatusService.php b/src/Service/BuildStatusService.php
index df40e403e..12230e076 100644
--- a/src/Service/BuildStatusService.php
+++ b/src/Service/BuildStatusService.php
@@ -1,58 +1,43 @@
+ * @author Dmitry Khomutov
*/
class BuildStatusService
{
- /**
- * @var BuildStatusService
- */
- protected $prevService = null;
+ private ?BuildStatusService $prevService = null;
- /**
- * @var Project
- */
- protected $project;
+ private Project $project;
- /**
- * @var string
- */
- protected $branch;
+ private string $branch;
- /**
- * @var Build
- */
- protected $build;
+ private ?Build $build;
- /**
- * @var string
- */
- protected $url;
+ private string $url;
- /**
- * @var array
- */
- protected $finishedStatusIds = [
+ private array $finishedStatusIds = [
Build::STATUS_SUCCESS,
Build::STATUS_FAILED,
];
- /**
- * @param string $branch
- * @param bool $isParent
- */
public function __construct(
- $branch,
+ string $branch,
Project $project,
- Build $build = null,
- $isParent = false
+ ?Build $build = null,
+ bool $isParent = false
) {
$this->project = $project;
$this->branch = $branch;
@@ -60,33 +45,25 @@ public function __construct(
if ($this->build) {
$this->loadParentBuild($isParent);
}
- if (defined('APP_URL')) {
+ if (\defined('APP_URL')) {
$this->setUrl(APP_URL);
}
}
- /**
- * @param string $url
- */
- public function setUrl($url)
+ public function setUrl(string $url): void
{
$this->url = $url;
}
- /**
- * @return Build
- */
- public function getBuild()
+ public function getBuild(): Build
{
return $this->build;
}
/**
- * @param bool $isParent
- *
* @throws Exception
*/
- protected function loadParentBuild($isParent = true)
+ protected function loadParentBuild(bool $isParent = true): void
{
if ($isParent === false && !$this->isFinished()) {
$lastFinishedBuild = $this->project->getLatestBuild($this->branch, $this->finishedStatusIds);
@@ -102,46 +79,32 @@ protected function loadParentBuild($isParent = true)
}
}
- /**
- * @return string
- */
- public function getActivity()
+ public function getActivity(): string
{
- if (in_array($this->build->getStatus(), $this->finishedStatusIds, true)) {
+ if (\in_array($this->build->getStatus(), $this->finishedStatusIds, true)) {
return 'Sleeping';
- } elseif ($this->build->getStatus() == Build::STATUS_PENDING) {
+ } elseif ($this->build->getStatus() === Build::STATUS_PENDING) {
return 'Pending';
- } elseif ($this->build->getStatus() == Build::STATUS_RUNNING) {
- return 'Building';
}
- return 'Unknown';
+ return 'Building';
}
- /**
- * @return string
- */
- public function getName()
+ public function getName(): string
{
return $this->project->getTitle() . ' / ' . $this->branch;
}
- /**
- * @return bool
- */
- public function isFinished()
+ public function isFinished(): bool
{
- if (in_array($this->build->getStatus(), $this->finishedStatusIds, true)) {
+ if (\in_array($this->build->getStatus(), $this->finishedStatusIds, true)) {
return true;
}
return false;
}
- /**
- * @return Build|null
- */
- public function getFinishedBuildInfo()
+ public function getFinishedBuildInfo(): ?Build
{
if ($this->isFinished()) {
return $this->build;
@@ -152,22 +115,16 @@ public function getFinishedBuildInfo()
return null;
}
- /**
- * @return int|string
- */
- public function getLastBuildLabel()
+ public function getLastBuildLabel(): string
{
if ($buildInfo = $this->getFinishedBuildInfo()) {
- return $buildInfo->getId();
+ return (string)$buildInfo->getId();
}
return '';
}
- /**
- * @return string
- */
- public function getLastBuildTime()
+ public function getLastBuildTime(): string
{
$dateFormat = 'Y-m-d\\TH:i:sO';
if ($buildInfo = $this->getFinishedBuildInfo()) {
@@ -177,45 +134,25 @@ public function getLastBuildTime()
return '';
}
- /**
- * @return string
- */
- public function getBuildStatus(Build $build)
+ public function getLastBuildStatus(): string
{
- switch ($build->getStatus()) {
- case Build::STATUS_SUCCESS:
+ if ($build = $this->getFinishedBuildInfo()) {
+ if (Build::STATUS_SUCCESS === $build->getStatus()) {
return 'Success';
- case Build::STATUS_FAILED:
- return 'Failure';
- }
-
- return 'Unknown';
- }
+ }
- /**
- * @return string
- */
- public function getLastBuildStatus()
- {
- if ($build = $this->getFinishedBuildInfo()) {
- return $this->getBuildStatus($build);
+ return 'Failure';
}
return '';
}
- /**
- * @return string
- */
- public function getBuildUrl()
+ public function getBuildUrl(): string
{
return $this->url . 'build/view/' . $this->build->getId();
}
- /**
- * @return array
- */
- public function toArray()
+ public function toArray(): array
{
if (!$this->build) {
return [];
diff --git a/src/Service/ProjectService.php b/src/Service/ProjectService.php
index 9f3bf44b4..d90f5de20 100644
--- a/src/Service/ProjectService.php
+++ b/src/Service/ProjectService.php
@@ -1,43 +1,46 @@
+ * @author Dmitry Khomutov
*/
class ProjectService
{
- /**
- * @var ProjectStore
- */
- protected $projectStore;
+ private ProjectStore $projectStore;
- public function __construct(ProjectStore $projectStore)
- {
- $this->projectStore = $projectStore;
+ private StoreRegistry $storeRegistry;
+
+ public function __construct(
+ StoreRegistry $storeRegistry,
+ ProjectStore $projectStore
+ ) {
+ $this->storeRegistry = $storeRegistry;
+ $this->projectStore = $projectStore;
}
/**
* Create a new project model and use the project store to save it.
- *
- * @param string $title
- * @param string $type
- * @param string $reference
- * @param int $userId
- * @param array $options
- *
- * @return Project
*/
- public function createProject($title, $type, $reference, $userId, $options = [])
+ public function createProject(string $title, string $type, string $reference, int $userId, array $options = []): Project
{
// Create base project and use updateProject() to set its properties:
- $project = new Project();
+ $project = new Project($this->storeRegistry);
$project->setCreateDate(new DateTime());
$project->setUserId((int)$userId);
@@ -46,15 +49,8 @@ public function createProject($title, $type, $reference, $userId, $options = [])
/**
* Update the properties of a given project.
- *
- * @param string $title
- * @param string $type
- * @param string $reference
- * @param array $options
- *
- * @return Project
*/
- public function updateProject(Project $project, $title, $type, $reference, $options = [])
+ public function updateProject(Project $project, string $title, string $type, string $reference, array $options = []): Project
{
// Set basic properties:
$project->setTitle($title);
@@ -65,39 +61,39 @@ public function updateProject(Project $project, $title, $type, $reference, $opti
$project->setOverwriteBuildConfig(true);
// Handle extra project options:
- if (array_key_exists('ssh_private_key', $options)) {
+ if (\array_key_exists('ssh_private_key', $options)) {
$project->setSshPrivateKey($options['ssh_private_key']);
}
- if (array_key_exists('ssh_public_key', $options)) {
+ if (\array_key_exists('ssh_public_key', $options)) {
$project->setSshPublicKey($options['ssh_public_key']);
}
- if (array_key_exists('overwrite_build_config', $options)) {
+ if (\array_key_exists('overwrite_build_config', $options)) {
$project->setOverwriteBuildConfig($options['overwrite_build_config']);
}
- if (array_key_exists('build_config', $options)) {
+ if (\array_key_exists('build_config', $options)) {
$project->setBuildConfig($options['build_config']);
}
- if (array_key_exists('allow_public_status', $options)) {
+ if (\array_key_exists('allow_public_status', $options)) {
$project->setAllowPublicStatus($options['allow_public_status']);
}
- if (array_key_exists('archived', $options)) {
+ if (\array_key_exists('archived', $options)) {
$project->setArchived($options['archived']);
}
- if (array_key_exists('default_branch', $options)) {
+ if (\array_key_exists('default_branch', $options)) {
$project->setDefaultBranch($options['default_branch']);
}
- if (array_key_exists('default_branch_only', $options)) {
+ if (\array_key_exists('default_branch_only', $options)) {
$project->setDefaultBranchOnly($options['default_branch_only']);
}
- if (array_key_exists('group', $options)) {
+ if (\array_key_exists('group', $options)) {
$project->setGroupId((int)$options['group']);
} else {
$project->setGroupId(1);
@@ -109,7 +105,7 @@ public function updateProject(Project $project, $title, $type, $reference, $opti
/** @var Project $project */
$project = $this->projectStore->save($project);
- if (array_key_exists('environments', $options)) {
+ if (\array_key_exists('environments', $options)) {
$project->setEnvironments($options['environments']);
}
@@ -118,39 +114,36 @@ public function updateProject(Project $project, $title, $type, $reference, $opti
/**
* Delete a given project.
- *
- * @return bool
*/
- public function deleteProject(Project $project)
+ public function deleteProject(Project $project): bool
{
- try {
- $fileSystem = new Filesystem();
-
- $fileSystem->remove(RUNTIME_DIR . 'builds/' . $project->getId());
- $fileSystem->remove(PUBLIC_DIR . 'artifacts/pdepend/' . $project->getId());
- $fileSystem->remove(PUBLIC_DIR . 'artifacts/phpunit/' . $project->getId());
- } catch (Exception $e) {
+ if (!$project->getId()) {
+ return false;
}
+ $fileSystem = new Filesystem();
+
+ $fileSystem->remove(RUNTIME_DIR . 'builds/' . $project->getId());
+ $fileSystem->remove(PUBLIC_DIR . 'artifacts/pdepend/' . $project->getId());
+ $fileSystem->remove(PUBLIC_DIR . 'artifacts/phpunit/' . $project->getId());
+
return $this->projectStore->delete($project);
}
/**
* In circumstances where it is necessary, populate access information based on other project properties.
- *
- * @return Project
*/
- protected function processAccessInformation(Project $project)
+ public function processAccessInformation(Project $project): Project
{
$reference = $project->getReference();
- if (in_array($project->getType(), [
+ if (\in_array($project->getType(), [
Project::TYPE_GITHUB,
Project::TYPE_GITLAB
], true)) {
$info = [];
- if (preg_match(
+ if (\preg_match(
'#^((https|http|ssh)://)?((.+)@)?(([^/:]+):?)(:?([0-9]*)/?)(.+)\.git#',
$reference,
$matches
diff --git a/src/Service/UserService.php b/src/Service/UserService.php
index 981a7914a..49b1a19f0 100644
--- a/src/Service/UserService.php
+++ b/src/Service/UserService.php
@@ -1,43 +1,42 @@
+ * @author Dmitry Khomutov
*/
class UserService
{
- /**
- * @var UserStore
- */
- protected $store;
+ private UserStore $store;
- public function __construct(UserStore $store)
- {
- $this->store = $store;
+ private StoreRegistry $storeRegistry;
+
+ public function __construct(
+ StoreRegistry $storeRegistry,
+ UserStore $store
+ ) {
+ $this->storeRegistry = $storeRegistry;
+ $this->store = $store;
}
- /**
- * Create a new user.
- *
- * @param string $name
- * @param string $email
- * @param string $providerKey
- * @param array $providerData
- * @param string $password
- * @param bool $isAdmin
- *
- * @return User
- */
- public function createUser($name, $email, $providerKey, $providerData, $password, $isAdmin = false)
+ public function createUser(string $name, string $email, string $providerKey, array $providerData, string $password, bool $isAdmin = false): ?User
{
- $user = new User();
+ $user = new User($this->storeRegistry);
$user->setName($name);
$user->setEmail($email);
- $user->setHash(password_hash($password, PASSWORD_DEFAULT));
+ $user->setHash(\password_hash($password, PASSWORD_DEFAULT));
$user->setProviderKey($providerKey);
$user->setProviderData($providerData);
$user->setIsAdmin($isAdmin);
@@ -48,8 +47,6 @@ public function createUser($name, $email, $providerKey, $providerData, $password
/**
* Update a user.
*
- * @param string $name
- * @param string $emailAddress
* @param string $password
* @param bool $isAdmin
* @param string $language
@@ -57,16 +54,16 @@ public function createUser($name, $email, $providerKey, $providerData, $password
*
* @return User
*/
- public function updateUser(User $user, $name, $emailAddress, $password = null, $isAdmin = null, $language = null, $perPage = null)
+ public function updateUser(User $user, string $name, string $emailAddress, ?string $password = null, ?bool $isAdmin = null, ?string $language = null, ?int $perPage = null): ?User
{
$user->setName($name);
$user->setEmail($emailAddress);
if (!empty($password)) {
- $user->setHash(password_hash($password, PASSWORD_DEFAULT));
+ $user->setHash(\password_hash($password, PASSWORD_DEFAULT));
}
- if (!is_null($isAdmin)) {
+ if (!\is_null($isAdmin)) {
$user->setIsAdmin($isAdmin);
}
@@ -78,11 +75,13 @@ public function updateUser(User $user, $name, $emailAddress, $password = null, $
/**
* Delete a user.
- *
- * @return bool
*/
- public function deleteUser(User $user)
+ public function deleteUser(User $user): bool
{
+ if (!$user->getId()) {
+ return false;
+ }
+
return $this->store->delete($user);
}
}
diff --git a/src/Store.php b/src/Store.php
index 9794e3226..02949dabf 100644
--- a/src/Store.php
+++ b/src/Store.php
@@ -1,66 +1,92 @@
+ * @author Dmitry Khomutov
+ */
abstract class Store
{
- /**
- * @var string
- */
- protected $modelName = null;
+ protected string $modelName = '';
- /**
- * @var string
- */
- protected $tableName = '';
+ protected string $tableName = '';
- /**
- * @var string
- */
- protected $primaryKey = null;
+ protected string $primaryKey = 'id';
- /**
- * @param string $key
- * @param string $useConnection
- *
- * @return Model|null
- */
- abstract public function getByPrimaryKey($key, $useConnection = 'read');
+ protected DatabaseManager $databaseManager;
- /**
- * @throws RuntimeException
- */
- public function __construct()
+ protected StoreRegistry $storeRegistry;
+
+ public function __construct(
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry
+ ) {
+ $this->databaseManager = $databaseManager;
+ $this->storeRegistry = $storeRegistry;
+ }
+
+ public function getById(int $id, string $useConnection = 'read'): ?Model
{
- if (empty($this->primaryKey)) {
- throw new RuntimeException('Save not implemented for this store.');
+ $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} = :id LIMIT 1';
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
+
+ if ($stmt) {
+ $stmt->bindValue(':id', $id);
+
+ if ($stmt->execute()) {
+ if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
+ return new $this->modelName($this->storeRegistry, $data);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public function getAll(string $useConnection = 'read'): array
+ {
+ $query = 'SELECT * FROM {{' . $this->tableName . '}}';
+ $countQuery = 'SELECT COUNT(*) AS {{count}} FROM {{' . $this->tableName . '}}';
+
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($countQuery);
+ $stmt->execute();
+ $res = $stmt->fetch(PDO::FETCH_ASSOC);
+ $count = (int)$res['count'];
+
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
+ $stmt->execute();
+ $res = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $rtn = [];
+
+ foreach ($res as $data) {
+ $rtn[] = new $this->modelName($this->storeRegistry, $data);
}
+
+ return ['items' => $rtn, 'count' => $count];
}
/**
- * @param array $where
- * @param int $limit
- * @param int $offset
- * @param array $order
- * @param string $whereType
- *
- * @return array
- *
+ * @throws Common\Exception\Exception
* @throws InvalidArgumentException
*/
public function getWhere(
- $where = [],
- $limit = 25,
- $offset = 0,
- $order = [],
- $whereType = 'AND'
- ) {
- $query = 'SELECT * FROM {{' . $this->tableName . '}}';
+ array $where = [],
+ int $limit = 25,
+ int $offset = 0,
+ array $order = [],
+ string $whereType = 'AND'
+ ): array {
+ $query = 'SELECT * FROM {{' . $this->tableName . '}}';
$countQuery = 'SELECT COUNT(*) AS {{count}} FROM {{' . $this->tableName . '}}';
$wheres = [];
@@ -68,24 +94,24 @@ public function getWhere(
foreach ($where as $key => $value) {
$key = $this->fieldCheck($key);
- if (!is_array($value)) {
+ if (!\is_array($value)) {
$params[] = $value;
$wheres[] = $key . ' = ?';
}
}
- if (count($wheres)) {
- $query .= ' WHERE (' . implode(' ' . $whereType . ' ', $wheres) . ')';
- $countQuery .= ' WHERE (' . implode(' ' . $whereType . ' ', $wheres) . ')';
+ if (\count($wheres)) {
+ $query .= ' WHERE (' . \implode(' ' . $whereType . ' ', $wheres) . ')';
+ $countQuery .= ' WHERE (' . \implode(' ' . $whereType . ' ', $wheres) . ')';
}
- if (count($order)) {
+ if (\count($order)) {
$orders = [];
foreach ($order as $key => $value) {
$orders[] = $this->fieldCheck($key) . ' ' . $value;
}
- $query .= ' ORDER BY ' . implode(', ', $orders);
+ $query .= ' ORDER BY ' . \implode(', ', $orders);
}
if ($limit) {
@@ -96,175 +122,195 @@ public function getWhere(
$query .= ' OFFSET ' . $offset;
}
- $stmt = Database::getConnection('read')->prepareCommon($countQuery);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($countQuery);
$stmt->execute($params);
$res = $stmt->fetch(PDO::FETCH_ASSOC);
$count = (int)$res['count'];
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->execute($params);
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
$rtn = [];
foreach ($res as $data) {
- $rtn[] = new $this->modelName($data);
+ $rtn[] = new $this->modelName($this->storeRegistry, $data);
}
return ['items' => $rtn, 'count' => $count];
}
/**
- * @param bool $saveAllColumns
- *
* @throws InvalidArgumentException
- *
- * @return Model|null
+ * @throws Exception
*/
- public function save(Model $obj, $saveAllColumns = false)
+ public function save(Model $model): ?Model
{
- if (!($obj instanceof $this->modelName)) {
- throw new InvalidArgumentException(get_class($obj) . ' is an invalid model type for this store.');
+ if (!($model instanceof $this->modelName)) {
+ throw new InvalidArgumentException(\get_class($model) . ' is an invalid model type for this store.');
}
- $data = $obj->getDataArray();
+ $data = $this->getData($model);
- if (isset($data[$this->primaryKey])) {
- $rtn = $this->saveByUpdate($obj, $saveAllColumns);
- } else {
- $rtn = $this->saveByInsert($obj, $saveAllColumns);
+ if ($model->getId() !== null) {
+ return $this->saveByUpdate($model, $data);
}
- return $rtn;
+ return $this->saveByInsert($model, $data);
}
/**
- * @param bool $saveAllColumns
- *
- * @return Model|null
- *
* @throws Exception
*/
- public function saveByUpdate(Model $obj, $saveAllColumns = false)
+ protected function saveByUpdate(Model $model, array $data): ?Model
{
- $rtn = null;
- $data = $obj->getDataArray();
- $modified = ($saveAllColumns) ? array_keys($data) : $obj->getModified();
+ if (empty($data)) {
+ return $model;
+ }
- $updates = [];
+ $updates = [];
$updateParams = [];
- foreach ($modified as $key) {
- $updates[] = $key . ' = :' . $key;
- $updateParams[] = [$key, $data[$key]];
+ foreach ($data as $column => $value) {
+ $updates[] = $column . ' = :' . $column;
+ $updateParams[] = [$column, $value];
}
- if (count($updates)) {
- $qs = sprintf(
- 'UPDATE {{%s}} SET %s WHERE {{%s}} = :primaryKey',
- $this->tableName,
- implode(', ', $updates),
- $this->primaryKey
- );
- $q = Database::getConnection('write')->prepareCommon($qs);
-
- foreach ($updateParams as $updateParam) {
- $q->bindValue(':' . $updateParam[0], $updateParam[1]);
- }
-
- $q->bindValue(':primaryKey', $data[$this->primaryKey]);
- $q->execute();
-
- $rtn = $this->getByPrimaryKey($data[$this->primaryKey], 'write');
- } else {
- $rtn = $obj;
+ $queryString = \sprintf(
+ 'UPDATE {{%s}} SET %s WHERE {{%s}} = :primaryKey',
+ $this->tableName,
+ \implode(', ', $updates),
+ $this->primaryKey
+ );
+ $query = $this->databaseManager
+ ->getConnection('write')
+ ->prepare($queryString);
+
+ foreach ($updateParams as $updateParam) {
+ $query->bindValue(':' . $updateParam[0], $updateParam[1]);
}
- return $rtn;
+ $query->bindValue(':primaryKey', $data[$this->primaryKey]);
+ $query->execute();
+
+ return $this->getById($model->getId());
}
/**
- * @param bool $saveAllColumns
- *
- * @return Model|null
- *
* @throws Exception
*/
- public function saveByInsert(Model $obj, $saveAllColumns = false)
+ protected function saveByInsert(Model $model, array $data): ?Model
{
- $rtn = null;
- $data = $obj->getDataArray();
- $modified = ($saveAllColumns) ? array_keys($data) : $obj->getModified();
-
- $cols = [];
- $values = [];
- $qParams = [];
- foreach ($modified as $key) {
- $cols[] = $key;
- $values[] = ':' . $key;
- $qParams[':' . $key] = $data[$key];
+ if (empty($data)) {
+ return $model;
}
- if (count($cols)) {
- $qs = sprintf(
- 'INSERT INTO {{%s}} (%s) VALUES (%s)',
- $this->tableName,
- implode(', ', $cols),
- implode(', ', $values)
- );
- $q = Database::getConnection('write')->prepareCommon($qs);
-
- if ($q->execute($qParams)) {
- $id = Database::getConnection('write')->lastInsertIdExtended($this->tableName);
- $rtn = $this->getByPrimaryKey($id, 'write');
+ $cols = [];
+ $values = [];
+ $queryParams = [];
+ foreach ($data as $column => $value) {
+ if ('id' !== $column) {
+ $cols[] = $column;
+ $values[] = ':' . $column;
+ $queryParams[':' . $column] = $value;
}
}
- return $rtn;
+ $queryString = \sprintf(
+ 'INSERT INTO {{%s}} (%s) VALUES (%s)',
+ $this->tableName,
+ \implode(', ', $cols),
+ \implode(', ', $values)
+ );
+ $query = $this->databaseManager
+ ->getConnection('write')
+ ->prepare($queryString);
+
+ if (!$query->execute($queryParams)) {
+ return $model;
+ }
+
+ $id = $this->databaseManager
+ ->getConnection('write')
+ ->lastInsertId($this->tableName);
+
+ return $this->getById($id);
}
/**
- * @return bool
- *
+ * @throws Common\Exception\Exception
* @throws InvalidArgumentException
*/
- public function delete(Model $obj)
+ public function delete(Model $model): bool
{
- if (!($obj instanceof $this->modelName)) {
- throw new InvalidArgumentException(get_class($obj) . ' is an invalid model type for this store.');
+ if (!($model instanceof $this->modelName)) {
+ throw new InvalidArgumentException(\get_class($model) . ' is an invalid model type for this store.');
}
- $data = $obj->getDataArray();
-
- $q = Database::getConnection('write')
- ->prepareCommon(
- sprintf(
+ $query = $this->databaseManager->getConnection('write')
+ ->prepare(
+ \sprintf(
'DELETE FROM {{%s}} WHERE {{%s}} = :primaryKey',
$this->tableName,
$this->primaryKey
)
);
- $q->bindValue(':primaryKey', $data[$this->primaryKey]);
- $q->execute();
+ $query->bindValue(':primaryKey', $model->getId());
+ $query->execute();
return true;
}
/**
- * @param string $field
- *
- * @return string
- *
* @throws InvalidArgumentException
*/
- protected function fieldCheck($field)
+ protected function fieldCheck(string $field): string
{
if (empty($field)) {
throw new InvalidArgumentException('You cannot have an empty field name.');
}
- if (strpos($field, '.') === false) {
+ if (\strpos($field, '.') === false) {
return '{{' . $this->tableName . '}}.{{' . $field . '}}';
}
return $field;
}
+
+ protected function getData(Model $model): array
+ {
+ $rawData = $model->getDataArray();
+ $modified = \array_keys($model->getId() === null ? $rawData : $model->getModified());
+ $data = [];
+ foreach ($rawData as $column => $value) {
+ if (!\in_array($column, $modified, true)) {
+ continue;
+ }
+ $data[$column] = $this->castToDatabase($model->getDataType($column), $value);
+ }
+
+ return $data;
+ }
+
+ /**
+ * @return mixed
+ */
+ private function castToDatabase(string $type, $value)
+ {
+ if ($value === null || \gettype($value) === 'string') {
+ return $value;
+ }
+
+ switch ($type) {
+ case 'datetime':
+ return $value->format('Y-m-d H:i:s');
+ case 'array':
+ return \json_encode($value);
+ case 'newline':
+ return \implode("\n", $value);
+ case 'bool':
+ case 'boolean':
+ return $value ? 1 : 0;
+ default:
+ return $value;
+ }
+ }
}
diff --git a/src/Store/BuildErrorStore.php b/src/Store/BuildErrorStore.php
index e9a6ed2d3..b40894faf 100644
--- a/src/Store/BuildErrorStore.php
+++ b/src/Store/BuildErrorStore.php
@@ -1,90 +1,37 @@
+ * @author Dmitry Khomutov
+ */
class BuildErrorStore extends Store
{
- /**
- * @var string
- */
- protected $tableName = 'build_errors';
-
- /**
- * @var string
- */
- protected $modelName = '\PHPCensor\Model\BuildError';
+ protected string $tableName = 'build_errors';
- /**
- * @var string
- */
- protected $primaryKey = 'id';
-
- /**
- * Get a BuildError by primary key (Id)
- *
- * @param int $key
- * @param string $useConnection
- *
- * @return BuildError|null
- */
- public function getByPrimaryKey($key, $useConnection = 'read')
- {
- return $this->getById($key, $useConnection);
- }
-
- /**
- * Get a single BuildError by Id.
- *
- * @param int $id
- * @param string $useConnection
- *
- * @return BuildError|null
- *
- * @throws HttpException
- */
- public function getById($id, $useConnection = 'read')
- {
- if (is_null($id)) {
- throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
- }
-
- $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} = :id LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
- $stmt->bindValue(':id', $id);
-
- if ($stmt->execute()) {
- if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new BuildError($data);
- }
- }
-
- return null;
- }
+ protected string $modelName = BuildError::class;
/**
* Get multiple BuildError by BuildId.
*
- * @param int $buildId
- * @param int|null $limit
- * @param int $offset
- * @param string|null $plugin
- * @param int|null $severity
- * @param string|null $isNew
- *
- * @return array
- *
* @throws HttpException
*/
- public function getByBuildId($buildId, $limit = null, $offset = 0, $plugin = null, $severity = null, $isNew = null)
+ public function getByBuildId(int $buildId, ?int $limit = null, int $offset = 0, ?string $plugin = null, ?int $severity = null, ?string $isNew = null): array
{
- if (is_null($buildId)) {
+ if (\is_null($buildId)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
@@ -109,7 +56,7 @@ public function getByBuildId($buildId, $limit = null, $offset = 0, $plugin = nul
if ($offset) {
$query .= ' OFFSET :offset';
}
- $stmt = Database::getConnection()->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection()->prepare($query);
$stmt->bindValue(':build_id', $buildId);
if ($plugin) {
$stmt->bindValue(':plugin', $plugin, PDO::PARAM_STR);
@@ -127,12 +74,10 @@ public function getByBuildId($buildId, $limit = null, $offset = 0, $plugin = nul
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new BuildError($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new BuildError($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
@@ -143,16 +88,9 @@ public function getByBuildId($buildId, $limit = null, $offset = 0, $plugin = nul
/**
* Gets the total number of errors for a given build.
*
- * @param int $buildId
- * @param string|null $plugin
- * @param int|null $severity
- * @param string|null $isNew
- *
- * @return int
- *
* @throws Exception
*/
- public function getErrorTotalForBuild($buildId, $plugin = null, $severity = null, $isNew = null)
+ public function getErrorTotalForBuild(int $buildId, ?string $plugin = null, ?int $severity = null, ?string $isNew = null): int
{
$query = 'SELECT COUNT(*) AS {{total}} FROM {{' . $this->tableName . '}} WHERE {{build_id}} = :build';
@@ -170,7 +108,7 @@ public function getErrorTotalForBuild($buildId, $plugin = null, $severity = null
$query .= ' AND {{is_new}} = false';
}
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':build', $buildId, PDO::PARAM_INT);
@@ -191,14 +129,7 @@ public function getErrorTotalForBuild($buildId, $plugin = null, $severity = null
}
}
- /**
- * @param int $buildId
- * @param int $severity
- * @param string $isNew
- *
- * @return array
- */
- public function getKnownPlugins($buildId, $severity = null, $isNew = '')
+ public function getKnownPlugins(int $buildId, ?int $severity = null, ?string $isNew = null): array
{
$query = 'SELECT DISTINCT {{plugin}} from {{' . $this->tableName . '}} WHERE {{build_id}} = :build';
@@ -212,7 +143,7 @@ public function getKnownPlugins($buildId, $severity = null, $isNew = '')
$query .= ' AND {{is_new}} = false';
}
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':build', $buildId);
if (null !== $severity) {
$stmt->bindValue(':severity', (int)$severity, PDO::PARAM_INT);
@@ -220,26 +151,15 @@ public function getKnownPlugins($buildId, $severity = null, $isNew = '')
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $map = fn ($item) => $item['plugin'];
- $map = function ($item) {
- return $item['plugin'];
- };
- $rtn = array_map($map, $res);
-
- return $rtn;
+ return \array_map($map, $res);
} else {
return [];
}
}
- /**
- * @param int $buildId
- * @param string $plugin
- * @param string $isNew
- *
- * @return array
- */
- public function getKnownSeverities($buildId, $plugin = '', $isNew = '')
+ public function getKnownSeverities(int $buildId, ?string $plugin = null, ?string $isNew = null): array
{
$query = 'SELECT DISTINCT {{severity}} FROM {{' . $this->tableName . '}} WHERE {{build_id}} = :build';
@@ -253,7 +173,7 @@ public function getKnownSeverities($buildId, $plugin = '', $isNew = '')
$query .= ' AND {{is_new}} = false';
}
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':build', $buildId);
if ($plugin) {
$stmt->bindValue(':plugin', $plugin);
@@ -261,13 +181,9 @@ public function getKnownSeverities($buildId, $plugin = '', $isNew = '')
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $map = fn ($item) => (int)$item['severity'];
- $map = function ($item) {
- return (int)$item['severity'];
- };
- $rtn = array_map($map, $res);
-
- return $rtn;
+ return \array_map($map, $res);
} else {
return [];
}
@@ -276,20 +192,17 @@ public function getKnownSeverities($buildId, $plugin = '', $isNew = '')
/**
* Check if a build error is new.
*
- * @param int $projectId
- * @param string $hash
- *
- * @return bool
* @throws Exception
*/
- public function getIsNewError($projectId, $hash)
+ public function getIsNewError(int $projectId, string $hash): bool
{
$query = '
SELECT COUNT(*) AS {{total}} FROM {{' . $this->tableName . '}} AS be
LEFT JOIN {{builds}} AS b ON be.build_id = b.id
WHERE be.hash = :hash AND b.project_id = :project';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':project', $projectId);
$stmt->bindValue(':hash', $hash);
@@ -304,10 +217,9 @@ public function getIsNewError($projectId, $hash)
}
/**
- * @return array
* @throws Exception
*/
- public function getErrorAmountPerPluginForBuild($buildId)
+ public function getErrorAmountPerPluginForBuild(int $buildId): array
{
$query = '
SELECT {{plugin}}, COUNT(*) AS {{amount}}
@@ -316,7 +228,7 @@ public function getErrorAmountPerPluginForBuild($buildId)
GROUP BY {{plugin}}
';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':build', $buildId);
$stmt->execute();
diff --git a/src/Store/BuildErrorWriter.php b/src/Store/BuildErrorWriter.php
index 6013ff0d7..fdee2ed59 100644
--- a/src/Store/BuildErrorWriter.php
+++ b/src/Store/BuildErrorWriter.php
@@ -1,108 +1,95 @@
+ * @author Dmitry Khomutov
*/
class BuildErrorWriter
{
- /**
- * @var int
- */
- protected $buildId;
+ private int $buildId;
- /**
- * @var int
- */
- protected $projectId;
+ private int $projectId;
- /**
- * @var array
- */
- protected $errors = [];
+ private array $errors = [];
- /**
- * @var int
- *
- * @see https://stackoverflow.com/questions/40361164/pdoexception-sqlstatehy000-general-error-7-number-of-parameters-must-be-bet
- */
- protected $bufferSize;
+ private DatabaseManager $databaseManager;
+
+ private StoreRegistry $storeRegistry;
/**
- * @param int $projectId
- * @param int $buildId
+ * @see https://stackoverflow.com/questions/40361164/pdoexception-sqlstatehy000-general-error-7-number-of-parameters-must-be-bet
*/
- public function __construct($projectId, $buildId)
- {
- $this->bufferSize = (int)Config::getInstance()->get('php-censor.build.writer_buffer_size', 500);
+ private int $bufferSize;
+
+ public function __construct(
+ ConfigurationInterface $configuration,
+ DatabaseManager $databaseManager,
+ StoreRegistry $storeRegistry,
+ int $projectId,
+ int $buildId
+ ) {
+ $this->bufferSize = (int)$configuration->get('php-censor.build.writer_buffer_size', 500);
$this->projectId = $projectId;
$this->buildId = $buildId;
+
+ $this->databaseManager = $databaseManager;
+ $this->storeRegistry = $storeRegistry;
}
- /**
- * Destructor
- */
public function __destruct()
{
$this->flush();
}
- /**
- * Write error
- *
- * @param string $plugin
- * @param string $message
- * @param int $severity
- * @param string $file
- * @param int $lineStart
- * @param int $lineEnd
- * @param DateTime $createdDate
- */
public function write(
- $plugin,
- $message,
- $severity,
- $file = null,
- $lineStart = null,
- $lineEnd = null,
- $createdDate = null
- ) {
- if (is_null($createdDate)) {
+ string $plugin,
+ string $message,
+ int $severity,
+ ?string $file = null,
+ ?int $lineStart = null,
+ ?int $lineEnd = null,
+ ?DateTime $createdDate = null
+ ): void {
+ if (\is_null($createdDate)) {
$createdDate = new DateTime();
}
/** @var BuildErrorStore $errorStore */
- $errorStore = Factory::getStore('BuildError');
+ $errorStore = $this->storeRegistry->get('BuildError');
$hash = BuildError::generateHash($plugin, $file, $lineStart, $lineEnd, $severity, $message);
$this->errors[] = [
- 'plugin' => (string)$plugin,
- 'message' => (string)$message,
- 'severity' => (int)$severity,
- 'file' => !is_null($file) ? (string)$file : null,
- 'line_start' => !is_null($lineStart) ? (int)$lineStart : null,
- 'line_end' => !is_null($lineEnd) ? (int)$lineEnd : null,
+ 'plugin' => $plugin,
+ 'message' => $message,
+ 'severity' => $severity,
+ 'file' => $file,
+ 'line_start' => $lineStart,
+ 'line_end' => $lineEnd,
'create_date' => $createdDate->format('Y-m-d H:i:s'),
'hash' => $hash,
'is_new' => $errorStore->getIsNewError($this->projectId, $hash) ? 1 : 0,
];
- if (count($this->errors) >= $this->bufferSize) {
+ if (\count($this->errors) >= $this->bufferSize) {
$this->flush();
}
}
- /**
- * Flush buffer
- */
- public function flush()
+ public function flush(): void
{
if (empty($this->errors)) {
return;
@@ -147,9 +134,9 @@ public function flush()
{{hash}},
{{is_new}}
)
- VALUES ' . join(', ', $insertValuesPlaceholders) . '
+ VALUES ' . \join(', ', $insertValuesPlaceholders) . '
';
- $stmt = Database::getConnection('write')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('write')->prepare($query);
$stmt->execute($insertValuesData);
$this->errors = [];
diff --git a/src/Store/BuildMetaStore.php b/src/Store/BuildMetaStore.php
index ce3315353..ff358c705 100644
--- a/src/Store/BuildMetaStore.php
+++ b/src/Store/BuildMetaStore.php
@@ -1,83 +1,35 @@
+ * @author Dmitry Khomutov
+ */
class BuildMetaStore extends Store
{
- /**
- * @var string
- */
- protected $tableName = 'build_metas';
-
- /**
- * @var string
- */
- protected $modelName = '\PHPCensor\Model\BuildMeta';
-
- /**
- * @var string
- */
- protected $primaryKey = 'id';
-
- /**
- * Get a BuildMeta by primary key (Id)
- *
- * @param int $key
- * @param string $useConnection
- *
- * @return BuildMeta|null
- */
- public function getByPrimaryKey($key, $useConnection = 'read')
- {
- return $this->getById($key, $useConnection);
- }
-
- /**
- * Get a single BuildMeta by Id.
- *
- * @param int $id
- * @param string $useConnection
- *
- * @return BuildMeta|null
- *
- * @throws HttpException
- */
- public function getById($id, $useConnection = 'read')
- {
- if (is_null($id)) {
- throw new HttpException('id passed to ' . __FUNCTION__ . ' cannot be null.');
- }
-
- $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} = :id LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
- $stmt->bindValue(':id', $id);
-
- if ($stmt->execute()) {
- if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new BuildMeta($data);
- }
- }
+ protected string $tableName = 'build_metas';
- return null;
- }
+ protected string $modelName = BuildMeta::class;
/**
- * @param int $buildId
- * @param string $key
- *
- * @return BuildMeta|null
- *
* @throws HttpException
*/
- public function getByKey($buildId, $key)
+ public function getByKey(int $buildId, string $key): ?BuildMeta
{
- if (is_null($buildId)) {
+ if (\is_null($buildId)) {
throw new HttpException('buildId passed to ' . __FUNCTION__ . ' cannot be null.');
}
@@ -86,13 +38,13 @@ public function getByKey($buildId, $key)
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{build_id}} = :build_id AND {{meta_key}} = :meta_key LIMIT 1';
- $stmt = Database::getConnection()->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':build_id', $buildId);
$stmt->bindValue(':meta_key', $key);
if ($stmt->execute()) {
if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new BuildMeta($data);
+ return new BuildMeta($this->storeRegistry, $data);
}
}
@@ -102,34 +54,26 @@ public function getByKey($buildId, $key)
/**
* Get multiple BuildMeta by BuildId.
*
- * @param int $buildId
- * @param int $limit
- * @param string $useConnection
- *
- * @return array
- *
* @throws HttpException
*/
- public function getByBuildId($buildId, $limit = 1000, $useConnection = 'read')
+ public function getByBuildId(int $buildId, int $limit = 1000, string $useConnection = 'read'): array
{
- if (is_null($buildId)) {
+ if (\is_null($buildId)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{build_id}} = :build_id LIMIT :limit';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':build_id', $buildId);
$stmt->bindValue(':limit', (int)$limit, PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new BuildMeta($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new BuildMeta($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
@@ -139,30 +83,22 @@ public function getByBuildId($buildId, $limit = 1000, $useConnection = 'read')
/**
* Only used by an upgrade migration to move errors from build_meta to build_error
- *
- * @param int $limit
- *
- * @return array
*/
- public function getErrorsForUpgrade($limit)
+ public function getErrorsForUpgrade(int $limit): array
{
$query = 'SELECT * FROM {{' . $this->tableName . '}}
WHERE {{meta_key}} IN (\'phpmd-data\', \'phpcs-data\', \'phpdoccheck-data\', \'technical_debt-data\')
ORDER BY {{id}} ASC LIMIT :limit';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $map = fn ($item) => new BuildMeta($this->storeRegistry, $item);
- $map = function ($item) {
- return new BuildMeta($item);
- };
- $rtn = array_map($map, $res);
-
- return $rtn;
+ return \array_map($map, $res);
} else {
return [];
}
diff --git a/src/Store/BuildStore.php b/src/Store/BuildStore.php
index 6663b98a3..98fd7b814 100644
--- a/src/Store/BuildStore.php
+++ b/src/Store/BuildStore.php
@@ -1,108 +1,53 @@
+ * @author Dmitry Khomutov
*/
class BuildStore extends Store
{
- /**
- * @var string
- */
- protected $tableName = 'builds';
-
- /**
- * @var string
- */
- protected $modelName = '\PHPCensor\Model\Build';
-
- /**
- * @var string
- */
- protected $primaryKey = 'id';
-
- /**
- * Get a Build by primary key (Id)
- *
- * @param int $key
- * @param string $useConnection
- *
- * @return Build|null
- */
- public function getByPrimaryKey($key, $useConnection = 'read')
- {
- return $this->getById($key, $useConnection);
- }
-
- /**
- * Get a single Build by Id.
- *
- * @param int $id
- * @param string $useConnection
- *
- * @return Build|null
- *
- * @throws HttpException
- */
- public function getById($id, $useConnection = 'read')
- {
- if (is_null($id)) {
- throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
- }
+ protected string $tableName = 'builds';
- $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} = :id LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
- $stmt->bindValue(':id', $id);
-
- if ($stmt->execute()) {
- if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new Build($data);
- }
- }
-
- return null;
- }
+ protected string $modelName = Build::class;
/**
* Get multiple Build by ProjectId.
*
- * @param int $projectId
- * @param int $limit
- * @param string $useConnection
- *
- * @return array
- *
* @throws HttpException
*/
- public function getByProjectId($projectId, $limit = 1000, $useConnection = 'read')
+ public function getByProjectId(int $projectId, int $limit = 1000, string $useConnection = 'read'): array
{
- if (is_null($projectId)) {
+ if (\is_null($projectId)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :project_id LIMIT :limit';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':project_id', $projectId);
$stmt->bindValue(':limit', (int)$limit, PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new Build($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new Build($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
@@ -113,34 +58,26 @@ public function getByProjectId($projectId, $limit = 1000, $useConnection = 'read
/**
* Get multiple Build by Status.
*
- * @param int $status
- * @param int $limit
- * @param string $useConnection
- *
- * @return array
- *
* @throws HttpException
*/
- public function getByStatus($status, $limit = 1000, $useConnection = 'read')
+ public function getByStatus(int $status, int $limit = 1000, string $useConnection = 'read'): array
{
- if (is_null($status)) {
+ if (\is_null($status)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{status}} = :status ORDER BY {{create_date}} ASC LIMIT :limit';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':status', $status);
$stmt->bindValue(':limit', (int)$limit, PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new Build($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new Build($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
@@ -148,52 +85,37 @@ public function getByStatus($status, $limit = 1000, $useConnection = 'read')
}
}
- /**
- * @param int $limit
- * @param int $offset
- *
- * @return array
- */
- public function getBuilds($limit = 5, $offset = 0)
+ public function getBuilds(int $limit = 5, int $offset = 0): array
{
$query = 'SELECT * FROM {{' . $this->tableName . '}} ORDER BY {{id}} DESC LIMIT :limit OFFSET :offset';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $map = fn ($item) => new Build($this->storeRegistry, $item);
- $map = function ($item) {
- return new Build($item);
- };
- $rtn = array_map($map, $res);
-
- return $rtn;
+ return \array_map($map, $res);
} else {
return [];
}
}
/**
- * @param int $projectId
- * @param string $branch
- *
- * @return Build|null
- *
* @throws Exception
*/
- public function getLatestBuildByProjectAndBranch($projectId, $branch)
+ public function getLatestBuildByProjectAndBranch(int $projectId, string $branch): ?Build
{
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :project_id AND {{branch}} = :branch ORDER BY {{id}} DESC';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':project_id', $projectId);
$stmt->bindValue(':branch', $branch);
if ($stmt->execute() && $data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new Build($data);
+ return new Build($this->storeRegistry, $data);
}
return null;
@@ -202,24 +124,19 @@ public function getLatestBuildByProjectAndBranch($projectId, $branch)
/**
* Return an array of the latest builds for a given project.
*
- * @param int $projectId
- * @param int $limit
- *
- * @return array
- *
* @throws Exception
*/
- public function getLatestBuilds($projectId = null, $limit = 5)
+ public function getLatestBuilds(?int $projectId = null, int $limit = 5): array
{
- if (!is_null($projectId)) {
+ if (!\is_null($projectId)) {
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :pid ORDER BY {{id}} DESC LIMIT :limit';
} else {
$query = 'SELECT * FROM {{' . $this->tableName . '}} ORDER BY {{id}} DESC LIMIT :limit';
}
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
- if (!is_null($projectId)) {
+ if (!\is_null($projectId)) {
$stmt->bindValue(':pid', $projectId);
}
@@ -227,13 +144,9 @@ public function getLatestBuilds($projectId = null, $limit = 5)
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $map = fn ($item) => new Build($this->storeRegistry, $item);
- $map = function ($item) {
- return new Build($item);
- };
- $rtn = array_map($map, $res);
-
- return $rtn;
+ return \array_map($map, $res);
} else {
return [];
}
@@ -241,37 +154,27 @@ public function getLatestBuilds($projectId = null, $limit = 5)
/**
* Return the latest build for a specific project, of a specific build status.
- *
- * @param int|null $projectId
- * @param int $status
- *
- * @return array|Build
*/
- public function getLastBuildByStatus($projectId = null, $status = Build::STATUS_SUCCESS)
+ public function getLastBuildByStatus(?int $projectId = null, int $status = Build::STATUS_SUCCESS): ?Build
{
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :pid AND {{status}} = :status ORDER BY {{id}} DESC LIMIT 1';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':pid', $projectId);
$stmt->bindValue(':status', $status);
if ($stmt->execute()) {
if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new Build($data);
+ return new Build($this->storeRegistry, $data);
}
- } else {
- return [];
}
+
+ return null;
}
/**
* Return an array of the latest builds for all projects.
- *
- * @param int $limitByProject
- * @param int $limitAll
- *
- * @return array
*/
- public function getAllProjectsLatestBuilds($limitByProject = 5, $limitAll = 10)
+ public function getAllProjectsLatestBuilds(int $limitByProject = 5, int $limitAll = 10): array
{
// don't fetch log field - contain many data
$query = '
@@ -294,7 +197,7 @@ public function getAllProjectsLatestBuilds($limitByProject = 5, $limitAll = 10)
LIMIT 10000
';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -315,37 +218,35 @@ public function getAllProjectsLatestBuilds($limitByProject = 5, $limitAll = 10)
];
}
$build = null;
- if (count($projects[$projectId][$environment]['latest']) < $limitByProject) {
- $build = new Build($item);
+ if (\count($projects[$projectId][$environment]['latest']) < $limitByProject) {
+ $build = new Build($this->storeRegistry, $item);
$projects[$projectId][$environment]['latest'][] = $build;
}
- if (count($latest) < $limitAll) {
- if (is_null($build)) {
- $build = new Build($item);
+ if (\count($latest) < $limitAll) {
+ if (\is_null($build)) {
+ $build = new Build($this->storeRegistry, $item);
}
$latest[] = $build;
}
if (empty($projects[$projectId][$environment]['success']) && Build::STATUS_SUCCESS === $item['status']) {
- if (is_null($build)) {
- $build = new Build($item);
+ if (\is_null($build)) {
+ $build = new Build($this->storeRegistry, $item);
}
$projects[$projectId][$environment]['success'] = $build;
}
if (empty($projects[$projectId][$environment]['failed']) && Build::STATUS_FAILED === $item['status']) {
- if (is_null($build)) {
- $build = new Build($item);
+ if (\is_null($build)) {
+ $build = new Build($this->storeRegistry, $item);
}
$projects[$projectId][$environment]['failed'] = $build;
}
}
foreach ($projects as $idx => $project) {
- $projects[$idx] = array_filter($project, function ($val) {
- return ($val['latest'][0]->getStatus() != Build::STATUS_SUCCESS);
- });
+ $projects[$idx] = \array_filter($project, fn ($val) => $val['latest'][0]->getStatus() !== Build::STATUS_SUCCESS);
}
- $projects = array_filter($projects);
+ $projects = \array_filter($projects);
return ['projects' => $projects, 'latest' => $latest];
} else {
@@ -355,30 +256,22 @@ public function getAllProjectsLatestBuilds($limitByProject = 5, $limitAll = 10)
/**
* Return an array of builds for a given project and commit ID.
- *
- * @param int $projectId
- * @param string $commitId
- *
- * @return array
*/
- public function getByProjectAndCommit($projectId, $commitId)
+ public function getByProjectAndCommit(int $projectId, string $commitId): array
{
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :project_id AND {{commit_id}} = :commit_id';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':project_id', $projectId);
$stmt->bindValue(':commit_id', $commitId);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $map = fn ($item) => new Build($this->storeRegistry, $item);
- $map = function ($item) {
- return new Build($item);
- };
-
- $rtn = array_map($map, $res);
+ $rtn = \array_map($map, $res);
- return ['items' => $rtn, 'count' => count($rtn)];
+ return ['items' => $rtn, 'count' => \count($rtn)];
} else {
return ['items' => [], 'count' => 0];
}
@@ -387,22 +280,16 @@ public function getByProjectAndCommit($projectId, $commitId)
/**
* Returns all registered branches for project
*
- * @param int $projectId
- *
- * @return array
- *
* @throws Exception
*/
- public function getBuildBranches($projectId)
+ public function getBuildBranches(int $projectId): array
{
$query = 'SELECT DISTINCT {{branch}} FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :project_id';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':project_id', $projectId);
if ($stmt->execute()) {
- $res = $stmt->fetchAll(PDO::FETCH_COLUMN);
-
- return $res;
+ return $stmt->fetchAll(PDO::FETCH_COLUMN);
} else {
return [];
}
@@ -410,16 +297,8 @@ public function getBuildBranches($projectId)
/**
* Return build metadata by key, project and optionally build id.
- *
- * @param string $key
- * @param int $projectId
- * @param int|null $buildId
- * @param string|null $branch
- * @param int $numResults
- *
- * @return array|null
*/
- public function getMeta($key, $projectId, $buildId = null, $branch = null, $numResults = 1)
+ public function getMeta(string $key, ?int $projectId, ?int $buildId = null, ?string $branch = null, int $numResults = 1): ?array
{
$query = 'SELECT bm.build_id, bm.meta_key, bm.meta_value
FROM {{build_metas}} AS {{bm}}
@@ -435,19 +314,19 @@ public function getMeta($key, $projectId, $buildId = null, $branch = null, $numR
}
// Include specific branch information if required:
- if (!is_null($branch)) {
+ if (!\is_null($branch)) {
$query .= ' AND b.branch = :branch ';
}
$query .= ' ORDER BY bm.id DESC LIMIT :numResults';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':key', $key, PDO::PARAM_STR);
- $stmt->bindValue(':projectId', (int)$projectId, PDO::PARAM_INT);
- $stmt->bindValue(':buildId', (int)$buildId, PDO::PARAM_INT);
- $stmt->bindValue(':numResults', (int)$numResults, PDO::PARAM_INT);
+ $stmt->bindValue(':projectId', $projectId, PDO::PARAM_INT);
+ $stmt->bindValue(':buildId', $buildId, PDO::PARAM_INT);
+ $stmt->bindValue(':numResults', $numResults, PDO::PARAM_INT);
- if (!is_null($branch)) {
+ if (!\is_null($branch)) {
$stmt->bindValue(':branch', $branch, PDO::PARAM_STR);
}
@@ -455,11 +334,11 @@ public function getMeta($key, $projectId, $buildId = null, $branch = null, $numR
$rtn = $stmt->fetchAll(PDO::FETCH_ASSOC);
/** @var BuildErrorStore $errorStore */
- $errorStore = Factory::getStore('BuildError');
+ $errorStore = $this->storeRegistry->get('BuildError');
- $rtn = array_reverse($rtn);
- $rtn = array_map(function ($item) use ($key, $errorStore, $buildId) {
- $item['meta_value'] = json_decode($item['meta_value'], true);
+ $rtn = \array_reverse($rtn);
+ $rtn = \array_map(function ($item) use ($key, $errorStore, $buildId) {
+ $item['meta_value'] = \json_decode($item['meta_value'], true);
if ('plugin-summary' === $key) {
foreach ($item['meta_value'] as $stage => $stageData) {
foreach ($stageData as $plugin => $pluginData) {
@@ -474,7 +353,7 @@ public function getMeta($key, $projectId, $buildId = null, $branch = null, $numR
return $item;
}, $rtn);
- if (!count($rtn)) {
+ if (!\count($rtn)) {
return null;
} else {
return $rtn;
@@ -486,18 +365,14 @@ public function getMeta($key, $projectId, $buildId = null, $branch = null, $numR
/**
* Set a metadata value for a given project and build ID.
- *
- * @param int $buildId
- * @param string $key
- * @param string $value
*/
- public function setMeta($buildId, $key, $value)
+ public function setMeta(int $buildId, string $key, string $value): void
{
/** @var BuildMetaStore $store */
- $store = Factory::getStore('BuildMeta');
+ $store = $this->storeRegistry->get('BuildMeta');
$meta = $store->getByKey($buildId, $key);
- if (is_null($meta)) {
- $meta = new BuildMeta();
+ if (\is_null($meta)) {
+ $meta = new BuildMeta($this->storeRegistry);
$meta->setBuildId($buildId);
$meta->setMetaKey($key);
}
@@ -506,10 +381,10 @@ public function setMeta($buildId, $key, $value)
$store->save($meta);
}
- public function deleteAllByProject($projectId)
+ public function deleteAllByProject(int $projectId): int
{
- $q = Database::getConnection('write')
- ->prepareCommon(
+ $q = $this->databaseManager->getConnection('write')
+ ->prepare(
'DELETE FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :project_id'
);
$q->bindValue(':project_id', $projectId);
@@ -519,33 +394,25 @@ public function deleteAllByProject($projectId)
}
/**
- * @param int $projectId
- * @param int $keep
- *
- * @return array
- *
* @throws HttpException
*/
- public function getOldByProject($projectId, $keep = 100)
+ public function getOldByProject(int $projectId, int $keep = 100): array
{
- if (is_null($projectId)) {
+ if (\is_null($projectId)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :project_id ORDER BY {{create_date}} DESC LIMIT 1000000 OFFSET :keep';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':project_id', $projectId);
$stmt->bindValue(':keep', (int)$keep, PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $map = fn ($item) => new Build($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $map = function ($item) {
- return new Build($item);
- };
- $rtn = array_map($map, $res);
-
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
}
@@ -554,17 +421,13 @@ public function getOldByProject($projectId, $keep = 100)
}
/**
- * @param int $buildId
- *
- * @return int
- *
* @throws Exception
*/
- public function getNewErrorsCount($buildId)
+ public function getNewErrorsCount(int $buildId): int
{
$query = 'SELECT COUNT(*) AS {{total}} FROM {{build_errors}} WHERE {{build_id}} = :build_id AND {{is_new}} = true';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':build_id', $buildId);
@@ -578,57 +441,114 @@ public function getNewErrorsCount($buildId)
}
/**
- * @param int $buildId
- *
- * @return int
- *
* @throws Exception
*/
- public function getErrorsCount($buildId)
+ public function getErrorsCount(int $buildId): int
{
$query = 'SELECT COUNT(*) AS {{total}} FROM {{build_errors}} WHERE {{build_id}} = :build_id';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
- $stmt->bindValue(':build_id', $buildId);
+ if ($stmt) {
+ $stmt->bindValue(':build_id', $buildId);
- if ($stmt->execute()) {
- $res = $stmt->fetch(PDO::FETCH_ASSOC);
+ if ($stmt->execute()) {
+ $res = $stmt->fetch(PDO::FETCH_ASSOC);
- return (int)$res['total'];
+ return (int)$res['total'];
+ }
}
return 0;
}
/**
- * @param int $buildId
- * @param int $projectId
- * @param string $branch
- *
- * @return array
- *
* @throws Exception
*/
- public function getBuildErrorsTrend($buildId, $projectId, $branch)
+ public function getTestCoverage(int $buildId): string
+ {
+ $coverage = '0.00';
+ $type = 'lines';
+
+ try {
+ $build = $this->getById($buildId);
+
+ if (isset($build) && $build instanceof Build) {
+ $coverageMeta = $this->getMeta(
+ 'php_unit-coverage',
+ $build->getProjectId(),
+ $build->getId(),
+ $build->getBranch()
+ );
+
+ if ($coverageMeta && isset($coverageMeta[0]['meta_value'][$type])) {
+ $coverage = $coverageMeta[0]['meta_value'][$type];
+ }
+ }
+ } catch (\Throwable $e) {
+ }
+
+ return $coverage;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function getBuildErrorsTrend(int $buildId, int $projectId, string $branch): array
{
$query = '
SELECT b.id AS {{build_id}}, count(be.id) AS {{count}} FROM {{' . $this->tableName . '}} AS b
LEFT JOIN {{build_errors}} AS be
ON b.id = be.build_id
-WHERE b.project_id = :project_id AND b.branch = :branch AND b.id <= :build_id
+WHERE b.project_id = :project_id
+ AND b.branch = :branch
+ AND b.id < :build_id
+ AND b.status NOT IN (' . Build::STATUS_PENDING . ', ' . Build::STATUS_RUNNING . ')
GROUP BY b.id
-order BY b.id DESC
-LIMIT 2';
+ORDER BY b.id DESC
+LIMIT 1';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
- $stmt->bindValue(':build_id', $buildId, PDO::PARAM_INT);
- $stmt->bindValue(':project_id', $projectId, PDO::PARAM_INT);
- $stmt->bindValue(':branch', $branch, PDO::PARAM_STR);
+ if ($stmt) {
+ $stmt->bindValue(':build_id', $buildId, PDO::PARAM_INT);
+ $stmt->bindValue(':project_id', $projectId, PDO::PARAM_INT);
+ $stmt->bindValue(':branch', $branch, PDO::PARAM_STR);
- if ($stmt->execute()) {
- return $stmt->fetchAll(PDO::FETCH_ASSOC);
+ if ($stmt->execute()) {
+ return $stmt->fetchAll(PDO::FETCH_ASSOC);
+ }
+ }
+
+ return [];
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function getBuildTestCoverageTrend(int $buildId, int $projectId, string $branch): array
+ {
+ $query = '
+SELECT b.id AS {{build_id}}, bm.coverage AS {{coverage}} FROM {{' . $this->tableName . '}} AS b
+LEFT JOIN (SELECT {{build_id}}, {{meta_value}} AS {{coverage}} FROM {{build_metas}} WHERE {{meta_key}} = \'php_unit-coverage\') AS bm
+ON b.id = bm.build_id
+WHERE b.project_id = :project_id
+ AND b.branch = :branch
+ AND b.id < :build_id
+ AND b.status NOT IN (' . Build::STATUS_PENDING . ', ' . Build::STATUS_RUNNING . ')
+ORDER BY b.id DESC
+LIMIT 1';
+
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
+
+ if ($stmt) {
+ $stmt->bindValue(':build_id', $buildId, PDO::PARAM_INT);
+ $stmt->bindValue(':project_id', $projectId, PDO::PARAM_INT);
+ $stmt->bindValue(':branch', $branch, PDO::PARAM_STR);
+
+ if ($stmt->execute()) {
+ return $stmt->fetchAll(PDO::FETCH_ASSOC);
+ }
}
return [];
diff --git a/src/Store/EnvironmentStore.php b/src/Store/EnvironmentStore.php
index 60f56bdaf..01c6192b0 100644
--- a/src/Store/EnvironmentStore.php
+++ b/src/Store/EnvironmentStore.php
@@ -1,98 +1,47 @@
+ */
class EnvironmentStore extends Store
{
- /**
- * @var string
- */
- protected $tableName = 'environments';
-
- /**
- * @var string
- */
- protected $modelName = '\PHPCensor\Model\Environment';
+ protected string $tableName = 'environments';
- /**
- * @var string
- */
- protected $primaryKey = 'id';
-
- /**
- * Get a Environment by primary key (Id)
- *
- * @param int $key
- * @param string $useConnection
- *
- * @return Environment|null
- */
- public function getByPrimaryKey($key, $useConnection = 'read')
- {
- return $this->getById($key, $useConnection);
- }
-
- /**
- * Get a single Environment by Id.
- *
- * @param int $id
- * @param string $useConnection
- *
- * @return Environment|null
- *
- * @throws HttpException
- */
- public function getById($id, $useConnection = 'read')
- {
- if (is_null($id)) {
- throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
- }
-
- $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} = :id LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
- $stmt->bindValue(':id', $id);
-
- if ($stmt->execute()) {
- if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new Environment($data);
- }
- }
-
- return null;
- }
+ protected string $modelName = Environment::class;
/**
* Get a single Environment by Name.
*
- * @param string $name
- * @param int $projectId
- * @param string $useConnection
- *
- * @return Environment|null
- *
* @throws HttpException
*/
- public function getByNameAndProjectId($name, $projectId, $useConnection = 'read')
+ public function getByNameAndProjectId(string $name, int $projectId, string $useConnection = 'read'): ?Environment
{
- if (is_null($name)) {
+ if (\is_null($name)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{name}} = :name AND {{project_id}} = :project_id LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':name', $name);
$stmt->bindValue(':project_id', $projectId);
if ($stmt->execute()) {
if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new Environment($data);
+ return new Environment($this->storeRegistry, $data);
}
}
@@ -102,33 +51,26 @@ public function getByNameAndProjectId($name, $projectId, $useConnection = 'read'
/**
* Get multiple Environment by Project id.
*
- * @param int $projectId
- * @param string $useConnection
- *
- * @return array
- *
* @throws Exception
*/
- public function getByProjectId($projectId, $useConnection = 'read')
+ public function getByProjectId(int $projectId, string $useConnection = 'read'): array
{
- if (is_null($projectId)) {
- throw new Exception('Value passed to ' . __FUNCTION__ . ' cannot be null.');
+ if (\is_null($projectId)) {
+ throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{project_id}} = :project_id';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':project_id', $projectId);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new Environment($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new Environment($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
diff --git a/src/Store/Factory.php b/src/Store/Factory.php
deleted file mode 100644
index d076476f3..000000000
--- a/src/Store/Factory.php
+++ /dev/null
@@ -1,65 +0,0 @@
-loadStore($storeName);
- }
-
- protected function __construct()
- {
- }
-
- /**
- * @param string $store
- *
- * @return Store;
- */
- public function loadStore($store)
- {
- if (!isset($this->loadedStores[$store])) {
- $class = 'PHPCensor\\Store\\' . $store . 'Store';
- $obj = new $class();
-
- $this->loadedStores[$store] = $obj;
- }
-
- return $this->loadedStores[$store];
- }
-}
diff --git a/src/Store/ProjectGroupStore.php b/src/Store/ProjectGroupStore.php
index 59c9b186b..b1421e9c2 100644
--- a/src/Store/ProjectGroupStore.php
+++ b/src/Store/ProjectGroupStore.php
@@ -1,97 +1,45 @@
+ */
class ProjectGroupStore extends Store
{
- /**
- * @var string
- */
- protected $tableName = 'project_groups';
-
- /**
- * @var string
- */
- protected $modelName = '\PHPCensor\Model\ProjectGroup';
+ protected string $tableName = 'project_groups';
- /**
- * @var string
- */
- protected $primaryKey = 'id';
-
- /**
- * Get a ProjectGroup by primary key (Id)
- *
- * @param int $key
- * @param string $useConnection
- *
- * @return ProjectGroup|null
- */
- public function getByPrimaryKey($key, $useConnection = 'read')
- {
- return $this->getById($key, $useConnection);
- }
-
- /**
- * Get a single ProjectGroup by Id.
- *
- * @param int $id
- * @param string $useConnection
- *
- * @return ProjectGroup|null
- *
- * @throws HttpException
- */
- public function getById($id, $useConnection = 'read')
- {
- if (is_null($id)) {
- throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
- }
-
- $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} = :id LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
-
- $stmt->bindValue(':id', $id);
-
- if ($stmt->execute()) {
- if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new ProjectGroup($data);
- }
- }
-
- return null;
- }
+ protected string $modelName = ProjectGroup::class;
/**
* Get a single ProjectGroup by title.
*
- * @param int $title
- * @param string $useConnection
- *
- * @return ProjectGroup|null
- *
* @throws HttpException
*/
- public function getByTitle($title, $useConnection = 'read')
+ public function getByTitle(string $title, string $useConnection = 'read'): ?ProjectGroup
{
- if (is_null($title)) {
+ if (\is_null($title)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{title}} = :title LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':title', $title);
if ($stmt->execute()) {
if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new ProjectGroup($data);
+ return new ProjectGroup($this->storeRegistry, $data);
}
}
diff --git a/src/Store/ProjectStore.php b/src/Store/ProjectStore.php
index cdcdc461c..f9151207d 100644
--- a/src/Store/ProjectStore.php
+++ b/src/Store/ProjectStore.php
@@ -1,99 +1,51 @@
+ * @author Dmitry Khomutov
*/
class ProjectStore extends Store
{
- /**
- * @var string
- */
- protected $tableName = 'projects';
+ protected string $tableName = 'projects';
- /**
- * @var string
- */
- protected $modelName = '\PHPCensor\Model\Project';
-
- /**
- * @var string
- */
- protected $primaryKey = 'id';
-
- /**
- * Get a Project by primary key (Id)
- *
- * @param int $key
- * @param string $useConnection
- *
- * @return Project|null
- */
- public function getByPrimaryKey($key, $useConnection = 'read')
- {
- return $this->getById($key, $useConnection);
- }
-
- /**
- * Get a single Project by Id.
- *
- * @param int $id
- * @param string $useConnection
- *
- * @return Project|null
- *
- * @throws HttpException
- */
- public function getById($id, $useConnection = 'read')
- {
- if (is_null($id)) {
- throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
- }
-
- $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} = :id LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
- $stmt->bindValue(':id', $id);
-
- if ($stmt->execute()) {
- if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new Project($data);
- }
- }
-
- return null;
- }
+ protected string $modelName = Project::class;
/**
* Get a single Project by Ids.
*
* @param int[] $values
- * @param string $useConnection
*
* @throws HttpException
*
* @return Project[]
*/
- public function getByIds($values, $useConnection = 'read')
+ public function getByIds(array $values, string $useConnection = 'read'): array
{
if (empty($values)) {
throw new HttpException('Values passed to ' . __FUNCTION__ . ' cannot be empty.');
}
- $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} IN ('.implode(', ', array_map('intval', $values)).')';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} IN (' . \implode(', ', \array_map('intval', $values)).')';
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$rtn = [];
if ($stmt->execute()) {
while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- $rtn[$data['id']] = new Project($data);
+ $rtn[$data['id']] = new Project($this->storeRegistry, $data);
}
}
@@ -103,35 +55,26 @@ public function getByIds($values, $useConnection = 'read')
/**
* Get multiple Project by Title.
*
- * @param string $title
- * @param int $limit
- * @param string $useConnection
- *
- * @return array
- *
* @throws HttpException
*/
- public function getByTitle($title, $limit = 1000, $useConnection = 'read')
+ public function getByTitle(string $title, int $limit = 1000, string $useConnection = 'read'): array
{
- if (is_null($title)) {
+ if (\is_null($title)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
-
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{title}} = :title LIMIT :limit';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':title', $title);
$stmt->bindValue(':limit', (int)$limit, PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new Project($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new Project($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
@@ -142,24 +85,20 @@ public function getByTitle($title, $limit = 1000, $useConnection = 'read')
/**
* Returns a list of all branch names.
*
- *
- * @return array
+ * @param $projectId
*/
- public function getKnownBranches($projectId)
+ public function getKnownBranches(int $projectId): array
{
$query = 'SELECT {{branch}}, COUNT(1) AS {{count}} from {{builds}} WHERE {{project_id}} = :pid GROUP BY {{branch}} ORDER BY {{count}} DESC';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':pid', $projectId);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return $item['branch'];
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => $item['branch'];
- return $rtn;
+ return \array_map($map, $res);
} else {
return [];
}
@@ -167,29 +106,23 @@ public function getKnownBranches($projectId)
/**
* Get a list of all projects, ordered by their title.
- *
- * @param bool $archived
- *
- * @return array
*/
- public function getAll($archived = false)
+ public function getAll(string $useConnection = 'read', bool $archived = false): array
{
$archived = (int)$archived;
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{archived}} = :archived ORDER BY {{title}} ASC';
- $stmt = Database::getConnection('read')->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':archived', $archived);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new Project($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new Project($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
@@ -201,24 +134,17 @@ public function getAll($archived = false)
/**
* Get multiple Project by GroupId.
*
- * @param int $groupId
- * @param bool $archived
- * @param int $limit
- * @param string $useConnection
- *
- * @return array
- *
* @throws Exception
*/
- public function getByGroupId($groupId, $archived = false, $limit = 1000, $useConnection = 'read')
+ public function getByGroupId(int $groupId, bool $archived = false, int $limit = 1000, string $useConnection = 'read'): array
{
- if (is_null($groupId)) {
- throw new Exception('Value passed to ' . __FUNCTION__ . ' cannot be null.');
+ if (\is_null($groupId)) {
+ throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$archived = (int)$archived;
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{group_id}} = :group_id AND {{archived}} = :archived ORDER BY {{title}} LIMIT :limit';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':group_id', $groupId);
$stmt->bindValue(':archived', $archived);
@@ -227,12 +153,10 @@ public function getByGroupId($groupId, $archived = false, $limit = 1000, $useCon
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new Project($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new Project($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
diff --git a/src/Store/SecretStore.php b/src/Store/SecretStore.php
new file mode 100644
index 000000000..e2761a3a0
--- /dev/null
+++ b/src/Store/SecretStore.php
@@ -0,0 +1,54 @@
+
+ */
+class SecretStore extends Store
+{
+ protected string $tableName = 'secrets';
+
+ protected string $modelName = Secret::class;
+
+ /**
+ * Get a single Project by Ids.
+ *
+ * @param string[] $values
+ *
+ * @throws HttpException
+ *
+ * @return Secret[]
+ */
+ public function getByNames(array $values, string $useConnection = 'read'): array
+ {
+ if (empty($values)) {
+ throw new HttpException('Values passed to ' . __FUNCTION__ . ' cannot be empty.');
+ }
+
+ $query = \sprintf(
+ 'SELECT * FROM {{%s}} WHERE {{name}} IN (%s)',
+ $this->tableName,
+ ("'" . \implode('\', \'', $values) . "'")
+ );
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
+
+ $rtn = [];
+ if ($stmt->execute()) {
+ while ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+ $rtn[$data['name']] = new Secret($this->storeRegistry, $data);
+ }
+ }
+
+ return $rtn;
+ }
+}
diff --git a/src/Store/UserStore.php b/src/Store/UserStore.php
index 350fd4c12..fb0ad4a33 100644
--- a/src/Store/UserStore.php
+++ b/src/Store/UserStore.php
@@ -1,98 +1,46 @@
+ * @author Dmitry Khomutov
*/
class UserStore extends Store
{
- /**
- * @var string
- */
- protected $tableName = 'users';
-
- /**
- * @var string
- */
- protected $modelName = '\PHPCensor\Model\User';
-
- /**
- * @var string
- */
- protected $primaryKey = 'id';
-
- /**
- * Get a User by primary key (Id)
- *
- * @param int $key
- * @param string $useConnection
- *
- * @return User|null
- */
- public function getByPrimaryKey($key, $useConnection = 'read')
- {
- return $this->getById($key, $useConnection);
- }
-
- /**
- * Get a single User by Id.
- *
- * @param int $id
- * @param string $useConnection
- *
- * @return User|null
- *
- * @throws HttpException
- */
- public function getById($id, $useConnection = 'read')
- {
- if (is_null($id)) {
- throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
- }
+ protected string $tableName = 'users';
- $query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{id}} = :id LIMIT 1';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
- $stmt->bindValue(':id', $id);
-
- if ($stmt->execute()) {
- if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new User($data);
- }
- }
-
- return null;
- }
+ protected string $modelName = User::class;
/**
* Get a single User by Email.
*
- * @param string $email
- *
* @throws HttpException
- *
- * @return User
*/
- public function getByEmail($email)
+ public function getByEmail(string $email): ?User
{
- if (is_null($email)) {
+ if (\is_null($email)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{email}} = :email LIMIT 1';
- $stmt = Database::getConnection()->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection()->prepare($query);
$stmt->bindValue(':email', $email);
if ($stmt->execute()) {
if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new User($data);
+ return new User($this->storeRegistry, $data);
}
}
@@ -102,25 +50,21 @@ public function getByEmail($email)
/**
* Get a single User by Email or Name.
*
- * @param string $emailOrName
- *
* @throws HttpException
- *
- * @return User
*/
- public function getByEmailOrName($emailOrName)
+ public function getByEmailOrName(string $emailOrName): ?User
{
- if (is_null($emailOrName)) {
+ if (\is_null($emailOrName)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{email}} = :value OR {{name}} = :value LIMIT 1';
- $stmt = Database::getConnection()->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':value', $emailOrName);
if ($stmt->execute()) {
if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new User($data);
+ return new User($this->storeRegistry, $data);
}
}
@@ -130,25 +74,21 @@ public function getByEmailOrName($emailOrName)
/**
* Get a single User by RememberKey.
*
- * @param string $rememberKey
- *
* @throws HttpException
- *
- * @return User
*/
- public function getByRememberKey($rememberKey)
+ public function getByRememberKey(string $rememberKey): ?User
{
- if (is_null($rememberKey)) {
+ if (\is_null($rememberKey)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{remember_key}} = :remember_key LIMIT 1';
- $stmt = Database::getConnection()->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection('read')->prepare($query);
$stmt->bindValue(':remember_key', $rememberKey);
if ($stmt->execute()) {
if ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
- return new User($data);
+ return new User($this->storeRegistry, $data);
}
}
@@ -158,34 +98,26 @@ public function getByRememberKey($rememberKey)
/**
* Get multiple User by Name.
*
- * @param string $name
- * @param int $limit
- * @param string $useConnection
- *
- * @return array
- *
* @throws HttpException
*/
- public function getByName($name, $limit = 1000, $useConnection = 'read')
+ public function getByName(string $name, int $limit = 1000, string $useConnection = 'read'): array
{
- if (is_null($name)) {
+ if (\is_null($name)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{' . $this->tableName . '}} WHERE {{name}} = :name LIMIT :limit';
- $stmt = Database::getConnection($useConnection)->prepareCommon($query);
+ $stmt = $this->databaseManager->getConnection($useConnection)->prepare($query);
$stmt->bindValue(':name', $name);
$stmt->bindValue(':limit', (int)$limit, PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
- $map = function ($item) {
- return new User($item);
- };
- $rtn = array_map($map, $res);
+ $map = fn ($item) => new User($this->storeRegistry, $item);
+ $rtn = \array_map($map, $res);
- $count = count($rtn);
+ $count = \count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
diff --git a/src/Store/WebhookRequestStore.php b/src/Store/WebhookRequestStore.php
new file mode 100644
index 000000000..cb10c635a
--- /dev/null
+++ b/src/Store/WebhookRequestStore.php
@@ -0,0 +1,21 @@
+
+ */
+class WebhookRequestStore extends Store
+{
+ protected string $tableName = 'webhook_requests';
+
+ protected string $modelName = WebhookRequest::class;
+}
diff --git a/src/StoreRegistry.php b/src/StoreRegistry.php
new file mode 100644
index 000000000..4b8eb968a
--- /dev/null
+++ b/src/StoreRegistry.php
@@ -0,0 +1,49 @@
+
+ */
+class StoreRegistry
+{
+ private DatabaseManager $databaseManager;
+
+ /**
+ * A collection of the stores currently loaded by the factory.
+ *
+ * @var Store[]
+ */
+ private array $loadedStores = [];
+
+ public function __construct(DatabaseManager $databaseManager)
+ {
+ $this->databaseManager = $databaseManager;
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ public function get(string $storeName): Store
+ {
+ if (!isset($this->loadedStores[$storeName])) {
+ try {
+ $class = 'PHPCensor\Store\\' . $storeName . 'Store';
+ $store = new $class($this->databaseManager, $this);
+
+ $this->loadedStores[$storeName] = $store;
+ } catch (\Throwable $exception) {
+ throw new RuntimeException($exception->getMessage());
+ }
+ }
+
+ return $this->loadedStores[$storeName];
+ }
+}
diff --git a/src/Traits/Model/Build/GitGetDiffLineNumberTrait.php b/src/Traits/Model/Build/GitGetDiffLineNumberTrait.php
new file mode 100644
index 000000000..8dfde96fb
--- /dev/null
+++ b/src/Traits/Model/Build/GitGetDiffLineNumberTrait.php
@@ -0,0 +1,89 @@
+
+ *
+ * @mixin GitBuild
+ */
+trait GitGetDiffLineNumberTrait
+{
+ /**
+ * Uses git diff to figure out what the diff line position is, based on the error line number.
+ */
+ protected function getDiffLineNumber(Builder $builder, string $file, ?int $line): ?int
+ {
+ $builder->logExecOutput(false);
+
+ $prNumber = $this->getExtra('pull_request_number');
+ $path = $builder->buildPath;
+
+ if (!empty($prNumber)) {
+ $builder->executeCommand('cd "%s" && git diff "origin/%s" "%s"', $path, $this->getBranch(), $file);
+ } else {
+ $commitId = $this->getCommitId();
+ $compare = empty($commitId) ? 'HEAD' : $commitId;
+
+ $builder->executeCommand('cd "%s" && git diff "%s^^" "%s"', $path, $compare, $file);
+ }
+
+ $builder->logExecOutput(true);
+
+ $diff = $builder->getLastOutput();
+
+ $lines = $this->getLinePositions($diff);
+
+ return $lines[(int)$line] ?? null;
+ }
+
+ /**
+ * Take a diff
+ */
+ private function getLinePositions(string $diff): ?array
+ {
+ if (empty($diff)) {
+ return null;
+ }
+
+ $rtn = [];
+
+ $diffLines = \explode(PHP_EOL, $diff);
+
+ while (\count($diffLines)) {
+ $line = \array_shift($diffLines);
+
+ if (\substr($line, 0, 2) === '@@') {
+ \array_unshift($diffLines, $line);
+
+ break;
+ }
+ }
+
+ $lineNumber = 0;
+ $position = 0;
+
+ foreach ($diffLines as $diffLine) {
+ if (\preg_match('/@@\s+\-[0-9]+\,[0-9]+\s+\+([0-9]+)\,([0-9]+)/', $diffLine, $matches)) {
+ $lineNumber = (int)$matches[1] - 1;
+ }
+
+ $rtn[$lineNumber] = $position;
+
+ $lineNumber++;
+ $position++;
+ }
+
+ return $rtn;
+ }
+}
diff --git a/src/Traits/Model/HasCreateDateTrait.php b/src/Traits/Model/HasCreateDateTrait.php
new file mode 100644
index 000000000..e902853d6
--- /dev/null
+++ b/src/Traits/Model/HasCreateDateTrait.php
@@ -0,0 +1,24 @@
+getDataItem('create_date');
+ }
+
+ public function setCreateDate(DateTime $value): bool
+ {
+ return $this->setDataItem('create_date', $value);
+ }
+}
diff --git a/src/Traits/Model/HasUserIdTrait.php b/src/Traits/Model/HasUserIdTrait.php
new file mode 100644
index 000000000..4af5c8cf3
--- /dev/null
+++ b/src/Traits/Model/HasUserIdTrait.php
@@ -0,0 +1,23 @@
+getDataItem('user_id');
+ }
+
+ public function setUserId(?int $value): bool
+ {
+ return $this->setDataItem('user_id', $value);
+ }
+}
diff --git a/src/View.php b/src/View.php
index 1e0bbe067..8e76aa75c 100644
--- a/src/View.php
+++ b/src/View.php
@@ -1,34 +1,30 @@
+ * @author Dmitry Khomutov
+ */
class View
{
- /**
- * @var array
- */
- protected $data = [];
+ protected array $data = [];
- /**
- * @var string
- */
- protected $viewFile;
+ protected string $viewFile;
- /**
- * @var string
- */
- protected static $extension = 'phtml';
+ protected static string $extension = 'phtml';
/**
- * @param string $file
- * @param string|null $path
+ * @throws RuntimeException
*/
- public function __construct($file, $path = null)
+ public function __construct(string $file, ?string $path = null)
{
if (!self::exists($file, $path)) {
throw new RuntimeException('View file does not exist: ' . $file);
@@ -37,106 +33,54 @@ public function __construct($file, $path = null)
$this->viewFile = self::getViewFile($file, $path);
}
- /**
- * @param string $file
- * @param string|null $path
- *
- * @return string
- */
- protected static function getViewFile($file, $path = null)
+ protected static function getViewFile(string $file, ?string $path = null): string
{
- $viewPath = is_null($path) ? (SRC_DIR . 'View/') : $path;
- $fullPath = $viewPath . $file . '.' . static::$extension;
+ $viewPath = \is_null($path) ? (SRC_DIR . 'View/') : $path;
- return $fullPath;
+ return $viewPath . $file . '.' . static::$extension;
}
- /**
- * @param string $file
- * @param string|null $path
- *
- * @return bool
- */
- public static function exists($file, $path = null)
+ public static function exists(string $file, ?string $path = null): bool
{
- if (!file_exists(self::getViewFile($file, $path))) {
+ if (!\file_exists(self::getViewFile($file, $path))) {
return false;
}
return true;
}
- /**
- * @param string $key
- *
- * @return bool
- */
- public function __isset($key)
+ public function __isset(string $key): bool
{
return isset($this->data[$key]);
}
/**
- * @param string $key
- *
* @return mixed
*/
- public function __get($key)
+ public function __get(string $key)
{
return $this->data[$key];
}
/**
- * @param string $key
* @param mixed $value
*/
- public function __set($key, $value)
+ public function __set(string $key, $value): void
{
$this->data[$key] = $value;
}
- /**
- * @return string
- */
- public function render()
+ public function render(): string
{
- extract($this->data);
+ \extract($this->data);
- ob_start();
+ \ob_start();
require($this->viewFile);
- $html = ob_get_contents();
- ob_end_clean();
+ $html = \ob_get_contents();
+ \ob_end_clean();
return $html;
}
-
- /**
- * @return bool
- */
- protected function loginIsDisabled()
- {
- $config = Config::getInstance();
- $disableAuth = (bool)$config->get('php-censor.security.disable_auth', false);
-
- return $disableAuth;
- }
-
- /**
- * @return User|null
- *
- * @throws Exception\HttpException
- */
- protected function getUser()
- {
- if (empty($_SESSION['php-censor-user-id'])) {
- return null;
- }
-
- /** @var UserStore $userStore */
- $userStore = Factory::getStore('User');
-
- return $userStore->getById($_SESSION['php-censor-user-id']);
- }
}
diff --git a/src/View/Build/errors.phtml b/src/View/Build/errors.phtml
index c28a53865..bff36390d 100644
--- a/src/View/Build/errors.phtml
+++ b/src/View/Build/errors.phtml
@@ -14,15 +14,15 @@ $linkTemplate = $build->getFileLinkTemplate();
foreach ($errors as $error):
- $link = str_replace('{BASEFILE}', basename($error->getFile()), $linkTemplate);
- $link = str_replace('{FILE}', $error->getFile(), $link);
- $link = str_replace('{LINE}', $error->getLineStart(), $link);
+ $link = \str_replace('{BASEFILE}', \basename($error->getFile()), $linkTemplate);
+ $link = \str_replace('{FILE}', $error->getFile(), $link);
+ $link = \str_replace('{LINE}', $error->getLineStart(), $link);
if ($error->getLineStart() == $error->getLineEnd() || !$error->getLineEnd()) {
# For Github
- $link = str_replace('-L{LINE_END}', '', $link);
+ $link = \str_replace('-L{LINE_END}', '', $link);
} else {
- $link = str_replace('{LINE_END}', $error->getLineEnd(), $link);
+ $link = \str_replace('{LINE_END}', $error->getLineEnd(), $link);
}
?>
diff --git a/src/View/Build/view.phtml b/src/View/Build/view.phtml
index cd99a2b2f..670314d78 100644
--- a/src/View/Build/view.phtml
+++ b/src/View/Build/view.phtml
@@ -4,11 +4,11 @@ use PHPCensor\Helper\Lang;
use PHPCensor\Helper\Template;
use PHPCensor\Model\Build;
use PHPCensor\Model\BuildError;
-use PHPCensor\Store\EnvironmentStore;
-use PHPCensor\Store\Factory;
+use PHPCensor\Model\Environment;
/**
- * @var Build $build
+ * @var Build $build
+ * @var Environment $environment
*/
?>
@@ -37,7 +37,7 @@ use PHPCensor\Store\Factory;
| = Lang::get('branch'); ?> |
- getSource(), Build::$pullRequestSources, true)): ?>
+ getSource(), Build::$pullRequestSources, true)): ?>
= $build->getRemoteBranch(); ?> :
@@ -59,18 +59,11 @@ use PHPCensor\Store\Factory;
| = Lang::get('environment'); ?> |
getEnvironmentId();
- $environment = null;
- if ($environmentId) {
- /** @var EnvironmentStore $environmentStore */
- $environmentStore = Factory::getStore('Environment');
- $environmentObject = $environmentStore->getById($environmentId);
- if ($environmentObject) {
- $environment = $environmentObject->getName();
- }
+ if ($environment) {
+ $environmentName = $environment->getName();
}
- echo !empty($environment) ? (' ' . $environment) : '—' ;
+ echo !empty($environmentName) ? (' ' . $environmentName) : '—' ;
?>
|
@@ -194,7 +187,7 @@ use PHPCensor\Store\Factory;
= Lang::get('errors'); ?>
- 0
+ 0
= $data['errors_total']; ?>
@@ -334,7 +327,7 @@ use PHPCensor\Store\Factory;
var BUILD_IS_NEW = '= $isNew; ?>';
var ActiveBuild = new Build(= $build->getId(); ?>);
- ActiveBuild.setupBuild(= json_encode($data); ?>, = json_encode($build->getFileLinkTemplate()); ?>);
+ ActiveBuild.setupBuild(= \json_encode($data); ?>, = \json_encode($build->getFileLinkTemplate()); ?>);
var url = document.location.toString();
if (url.match('#')) {
@@ -349,8 +342,8 @@ use PHPCensor\Store\Factory;
' . PHP_EOL;
- }
+ print '' . PHP_EOL;
+}
?>
-
+
| = Lang::get('no_builds_yet'); ?> |
@@ -23,14 +25,14 @@ use PHPCensor\Store\Factory;
switch ($build->getStatus()) {
case 0:
$cls = 'active';
- $subClass = 'info';
+ $subClass = 'info blink-item';
$status = Lang::get('pending');
break;
case 1:
$cls = 'warning';
- $subClass = 'warning';
+ $subClass = 'warning blink-item';
$status = Lang::get('running');
break;
@@ -57,7 +59,7 @@ $branches = $build->getExtra('branches');
getCommitId())) {
- print sprintf(
+ print \sprintf(
'%s %s',
$build->getCommitLink(),
substr($build->getCommitId(), 0, 7),
@@ -69,7 +71,7 @@ $branches = $build->getExtra('branches');
?>
|
- getSource(), Build::$pullRequestSources, true)): ?>
+ getSource(), Build::$pullRequestSources, true)): ?>
= $build->getRemoteBranch(); ?> :
@@ -79,7 +81,7 @@ $branches = $build->getExtra('branches');
= $build->getBranch(); ?>
- = $branches ? ' + '.implode(', ', $branches) : ''; ?>
+ = $branches ? ' + ' . \implode(', ', $branches) : ''; ?>
getTag()): ?> /
@@ -92,38 +94,58 @@ $branches = $build->getExtra('branches');
$environmentId = $build->getEnvironmentId();
$environment = null;
if ($environmentId) {
- /** @var EnvironmentStore $environmentStore */
- $environmentStore = Factory::getStore('Environment');
$environmentObject = $environmentStore->getById($environmentId);
if ($environmentObject) {
$environment = $environmentObject->getName();
}
}
- echo !empty($environment) ? $environment : '—' ;
+ echo !empty($environment) ? ' ' . $environment : '—' ;
?>
|
- = $build->getDuration(); ?> = Lang::get('seconds'); ?>
+ getStatus(), [Build::STATUS_PENDING, Build::STATUS_RUNNING], true)): ?>
+ = $build->getDuration(); ?> = Lang::get('seconds'); ?>
+
|
- = (int)$build->getErrorsTotal(); ?>
- getStatus(), [Build::STATUS_PENDING, Build::STATUS_RUNNING], true)): ?>
+ getStatus(), [Build::STATUS_PENDING, Build::STATUS_RUNNING], true)): ?>
getErrorsTrend(); ?>
-
-
-
-
+
+ = (int)$build->getErrorsTotal(); ?> (= $trend['delta']; ?>)
+
+ = (int)$build->getErrorsTotal(); ?> (+= $trend['delta']; ?>)
+
+ = (int)$build->getErrorsTotal(); ?>
|
- = $build->getErrorsNew(); ?>
+ getStatus(), [Build::STATUS_PENDING, Build::STATUS_RUNNING], true)): ?>
+ getErrorsNew(); ?>
+
+ = $newErrorsCount; ?>
+
+ = $newErrorsCount; ?>
+
+
+ |
+
+ getStatus(), [Build::STATUS_PENDING, Build::STATUS_RUNNING], true)): ?>
+ getTestCoverageTrend(); ?>
+
+ = $build->getTestCoverage(); ?>% (+= $trend['delta']; ?>%)
+
+ = $build->getTestCoverage(); ?>% (= $trend['delta']; ?>%)
+
+ = $build->getTestCoverage(); ?>%
+
+
|
= Lang::get('view'); ?>
- getUser()->getIsAdmin()): ?>
+ getIsAdmin()): ?>
diff --git a/src/View/Project/edit.phtml b/src/View/Project/edit.phtml
index d5b4f1e3c..a3eea3517 100644
--- a/src/View/Project/edit.phtml
+++ b/src/View/Project/edit.phtml
@@ -34,7 +34,7 @@ use PHPCensor\Helper\Lang;
-
+
| |