Merge branch 'refactoring'

This commit is contained in:
Dmitry Khomutov 2018-03-01 15:27:56 +07:00
commit 626e1fe038
No known key found for this signature in database
GPG key ID: EC19426474B37AAC
34 changed files with 826 additions and 527 deletions

View file

@ -11,7 +11,7 @@ setup:
test:
php_unit:
config:
- phpunit.pgsql.xml
- phpunit.xml
php_mess_detector:
allow_failures: true

View file

@ -15,20 +15,16 @@ php:
matrix:
fast_finish: true
env:
- TYPE=mysql
- TYPE=pgsql
install:
- composer selfupdate
- composer install
before_script:
- if [[ "$TYPE" == "mysql" ]]; then mysql -e "create database IF NOT EXISTS b8_test;" -uroot; fi
- if [[ "$TYPE" == "pgsql" ]]; then psql -c 'create database b8_test;' -U postgres; fi
- mysql -e "create database IF NOT EXISTS b8_test;" -uroot
- psql -c 'create database b8_test;' -U postgres
script:
- vendor/bin/phpunit --configuration phpunit.$TYPE.xml --coverage-clover=coverage.xml
- vendor/bin/phpunit --configuration phpunit.xml --coverage-clover=coverage.xml
after_success:
- bash <(curl -s https://codecov.io/bash)

View file

@ -1,27 +1,27 @@
<?php
if (!defined('ROOT_DIR')) {
define('ROOT_DIR', __DIR__ . DIRECTORY_SEPARATOR);
define('ROOT_DIR', __DIR__ . '/');
}
if (!defined('SRC_DIR')) {
define('SRC_DIR', ROOT_DIR . 'src' . DIRECTORY_SEPARATOR . 'PHPCensor' . DIRECTORY_SEPARATOR);
define('SRC_DIR', ROOT_DIR . 'src/PHPCensor/');
}
if (!defined('PUBLIC_DIR')) {
define('PUBLIC_DIR', ROOT_DIR . 'public' . DIRECTORY_SEPARATOR);
define('PUBLIC_DIR', ROOT_DIR . 'public/');
}
if (!defined('APP_DIR')) {
define('APP_DIR', ROOT_DIR . 'app' . DIRECTORY_SEPARATOR);
define('APP_DIR', ROOT_DIR . 'app/');
}
if (!defined('BIN_DIR')) {
define('BIN_DIR', ROOT_DIR . 'bin' . DIRECTORY_SEPARATOR);
define('BIN_DIR', ROOT_DIR . 'bin/');
}
if (!defined('RUNTIME_DIR')) {
define('RUNTIME_DIR', ROOT_DIR . 'runtime' . DIRECTORY_SEPARATOR);
define('RUNTIME_DIR', ROOT_DIR . 'runtime/');
}
require_once(ROOT_DIR . 'vendor/autoload.php');
@ -30,7 +30,7 @@ require_once(ROOT_DIR . 'vendor/autoload.php');
$conf = [];
$conf['b8']['app']['namespace'] = 'PHPCensor';
$conf['b8']['app']['default_controller'] = 'Home';
$conf['b8']['view']['path'] = SRC_DIR . 'View' . DIRECTORY_SEPARATOR;
$conf['b8']['view']['path'] = SRC_DIR . 'View/';
$config = new b8\Config($conf);

View file

@ -1,115 +1,130 @@
{
"name": "php-censor/php-censor",
"description": "PHP Censor is a open source self-hosted continuous integration server for PHP projects (PHPCI fork).",
"minimum-stability": "stable",
"type": "application",
"keywords": ["php", "php-censor", "phpci", "ci-server", "testing", "self-hosted", "open-source", "ci", "continuous integration"],
"homepage": "http://php-censor.info",
"license": "BSD-2-Clause",
"authors": [
{
"name": "Dmitry Khomutov",
"email": "poisoncorpsee@gmail.com",
"homepage": "http://corpsee.com",
"role": "PHP Censor developer"
},
{
"name": "Dan Cryer",
"email": "dan.cryer@block8.co.uk",
"homepage": "http://www.block8.co.uk",
"role": "PHPCI developer"
}
],
"support": {
"issues": "https://github.com/php-censor/php-censor/issues",
"source": "https://github.com/php-censor/php-censor"
},
"autoload": {
"psr-4": {
"PHPCensor\\": "src/PHPCensor/",
"b8\\": "src/B8Framework/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\PHPCensor\\": "tests/PHPCensor/",
"Tests\\b8\\": "tests/B8Framework/"
}
},
"require": {
"php": ">=5.6.0",
"ext-openssl": "*",
"ext-pdo": "*",
"ext-json": "*",
"ext-xml": "*",
"ext-curl": "*",
"swiftmailer/swiftmailer": "~5.4.0",
"symfony/yaml": "~3.4.0",
"symfony/console": "~3.4.0",
"symfony/finder": "~3.4.0",
"symfony/dom-crawler": "~3.4.0",
"symfony/css-selector": "~3.4.0",
"symfony/browser-kit": "~3.4.0",
"symfony/process": "~3.4.0",
"symfony/filesystem": "~3.4.0",
"symfony/debug": "~3.4.0",
"symfony/dependency-injection": "~3.4.0",
"symfony/event-dispatcher": "~3.4.0",
"symfony/cache": "~3.4.0",
"psr/log": "~1.0.0",
"monolog/monolog": "~1.22.0",
"pimple/pimple": "~3.0.0",
"robmorgan/phinx": "~0.8.0",
"sensiolabs/ansi-to-html": "~1.1.0",
"pda/pheanstalk": "~3.1.0",
"guzzlehttp/guzzle": "~6.2.0",
"jasongrimes/paginator": "~1.0.0",
"phpunit/phpunit": "~5.7.0",
"codeception/codeception": "~2.3.0",
"phpmd/phpmd": "~2.6.0",
"sebastian/phpcpd": "~2.0.0",
"squizlabs/php_codesniffer": "~2.8.0",
"block8/php-docblock-checker": "~1.3.0",
"phploc/phploc": "~4.0.0",
"jakub-onderka/php-parallel-lint": "~0.9.0",
"sensiolabs/security-checker": "~4.0.0",
"doctrine/instantiator": "~1.0.0",
"phpunit/php-token-stream": "~1.4.0",
"phpdocumentor/reflection-docblock": "~2.0.0",
"oomphinc/composer-installers-extender": "~1.1.0",
"npm-asset/sprintf-js": "~1.0.0",
"npm-asset/codemirror": "~5.23.0",
"bower-asset/admin-lte": "~2.3.0",
"bower-asset/font-awesome": "~4.7.0",
"bower-asset/ionicons": "~2.0.0",
"bower-asset/raphael": "~2.2.0"
},
"suggest": {
"maknz/slack": "For SlackNotify plugin",
"hipchat/hipchat-php": "For HipchatNotify plugin",
"mremi/flowdock": "For FlowdockNotify plugin"
},
"extra": {
"platform": {
"php": "5.6.*"
},
"installer-types": [
"bower-asset",
"npm-asset"
"name": "php-censor/php-censor",
"description": "PHP Censor is a open source self-hosted continuous integration server for PHP projects (PHPCI fork).",
"minimum-stability": "stable",
"type": "application",
"keywords": [
"php",
"php-censor",
"phpci",
"ci-server",
"testing",
"self-hosted",
"open-source",
"ci",
"continuous integration"
],
"installer-paths": {
"public/assets/vendor/{$name}/": ["type:bower-asset", "type:npm-asset"]
}
},
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
]
"homepage": "http://php-censor.info",
"license": "BSD-2-Clause",
"authors": [
{
"name": "Dmitry Khomutov",
"email": "poisoncorpsee@gmail.com",
"homepage": "http://corpsee.com",
"role": "PHP Censor developer"
},
{
"name": "Dan Cryer",
"email": "dan.cryer@block8.co.uk",
"homepage": "http://www.block8.co.uk",
"role": "PHPCI developer"
}
],
"support": {
"issues": "https://github.com/php-censor/php-censor/issues",
"source": "https://github.com/php-censor/php-censor"
},
"autoload": {
"psr-4": {
"PHPCensor\\": "src/PHPCensor/",
"b8\\": "src/B8Framework/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\PHPCensor\\": "tests/PHPCensor/",
"Tests\\b8\\": "tests/B8Framework/"
}
},
"require": {
"php": ">=5.6.0",
"ext-openssl": "*",
"ext-pdo": "*",
"ext-json": "*",
"ext-xml": "*",
"ext-curl": "*",
"swiftmailer/swiftmailer": "~5.4.0",
"symfony/yaml": "~3.4.0",
"symfony/console": "~3.4.0",
"symfony/finder": "~3.4.0",
"symfony/dom-crawler": "~3.4.0",
"symfony/css-selector": "~3.4.0",
"symfony/browser-kit": "~3.4.0",
"symfony/process": "~3.4.0",
"symfony/filesystem": "~3.4.0",
"symfony/debug": "~3.4.0",
"symfony/dependency-injection": "~3.4.0",
"symfony/event-dispatcher": "~3.4.0",
"symfony/cache": "~3.4.0",
"psr/log": "~1.0.0",
"monolog/monolog": "~1.22.0",
"pimple/pimple": "~3.0.0",
"robmorgan/phinx": "~0.8.0",
"sensiolabs/ansi-to-html": "~1.1.0",
"pda/pheanstalk": "~3.1.0",
"guzzlehttp/guzzle": "~6.2.0",
"jasongrimes/paginator": "~1.0.0",
"phpunit/phpunit": "~5.7.0",
"codeception/codeception": "~2.3.0",
"phpmd/phpmd": "~2.6.0",
"sebastian/phpcpd": "~2.0.0",
"squizlabs/php_codesniffer": "~2.8.0",
"block8/php-docblock-checker": "~1.3.0",
"phploc/phploc": "~4.0.0",
"jakub-onderka/php-parallel-lint": "~0.9.0",
"sensiolabs/security-checker": "~4.0.0",
"doctrine/instantiator": "~1.0.0",
"phpunit/php-token-stream": "~1.4.0",
"phpdocumentor/reflection-docblock": "~2.0.0",
"oomphinc/composer-installers-extender": "~1.1.0",
"npm-asset/sprintf-js": "~1.0.0",
"npm-asset/codemirror": "~5.23.0",
"bower-asset/admin-lte": "~2.3.0",
"bower-asset/font-awesome": "~4.7.0",
"bower-asset/ionicons": "~2.0.0",
"bower-asset/raphael": "~2.2.0"
},
"require-dev": {
"phpunit/dbunit": "~2.0.0"
},
"suggest": {
"maknz/slack": "For SlackNotify plugin",
"hipchat/hipchat-php": "For HipchatNotify plugin",
"mremi/flowdock": "For FlowdockNotify plugin"
},
"extra": {
"platform": {
"php": "5.6.*"
},
"installer-types": [
"bower-asset",
"npm-asset"
],
"installer-paths": {
"public/assets/vendor/{$name}/": [
"type:bower-asset",
"type:npm-asset"
]
}
},
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
]
}

70
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "e04dd5f7a7f3a869724c591daf5d8f2e",
"content-hash": "86960b0e8aee816f39921ca1c3e6bfc3",
"packages": [
{
"name": "behat/gherkin",
@ -220,16 +220,16 @@
},
{
"name": "codeception/codeception",
"version": "2.3.8",
"version": "2.3.9",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
"reference": "43eade17a8cd68e9cde401e8585b09d11d41b12d"
"reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/43eade17a8cd68e9cde401e8585b09d11d41b12d",
"reference": "43eade17a8cd68e9cde401e8585b09d11d41b12d",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/104f46fa0bde339f1bcc3a375aac21eb36e65a1e",
"reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e",
"shasum": ""
},
"require": {
@ -310,7 +310,7 @@
"functional testing",
"unit testing"
],
"time": "2018-01-27T22:47:33+00:00"
"time": "2018-02-26T23:29:41+00:00"
},
{
"name": "codeception/stub",
@ -3945,7 +3945,63 @@
"time": "2017-06-30T11:53:12+00:00"
}
],
"packages-dev": [],
"packages-dev": [
{
"name": "phpunit/dbunit",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/dbunit.git",
"reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/5c35d74549c21ba55d0ea74ba89d191a51f8cf25",
"reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"ext-simplexml": "*",
"php": "^5.4 || ^7.0",
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0",
"symfony/yaml": "^2.1 || ^3.0"
},
"bin": [
"dbunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "DbUnit port for PHP/PHPUnit to support database interaction testing.",
"homepage": "https://github.com/sebastianbergmann/dbunit/",
"keywords": [
"database",
"testing",
"xunit"
],
"time": "2016-12-02T14:39:14+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],

View file

@ -1,62 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
backupGlobals="false"
backupStaticAttributes="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./tests/bootstrap.php"
>
<php>
<env name="DB_TYPE" value="pgsql" />
<env name="DB_USER" value="postgres" />
<env name="DB_PASS" value="" />
<env name="DB_NAME" value="b8_test" />
</php>
<testsuites>
<testsuite name="B8Framework Test Suite">
<directory suffix="Test.php">./tests/B8Framework</directory>
</testsuite>
<testsuite name="PHP Censor Helper Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/Helper</directory>
</testsuite>
<testsuite name="PHP Censor Controller Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/Controller</directory>
</testsuite>
<testsuite name="PHP Censor Logging Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/Logging</directory>
</testsuite>
<testsuite name="PHP Censor Model Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/Model</directory>
</testsuite>
<testsuite name="PHP Censor Plugin Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/Plugin</directory>
</testsuite>
<testsuite name="PHP Censor Service Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/Service</directory>
</testsuite>
<testsuite name="PHP Censor Command Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/Command</directory>
</testsuite>
<testsuite name="PHP Censor ProcessControl Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/ProcessControl</directory>
</testsuite>
<testsuite name="PHP Censor Security Test Suite">
<directory suffix="Test.php">./tests/PHPCensor/Security</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
<exclude>
<directory suffix=".php">./src/PHPCensor/Migrations</directory>
<directory suffix=".php">./src/PHPCensor/Languages</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View file

@ -12,10 +12,12 @@
bootstrap="./tests/bootstrap.php"
>
<php>
<env name="DB_TYPE" value="mysql" />
<env name="DB_USER" value="root" />
<env name="DB_PASS" value="" />
<env name="DB_NAME" value="b8_test" />
<const name="MYSQL_USER" value="root" />
<const name="MYSQL_PASSWORD" value="" />
<const name="MYSQL_DBNAME" value="b8_test" />
<const name="POSTGRESQL_USER" value="postgres" />
<const name="POSTGRESQL_PASSWORD" value="" />
<const name="POSTGRESQL_DBNAME" value="b8_test" />
</php>
<testsuites>
<testsuite name="B8Framework Test Suite">

View file

@ -4,11 +4,44 @@ namespace b8;
class Database extends \PDO
{
const MYSQL_TYPE = 'mysql';
const POSTGRESQL_TYPE = 'pgsql';
/**
* @var string
*/
protected $type = 'read';
/**
* @var boolean
*/
protected static $initialised = false;
protected static $servers = ['read' => [], 'write' => []];
protected static $connections = ['read' => null, 'write' => null];
protected static $details = [];
protected static $lastUsed = ['read' => null, 'write' => null];
/**
* @var array
*/
protected static $servers = [
'read' => [],
'write' => []
];
/**
* @var array
*/
protected static $connections = [
'read' => null,
'write' => null
];
/**
* @var array
*/
protected static $dsn = [
'read' => '',
'write' => ''
];
protected static $details = [];
/**
* @param string $table
@ -17,7 +50,7 @@ class Database extends \PDO
*/
public function lastInsertIdExtended($table = null)
{
if ($table && $this->getAttribute(self::ATTR_DRIVER_NAME) == 'pgsql') {
if ($table && self::POSTGRESQL_TYPE === $this->getAttribute(self::ATTR_DRIVER_NAME)) {
return parent::lastInsertId($table . '_id_seq');
}
@ -31,10 +64,11 @@ class Database extends \PDO
self::$servers['read'] = $settings['servers']['read'];
self::$servers['write'] = $settings['servers']['write'];
self::$details['type'] = $settings['type'];
self::$details['db'] = $settings['name'];
self::$details['user'] = $settings['username'];
self::$details['pass'] = $settings['password'];
self::$details['driver'] = $settings['type'];
self::$details['db'] = $settings['name'];
self::$details['user'] = $settings['username'];
self::$details['pass'] = $settings['password'];
self::$initialised = true;
}
@ -52,11 +86,6 @@ class Database extends \PDO
self::init();
}
// If the connection hasn't been used for 5 minutes, force a reconnection:
if (!is_null(self::$lastUsed[$type]) && (time() - self::$lastUsed[$type]) > 300) {
self::$connections[$type] = null;
}
if (is_null(self::$connections[$type])) {
// Shuffle, so we pick a random server:
$servers = self::$servers[$type];
@ -69,29 +98,30 @@ class Database extends \PDO
// Pull the next server:
$server = array_shift($servers);
$dns = self::$details['type'] . ':host=' . $server['host'];
self::$dsn[$type] = self::$details['driver'] . ':host=' . $server['host'];
if (isset($server['port'])) {
$dns .= ';port=' . (integer)$server['port'];
self::$dsn[$type] .= ';port=' . (integer)$server['port'];
}
$dns .= ';dbname=' . self::$details['db'];
self::$dsn[$type] .= ';dbname=' . self::$details['db'];
$pdoOptions = [
\PDO::ATTR_PERSISTENT => false,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_TIMEOUT => 2,
\PDO::ATTR_PERSISTENT => false,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_TIMEOUT => 2,
];
if ('mysql' === self::$details['type']) {
if (self::MYSQL_TYPE === self::$details['driver']) {
$pdoOptions[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'";
}
// Try to connect:
try {
$connection = new self(
$dns,
self::$dsn[$type],
self::$details['user'],
self::$details['pass'],
$pdoOptions
);
$connection->setType($type);
} catch (\PDOException $ex) {
$connection = false;
}
@ -103,41 +133,71 @@ class Database extends \PDO
}
// No connection? Oh dear.
if (!$connection && $type == 'read') {
if (!$connection && $type === 'read') {
throw new \Exception('Could not connect to any ' . $type . ' servers.');
}
self::$connections[$type] = $connection;
}
self::$lastUsed[$type] = time();
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::$lastUsed = ['read' => null, 'write' => null];
self::$initialised = false;
}
public function prepareCommon($statement, array $driver_options = [])
/**
* @param string $statement
*
* @return string
*/
protected function quoteNames($statement)
{
$quote = '';
if ('mysql' === self::$details['type']) {
if (self::MYSQL_TYPE === self::$details['driver']) {
$quote = '`';
} elseif ('pgsql' === self::$details['type']) {
} elseif (self::POSTGRESQL_TYPE === self::$details['driver']) {
$quote = '"';
}
$statement = preg_replace('/{{(.*?)}}/', ($quote . '\1' . $quote), $statement);
return preg_replace('/{{(.*?)}}/', ($quote . '\1' . $quote), $statement);
}
return parent::prepare($statement, $driver_options);
/**
* @param string $statement
* @param array $driver_options
*
* @return \PDOStatement
*/
public function prepareCommon($statement, array $driver_options = [])
{
return parent::prepare($this->quoteNames($statement), $driver_options);
}
}

View file

@ -7,7 +7,6 @@ use Symfony\Component\Cache\Simple\ArrayCache;
class Model
{
public static $sleepable = [];
protected $getters = [];
protected $setters = [];
protected $data = [];
@ -35,82 +34,6 @@ class Model
return $this->tableName;
}
/**
* @param integer $depth
* @param integer $currentDepth
*
* @return array
*/
public function toArray($depth = 2, $currentDepth = 0)
{
if (isset(static::$sleepable) && is_array(static::$sleepable) && count(static::$sleepable)) {
$sleepable = static::$sleepable;
} else {
$sleepable = array_keys($this->getters);
}
$rtn = [];
foreach ($sleepable as $property) {
$rtn[$property] = $this->propertyToArray($property, $currentDepth, $depth);
}
return $rtn;
}
/**
* @param string $property
* @param integer $currentDepth
* @param integer $depth
*
* @return mixed
*/
protected function propertyToArray($property, $currentDepth, $depth)
{
$rtn = null;
if (array_key_exists($property, $this->getters)) {
$method = $this->getters[$property];
$rtn = $this->{$method}();
if (is_object($rtn) || is_array($rtn)) {
$rtn = ($depth > $currentDepth) ? $this->valueToArray($rtn, $currentDepth, $depth) : null;
}
}
return $rtn;
}
/**
* @param mixed $value
* @param integer $currentDepth
* @param integer $depth
*
* @return mixed
*/
protected function valueToArray($value, $currentDepth, $depth)
{
$rtn = null;
if (!is_null($value)) {
if (is_object($value) && method_exists($value, 'toArray')) {
$rtn = $value->toArray($depth, $currentDepth + 1);
} elseif (is_array($value)) {
$childArray = [];
foreach ($value as $k => $v) {
$childArray[$k] = $this->valueToArray($v, $currentDepth + 1, $depth);
}
$rtn = $childArray;
} else {
$rtn = (is_string($value) && !mb_check_encoding($value, 'UTF-8'))
? mb_convert_encoding($value, 'UTF-8')
: $value;
}
}
return $rtn;
}
/**
* @return array
*/

View file

@ -7,7 +7,7 @@ use PHPCensor\Model\Build;
/**
* BuildFactory - Takes in a generic "Build" and returns a type-specific build model.
*
*
* @author Dan Cryer <dan@block8.co.uk>
*/
class BuildFactory
@ -43,33 +43,33 @@ class BuildFactory
if (!empty($project)) {
switch ($project->getType()) {
case 'remote':
$type = 'RemoteGitBuild';
break;
case 'local':
$type = 'LocalBuild';
break;
case 'git':
$type = 'GitBuild';
break;
case 'github':
$type = 'GithubBuild';
break;
case 'bitbucket':
$type = 'BitbucketBuild';
break;
case 'bitbuckethg':
$type = 'BitbucketHgBuild';
break;
case 'gitlab':
$type = 'GitlabBuild';
break;
case 'hg':
$type = 'MercurialBuild';
break;
case 'svn':
$type = 'SubversionBuild';
break;
case 'gogs':
$type = 'GogsBuild';
break;
case 'hg':
$type = 'HgBuild';
break;
case 'bitbucket-hg':
$type = 'BitbucketHgBuild';
break;
case 'svn':
$type = 'SvnBuild';
break;
default:
return $build;
}

View file

@ -300,18 +300,14 @@ class BuildController extends Controller
*/
protected function formatBuilds($builds)
{
Project::$sleepable = ['id', 'title', 'reference', 'type'];
$rtn = ['count' => $builds['count'], 'items' => []];
/** @var Build $build */
foreach ($builds['items'] as $build) {
$item = $build->toArray(1);
$header = new View('Build/header-row');
$header = new View('Build/header-row');
$header->build = $build;
$item['header_row'] = $header->render();
$rtn['items'][$item['id']] = $item;
$rtn['items'][$build->getId()]['header_row'] = $header->render();
}
ksort($rtn['items']);

View file

@ -0,0 +1,18 @@
<?php
use Phinx\Migration\AbstractMigration;
class RenamedBuildTypes extends AbstractMigration
{
public function up()
{
$this->execute("UPDATE project SET type = 'git' WHERE type = 'remote'");
$this->execute("UPDATE project SET type = 'bitbucket-hg' WHERE type = 'bitbuckethg'");
}
public function down()
{
$this->execute("UPDATE project SET type = 'remote' WHERE type = 'git'");
$this->execute("UPDATE project SET type = 'bitbuckethg' WHERE type = 'bitbucket-hg'");
}
}

View file

@ -34,21 +34,11 @@ class Build extends Model
const SOURCE_WEBHOOK = 4;
const SOURCE_WEBHOOK_PULL_REQUEST = 5;
/**
* @var array
*/
public static $sleepable = [];
/**
* @var string
*/
protected $tableName = 'build';
/**
* @var string
*/
protected $modelName = 'Build';
/**
* @var integer
*/

View file

@ -15,7 +15,7 @@ use PHPCensor\Model\BuildError;
*
* @author Dan Cryer <dan@block8.co.uk>
*/
class BitbucketBuild extends RemoteGitBuild
class BitbucketBuild extends GitBuild
{
/**
* Get link to commit from another source (i.e. BitBucket)

View file

@ -9,7 +9,7 @@ use PHPCensor\Model\Build;
*
* @author Artem Bochkov <artem.v.bochkov@gmail.com>
*/
class BitbucketHgBuild extends MercurialBuild
class BitbucketHgBuild extends HgBuild
{
/**
* Get link to commit from another source (i.e. BitBucket)

View file

@ -11,7 +11,7 @@ use Psr\Log\LogLevel;
*
* @author Dan Cryer <dan@block8.co.uk>
*/
class RemoteGitBuild extends Build
class GitBuild extends Build
{
/**
* Get the URL to be used to clone this remote repository.

View file

@ -15,7 +15,7 @@ use PHPCensor\Model\BuildError;
*
* @author Dan Cryer <dan@block8.co.uk>
*/
class GithubBuild extends RemoteGitBuild
class GithubBuild extends GitBuild
{
/**
* Get link to commit from another source (i.e. Github)

View file

@ -4,10 +4,10 @@ namespace PHPCensor\Model\Build;
/**
* Gitlab Build Model
*
*
* @author André Cianfarani <a.cianfarani@c2is.fr>
*/
class GitlabBuild extends RemoteGitBuild
class GitlabBuild extends GitBuild
{
/**

View file

@ -5,7 +5,7 @@ namespace PHPCensor\Model\Build;
/**
* GogsBuild Build Model
*/
class GogsBuild extends RemoteGitBuild
class GogsBuild extends GitBuild
{
/**
* Get link to commit from Gogs repository

View file

@ -10,7 +10,7 @@ use PHPCensor\Builder;
*
* @author Pavel Gopanenko <pavelgopanenko@gmail.com>
*/
class MercurialBuild extends Build
class HgBuild extends Build
{
/**
* Get the URL to be used to clone this remote repository.

View file

@ -7,10 +7,10 @@ use PHPCensor\Builder;
/**
* Remote Subversion Build Model
*
*
* @author Nadir Dzhilkibaev <imam.sharif@gmail.com>
*/
class SubversionBuild extends Build
class SvnBuild extends Build
{
protected $svnCommand = 'svn export -q --non-interactive ';
@ -21,7 +21,7 @@ class SubversionBuild extends Build
{
$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') {
$url .= 'trunk';

View file

@ -12,21 +12,11 @@ class BuildError extends Model
const SEVERITY_NORMAL = 2;
const SEVERITY_LOW = 3;
/**
* @var array
*/
public static $sleepable = [];
/**
* @var string
*/
protected $tableName = 'build_error';
/**
* @var string
*/
protected $modelName = 'BuildError';
/**
* @var array
*/

View file

@ -7,21 +7,11 @@ use b8\Store\Factory;
class BuildMeta extends Model
{
/**
* @var array
*/
public static $sleepable = [];
/**
* @var string
*/
protected $tableName = 'build_meta';
/**
* @var string
*/
protected $modelName = 'BuildMeta';
/**
* @var array
*/

View file

@ -6,21 +6,11 @@ use PHPCensor\Model;
class Environment extends Model
{
/**
* @var array
*/
public static $sleepable = [];
/**
* @var string
*/
protected $tableName = 'environment';
/**
* @var string
*/
protected $modelName = 'Environment';
/**
* @var array
*/

View file

@ -14,21 +14,11 @@ use Symfony\Component\Yaml\Dumper as YamlDumper;
*/
class Project extends Model
{
/**
* @var array
*/
public static $sleepable = [];
/**
* @var string
*/
protected $tableName = 'project';
/**
* @var string
*/
protected $modelName = 'Project';
/**
* @var array
*/

View file

@ -7,21 +7,11 @@ use b8\Store\Factory;
class ProjectGroup extends Model
{
/**
* @var array
*/
public static $sleepable = [];
/**
* @var string
*/
protected $tableName = 'project_group';
/**
* @var string
*/
protected $modelName = 'ProjectGroup';
/**
* @var array
*/

View file

@ -10,21 +10,11 @@ use PHPCensor\Model;
*/
class User extends Model
{
/**
* @var array
*/
public static $sleepable = [];
/**
* @var string
*/
protected $tableName = 'user';
/**
* @var string
*/
protected $modelName = 'User';
/**
* @var array
*/

View file

@ -12,17 +12,17 @@ class EnvironmentStore extends Store
/**
* @var string
*/
protected $tableName = 'environment';
protected $tableName = 'environment';
/**
* @var string
*/
protected $modelName = '\PHPCensor\Model\Environment';
protected $modelName = '\PHPCensor\Model\Environment';
/**
* @var string
*/
protected $primaryKey = 'id';
protected $primaryKey = 'id';
/**
* Get a Environment by primary key (Id)

View file

@ -87,6 +87,7 @@ use PHPCensor\Model\Build;
</h3>
<div class="timeline-body">
<p>
<?php if (Build::SOURCE_WEBHOOK_PULL_REQUEST === $build->getSource()): ?>
<a href="<?= $build->getRemoteBranchLink(); ?>">
<i class="fa fa-code-fork"></i>
@ -115,11 +116,12 @@ use PHPCensor\Model\Build;
$build->getCommitterEmail() ? ('(' . $build->getCommitterEmail() . ')') : ''
);
if (!empty($build->getCommitMessage())) {
echo ' &mdash; ';
echo '</p><p>';
print $build->getCommitMessage();
}
}
?>
</p>
</div>
</div>
</li>

View file

@ -0,0 +1,231 @@
<?php
namespace Tests\b8;
use b8\Config;
use b8\Database;
class DatabaseMysqlTest extends \PHPUnit_Extensions_Database_TestCase
{
/**
* @var \PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection|null
*/
protected $connection = null;
/**
* @param string $name
* @param array $data
* @param string $dataName
*/
public function __construct($name = null, array $data = [], $dataName = '')
{
parent::__construct($name, $data, $dataName);
if (extension_loaded('mysqli')) {
if (null === $this->connection) {
try {
$pdo = new \PDO(
'mysql:host=localhost;dbname=' . MYSQL_DBNAME,
MYSQL_USER,
MYSQL_PASSWORD
);
$this->connection = $this->createDefaultDBConnection($pdo, MYSQL_DBNAME);
$this->connection->getConnection()->query('
CREATE TABLE IF NOT EXISTS `database_mysql_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`projectId` int(11) NOT NULL,
`branch` varchar(250) NOT NULL DEFAULT \'master\',
`createDate` datetime,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
');
} catch (\PDOException $ex) {
$this->connection = null;
}
}
} else {
$this->connection = null;
}
}
/**
* @return \PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
protected function getConnection()
{
if (null === $this->connection) {
$this->markTestSkipped('Test skipped because MySQL database/user/extension doesn`t exist.');
}
return $this->connection;
}
/**
* @return \PHPUnit_Extensions_Database_DataSet_IDataSet
*/
protected function getDataSet()
{
return $this->createArrayDataSet([
'database_mysql_test' => [[
'id' => 1,
'projectId' => 1,
'branch' => 'master',
'createDate' => null,
], [
'id' => 2,
'projectId' => 2,
'branch' => 'dev',
'createDate' => '2018-02-20 01:01:01',
], [
'id' => 3,
'projectId' => 2,
'branch' => 'master',
'createDate' => '2018-02-21 02:02:02',
]],
]);
}
protected function setUp()
{
parent::setUp();
new Config([
'b8' => [
'database' => [
'servers' => [
'read' => [
['host' => 'localhost'],
],
'write' => [
['host' => 'localhost'],
],
],
'type' => Database::MYSQL_TYPE,
'name' => MYSQL_DBNAME,
'username' => MYSQL_USER,
'password' => MYSQL_PASSWORD,
],
],
]);
Database::reset();
}
public function testGetConnection()
{
$writeConnection = Database::getConnection('write');
$readConnection = Database::getConnection('read');
self::assertInstanceOf('\b8\Database', $writeConnection);
self::assertInstanceOf('\b8\Database', $readConnection);
$writeDetails = $writeConnection->getDetails();
self::assertTrue(is_array($writeDetails));
self::assertEquals(MYSQL_DBNAME, $writeDetails['db']);
self::assertEquals(MYSQL_USER, $writeDetails['user']);
self::assertEquals(MYSQL_PASSWORD, $writeDetails['pass']);
$readDetails = $readConnection->getDetails();
self::assertTrue(is_array($readDetails));
self::assertEquals(MYSQL_DBNAME, $readDetails['db']);
self::assertEquals(MYSQL_USER, $readDetails['user']);
self::assertEquals(MYSQL_PASSWORD, $readDetails['pass']);
self::assertEquals('mysql:host=localhost;dbname=b8_test', $readConnection->getDsn());
}
public function testGetWriteConnectionWithPort()
{
new Config([
'b8' => [
'database' => [
'servers' => [
'read' => [
[
'host' => 'localhost',
'port' => 3306,
],
],
'write' => [
[
'host' => 'localhost',
'port' => 3306,
],
],
],
'type' => Database::MYSQL_TYPE,
'name' => MYSQL_DBNAME,
'username' => MYSQL_USER,
'password' => MYSQL_PASSWORD,
],
],
]);
Database::reset();
$writeConnection = Database::getConnection('write');
$readConnection = Database::getConnection('read');
self::assertInstanceOf('\b8\Database', $writeConnection);
self::assertInstanceOf('\b8\Database', $readConnection);
self::assertEquals('mysql:host=localhost;port=3306;dbname=b8_test', $readConnection->getDsn());
}
/**
* @expectedException \Exception
*/
public function testConnectionFailure()
{
new Config([
'b8' => [
'database' => [
'servers' => [
'read' => [
['host' => 'localhost'],
],
'write' => [
['host' => 'localhost'],
],
],
'type' => Database::MYSQL_TYPE,
'name' => 'b8_test_2',
'username' => '',
'password' => '',
],
],
]);
Database::reset();
Database::getConnection('read');
}
public function testPrepareCommon()
{
$readConnection = Database::getConnection('read');
$sql = 'SELECT * FROM {{database_mysql_test}} WHERE {{projectId}} = :projectId';
$query = $readConnection->prepareCommon($sql);
$query->bindValue(':projectId', 2);
$query->execute();
$data = $query->fetchAll(\PDO::FETCH_ASSOC);
self::assertEquals(2, count($data));
}
public function testLastInsertIdExtended()
{
$writeConnection = Database::getConnection('write');
$sql = 'INSERT INTO {{database_mysql_test}} ({{projectId}}) VALUES (3)';
$query = $writeConnection->prepareCommon($sql);
$query->execute();
self::assertEquals(4, $writeConnection->lastInsertIdExtended());
}
}

View file

@ -0,0 +1,235 @@
<?php
namespace Tests\b8;
use b8\Config;
use b8\Database;
class DatabasePostgresqlTest extends \PHPUnit_Extensions_Database_TestCase
{
/**
* @var \PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection|null
*/
protected $connection = null;
/**
* @param string $name
* @param array $data
* @param string $dataName
*/
public function __construct($name = null, array $data = [], $dataName = '')
{
parent::__construct($name, $data, $dataName);
if (extension_loaded('pgsql')) {
if (null === $this->connection) {
try {
$pdo = new \PDO(
'pgsql:host=localhost;dbname=' . POSTGRESQL_DBNAME,
POSTGRESQL_USER,
POSTGRESQL_PASSWORD
);
$this->connection = $this->createDefaultDBConnection($pdo, POSTGRESQL_DBNAME);
$this->connection->getConnection()->query('
CREATE TABLE IF NOT EXISTS "database_mysql_test" (
"id" SERIAL,
"projectId" integer NOT NULL,
"branch" character varying(250) NOT NULL DEFAULT \'master\',
"createDate" timestamp without time zone,
PRIMARY KEY ("id")
);
');
} catch (\PDOException $ex) {
$this->connection = null;
}
}
} else {
$this->connection = null;
}
}
/**
* @return \PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
protected function getConnection()
{
if (null === $this->connection) {
$this->markTestSkipped('Test skipped because PostgreSQL database/user/extension doesn`t exist.');
}
return $this->connection;
}
/**
* @return \PHPUnit_Extensions_Database_DataSet_IDataSet
*/
protected function getDataSet()
{
return $this->createArrayDataSet([
'database_mysql_test' => [[
'id' => 1,
'projectId' => 1,
'branch' => 'master',
'createDate' => null,
], [
'id' => 2,
'projectId' => 2,
'branch' => 'dev',
'createDate' => '2018-02-20 01:01:01',
], [
'id' => 3,
'projectId' => 2,
'branch' => 'master',
'createDate' => '2018-02-21 02:02:02',
]],
]);
}
protected function setUp()
{
parent::setUp();
new Config([
'b8' => [
'database' => [
'servers' => [
'read' => [
['host' => 'localhost'],
],
'write' => [
['host' => 'localhost'],
],
],
'type' => Database::POSTGRESQL_TYPE,
'name' => POSTGRESQL_DBNAME,
'username' => POSTGRESQL_USER,
'password' => POSTGRESQL_PASSWORD,
],
],
]);
Database::reset();
}
public function testGetConnection()
{
$writeConnection = Database::getConnection('write');
$readConnection = Database::getConnection('read');
self::assertInstanceOf('\b8\Database', $writeConnection);
self::assertInstanceOf('\b8\Database', $readConnection);
$writeDetails = $writeConnection->getDetails();
self::assertTrue(is_array($writeDetails));
self::assertEquals(POSTGRESQL_DBNAME, $writeDetails['db']);
self::assertEquals(POSTGRESQL_USER, $writeDetails['user']);
self::assertEquals(POSTGRESQL_PASSWORD, $writeDetails['pass']);
$readDetails = $readConnection->getDetails();
self::assertTrue(is_array($readDetails));
self::assertEquals(POSTGRESQL_DBNAME, $readDetails['db']);
self::assertEquals(POSTGRESQL_USER, $readDetails['user']);
self::assertEquals(POSTGRESQL_PASSWORD, $readDetails['pass']);
self::assertEquals('pgsql:host=localhost;dbname=b8_test', $readConnection->getDsn());
}
public function testGetWriteConnectionWithPort()
{
new Config([
'b8' => [
'database' => [
'servers' => [
'read' => [
[
'host' => 'localhost',
'port' => 5432,
],
],
'write' => [
[
'host' => 'localhost',
'port' => 5432,
],
],
],
'type' => Database::POSTGRESQL_TYPE,
'name' => POSTGRESQL_DBNAME,
'username' => POSTGRESQL_USER,
'password' => POSTGRESQL_PASSWORD,
],
],
]);
Database::reset();
$writeConnection = Database::getConnection('write');
$readConnection = Database::getConnection('read');
self::assertInstanceOf('\b8\Database', $writeConnection);
self::assertInstanceOf('\b8\Database', $readConnection);
self::assertEquals('pgsql:host=localhost;port=5432;dbname=b8_test', $readConnection->getDsn());
}
/**
* @expectedException \Exception
*/
public function testConnectionFailure()
{
new Config([
'b8' => [
'database' => [
'servers' => [
'read' => [
['host' => 'localhost'],
],
'write' => [
['host' => 'localhost'],
],
],
'type' => Database::POSTGRESQL_TYPE,
'name' => 'b8_test_2',
'username' => '',
'password' => '',
],
],
]);
Database::reset();
Database::getConnection('read');
}
public function testPrepareCommon()
{
$readConnection = Database::getConnection('read');
$sql = 'SELECT * FROM {{database_mysql_test}} WHERE {{projectId}} = :projectId';
$query = $readConnection->prepareCommon($sql);
$query->bindValue(':projectId', 2);
$query->execute();
$data = $query->fetchAll(\PDO::FETCH_ASSOC);
self::assertEquals(2, count($data));
}
public function testLastInsertIdExtended()
{
$this->connection->getConnection()->query('
ALTER SEQUENCE "database_mysql_test_id_seq" RESTART WITH 4;
');
$writeConnection = Database::getConnection('write');
$sql = 'INSERT INTO {{database_mysql_test}} ({{projectId}}) VALUES (3)';
$query = $writeConnection->prepareCommon($sql);
$query->execute();
self::assertEquals(4, $writeConnection->lastInsertIdExtended('database_mysql_test'));
}
}

View file

@ -1,94 +0,0 @@
<?php
namespace Tests\b8;
use b8\Config;
use b8\Database;
class DatabaseTest extends \PHPUnit\Framework\TestCase
{
protected function setUp()
{
$config = new Config([
'b8' => [
'database' => [
'servers' => [
'read' => [
['host' => 'localhost'],
],
'write' => [
['host' => 'localhost'],
],
],
'type' => DB_TYPE,
'name' => DB_NAME,
'username' => DB_USER,
'password' => DB_PASS,
],
],
]);
}
protected function checkDatabaseConnection()
{
try {
$connection = Database::getConnection('read');
} catch (\Exception $e) {
if ('Could not connect to any read servers.' === $e->getMessage()) {
$this->markTestSkipped('Test skipped because test database doesn`t exist.');
} else {
throw $e;
}
}
}
public function testGetWriteConnection()
{
$this->checkDatabaseConnection();
$connection = Database::getConnection('write');
self::assertInstanceOf('\b8\Database', $connection);
}
public function testGetDetails()
{
$this->checkDatabaseConnection();
$details = Database::getConnection('read')->getDetails();
self::assertTrue(is_array($details));
self::assertTrue(($details['db'] == DB_NAME));
self::assertTrue(($details['user'] == DB_USER));
self::assertTrue(($details['pass'] == DB_PASS));
}
/**
* @expectedException \Exception
*/
public function testConnectionFailure()
{
$this->checkDatabaseConnection();
Database::reset();
$config = new Config([
'b8' => [
'database' => [
'servers' => [
'read' => [
['host' => 'localhost'],
],
'write' => [
['host' => 'localhost'],
],
],
'type' => DB_TYPE,
'name' => 'b8_test_2',
'username' => '',
'password' => '',
],
],
]);
Database::getConnection('read');
}
}

View file

@ -83,7 +83,7 @@ class PhpUnitResultTest extends \PHPUnit\Framework\TestCase
public static function getTestData()
{
return [
'json' => [PhpUnitResultJson::class, 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money.txt'],
'json' => [PhpUnitResultJson::class, 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money.txt'],
'junit' => [PhpUnitResultJunit::class, 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money_junit.xml'],
];
}

View file

@ -1,51 +1,42 @@
<?php
if (!defined('ROOT_DIR')) {
define('ROOT_DIR', dirname(__DIR__) . DIRECTORY_SEPARATOR);
define('ROOT_DIR', dirname(__DIR__) . '/');
}
if (!defined('SRC_DIR')) {
define('SRC_DIR', ROOT_DIR . 'src' . DIRECTORY_SEPARATOR . 'PHPCensor' . DIRECTORY_SEPARATOR);
define('SRC_DIR', ROOT_DIR . 'src/PHPCensor/');
}
if (!defined('PUBLIC_DIR')) {
define('PUBLIC_DIR', ROOT_DIR . 'public' . DIRECTORY_SEPARATOR);
define('PUBLIC_DIR', ROOT_DIR . 'public/');
}
if (!defined('APP_DIR')) {
define('APP_DIR', ROOT_DIR . 'app' . DIRECTORY_SEPARATOR);
define('APP_DIR', ROOT_DIR . 'app/');
}
if (!defined('BIN_DIR')) {
define('BIN_DIR', ROOT_DIR . 'bin' . DIRECTORY_SEPARATOR);
define('BIN_DIR', ROOT_DIR . 'bin/');
}
if (!defined('RUNTIME_DIR')) {
define('RUNTIME_DIR', ROOT_DIR . 'runtime' . DIRECTORY_SEPARATOR);
define('RUNTIME_DIR', ROOT_DIR . 'runtime/');
}
require_once(ROOT_DIR . 'vendor/autoload.php');
// Load configuration if present:
$conf = [];
$conf['b8']['app']['namespace'] = 'PHPCensor';
$conf['b8']['app']['default_controller'] = 'Home';
$conf['b8']['view']['path'] = SRC_DIR . 'View' . DIRECTORY_SEPARATOR;
$conf['b8']['view']['path'] = SRC_DIR . 'View/';
$conf['php-censor']['url'] = 'http://php-censor.local';
$config = new b8\Config($conf);
$configFile = APP_DIR . 'config.yml';
if (file_exists($configFile)) {
$config->loadYaml($configFile);
}
if (!defined('APP_URL') && !empty($config)) {
define('APP_URL', $config->get('php-censor.url', '') . '/');
}
\PHPCensor\Helper\Lang::init($config, 'en');
define('DB_NAME', getenv('DB_NAME'));
define('DB_USER', getenv('DB_USER'));
define('DB_TYPE', getenv('DB_TYPE'));
define('DB_PASS', getenv('DB_PASS'));
\PHPCensor\Helper\Lang::init($config);