diff --git a/app.php b/app.php
new file mode 100644
index 000000000..4434da1f5
--- /dev/null
+++ b/app.php
@@ -0,0 +1,24 @@
+view;
+/** @var \TorrentPier\Db\Adapter $db */
+$db = $di->db;
+
+
+$view->addGlobal('title', 'Title Page Simple');
+
+
+$categories = $db->select('bb_categories', function (\Zend\Db\Sql\Select $query) {
+ $query->join('bb_forums', 'bb_categories.cat_id = bb_forums.cat_id');
+})->all();
+
+
+
+
+echo $view->make('app', [
+ 'data' => 'Hello world',
+ 'categories' => $categories
+]);
diff --git a/bootstrap.php b/bootstrap.php
new file mode 100644
index 000000000..3c4ca85c8
--- /dev/null
+++ b/bootstrap.php
@@ -0,0 +1,30 @@
+register(new ServiceProviders\ConfigServiceProvider, [
+ 'file.system.main' => __DIR__ . '/configs/main.php',
+ 'file.local.main' => __DIR__ . '/configs/local.php',
+]);
+
+//// Application
+$di->register(new ServiceProviders\LogServiceProvider());
+$di->register(new ServiceProviders\CacheServiceProvider());
+$di->register(new ServiceProviders\DbServiceProvider());
+$di->register(new ServiceProviders\SettingsServiceProvider());
+$di->register(new ServiceProviders\VisitorServiceProvider());
+$di->register(new ServiceProviders\RequestServiceProvider());
+
+// Services
+//$di->register(new \TorrentPier\ServiceProviders\SphinxServiceProvider());
+
+// View and Templates
+$di->register(new ServiceProviders\TranslationServiceProvider());
+$di->register(new ServiceProviders\CaptchaServiceProvider());
+$di->register(new ServiceProviders\TwigServiceProvider());
+$di->register(new ServiceProviders\ViewServiceProvider());
diff --git a/common.php b/common.php
index 31bc3aa19..26919184a 100644
--- a/common.php
+++ b/common.php
@@ -38,44 +38,19 @@ $di['settings.locale'] = function($di) {
};
$di->register(new \TorrentPier\ServiceProviders\ConfigServiceProvider, [
- 'config.file.system.main' => __DIR__ . '/library/config.php',
- 'config.file.local.main' => __DIR__ . '/library/config.local.php',
-]);
-
-$di->register(new \TorrentPier\ServiceProviders\LogServiceProvider(), [
- 'config.log.handlers' => $di->config->log->handlers
-]);
-
-$di->register(new \TorrentPier\ServiceProviders\CacheServiceProvider(), [
- 'config.services.cache' => $di->config->services->cache->toArray()
-]);
-
-$di->register(new \TorrentPier\ServiceProviders\DbServiceProvider, [
- 'config.db' => $di->config->db->toArray()
-]);
-
-$di->register(new \TorrentPier\ServiceProviders\SphinxServiceProvider, [
- 'config.sphinx' => $di->config->sphinx->toArray()
+ 'file.system.main' => __DIR__ . '/library/config.php',
+ 'file.local.main' => __DIR__ . '/library/config.local.php',
]);
+$di->register(new \TorrentPier\ServiceProviders\LogServiceProvider());
+$di->register(new \TorrentPier\ServiceProviders\CacheServiceProvider());
+$di->register(new \TorrentPier\ServiceProviders\DbServiceProvider());
+$di->register(new \TorrentPier\ServiceProviders\SphinxServiceProvider());
$di->register(new \TorrentPier\ServiceProviders\RequestServiceProvider());
$di->register(new \TorrentPier\ServiceProviders\ViewServiceProvider());
-
-$di->register(new \TorrentPier\ServiceProviders\TranslationServiceProvider(), [
- 'config.debug' => $di->config->debug,
- 'config.translator.dir_cache' => $di->config->translator->dir_cache,
- 'config.translator.resources' => $di->config->translator->resources->toArray()
-]);
-
-$di->register(new \TorrentPier\ServiceProviders\TwigServiceProvider, [
- 'config.debug' => $di->config->debug,
- 'config.twig.dir_templates' => $di->config->twig->dir_templates,
- 'config.twig.dir_cache' => $di->config->twig->dir_cache
-]);
-
-$di->register(new \TorrentPier\ServiceProviders\CaptchaServiceProvider, [
- 'config.captcha.secret_key' => $di->config->captcha->secret_key
-]);
+$di->register(new \TorrentPier\ServiceProviders\TranslationServiceProvider());
+$di->register(new \TorrentPier\ServiceProviders\TwigServiceProvider());
+$di->register(new \TorrentPier\ServiceProviders\CaptchaServiceProvider());
$bb_cfg = $di->config->toArray();
$page_cfg = $di->config->page->toArray();
@@ -132,11 +107,11 @@ require(CORE_DIR . 'dbs.php');
$DBS = new DBS([
'db' => [
'db' => [
- $di->config->db->hostname,
- $di->config->db->database,
- $di->config->db->username,
- $di->config->db->password,
- $di->config->db->charset,
+ $di->config->services->db->hostname,
+ $di->config->services->db->database,
+ $di->config->services->db->username,
+ $di->config->services->db->password,
+ $di->config->services->db->charset,
false
]
],
diff --git a/composer.json b/composer.json
index 365123ff0..8738048ca 100644
--- a/composer.json
+++ b/composer.json
@@ -46,7 +46,9 @@
"doctrine/cache": "^1.6"
},
"require-dev": {
- "phpunit/phpunit": "^4.8"
+ "phpunit/phpunit": "4.8.*",
+ "squizlabs/php_codesniffer": "2.5.*",
+ "sebastian/phpcpd": "2.0.*"
},
"autoload": {
"psr-4": {
@@ -54,5 +56,24 @@
}
},
"minimum-stability": "stable",
- "prefer-stable": true
+ "prefer-stable": true,
+ "scripts": {
+ "test": [
+ "composer test:lint",
+ "composer test:unit",
+ "composer test:cpd"
+ ],
+ "test:lint": [
+ "vendor/bin/phpcs --colors --report-full --standard=PSR2 src tests"
+ ],
+ "test:unit": [
+ "vendor/bin/phpunit --configuration phpunit.xml --coverage-text"
+ ],
+ "test:unit:html": [
+ "vendor/bin/phpunit --configuration phpunit.xml --coverage-html=internal_data/report"
+ ],
+ "test:cpd": [
+ "vendor/bin/phpcpd --exclude=vendor --exclude=internal_data ."
+ ]
+ }
}
diff --git a/configs/main.php b/configs/main.php
new file mode 100644
index 000000000..b656b9554
--- /dev/null
+++ b/configs/main.php
@@ -0,0 +1,79 @@
+ false,
+
+ 'services' => [
+ // Database
+ 'db' => [
+ 'debug' => '{self.debug}',
+ 'driver' => 'Pdo_Mysql',
+ 'hostname' => '127.0.0.1',
+ 'database' => 'tp_220',
+ 'username' => 'user',
+ 'password' => 'pass',
+ 'charset' => 'utf8'
+ ],
+
+ // Cache
+ 'cache' => [
+ 'adapter' => \TorrentPier\Cache\FileAdapter::class,
+ 'options' => [
+ 'directory' => __DIR__ . '/../internal_data/cache',
+ ],
+ ],
+
+ // Translation
+ 'translator' => [
+ 'dir_cache' => __DIR__ . '/../internal_data/cache',
+ 'resources' => [
+ [
+ 'resource' => __DIR__ . '/../messages/ru.php',
+ 'locale' => 'ru',
+ ],
+ [
+ 'resource' => __DIR__ . '/../messages/en.php',
+ 'locale' => 'en',
+ ]
+ ]
+ ],
+
+ // Twig
+ 'twig' => [
+ 'dir_templates' => __DIR__ . '/../templates/default',
+ 'dir_cache' => __DIR__ . '/../internal_data/cache',
+ ],
+
+ // Sphinx
+ 'sphinx' => [
+ 'debug' => '{self.debug}',
+ 'driver' => '{self.db.driver}',
+ 'hostname' => '{self.db.hostname}',
+ 'username' => 'user',
+ 'password' => 'pass',
+ 'port' => 9306,
+ 'charset' => 'utf8'
+ ],
+
+ // Logger
+ 'log' => [
+ 'handlers' => [
+ function () {
+ return new \Monolog\Handler\StreamHandler(
+ __DIR__.'/../internal_data/log/app.log',
+ \Monolog\Logger::DEBUG
+ );
+ }
+ ]
+ ],
+
+ // Captcha
+ // Get a Google reCAPTCHA API Key: https://www.google.com/recaptcha/admin
+ 'captcha' => [
+ 'disabled' => false,
+ 'public_key' => '', // your public key
+ 'secret_key' => '', // your secret key
+ 'theme' => 'light', // light or dark
+ ],
+ ]
+];
diff --git a/library/config.php b/library/config.php
index 665abe5b5..c2901a69f 100644
--- a/library/config.php
+++ b/library/config.php
@@ -24,6 +24,7 @@ $config = [
'adapter' => \TorrentPier\Cache\FileAdapter::class,
'options' => [
'directory' => __DIR__ . '/../internal_data/cache',
+ 'prefix' => 'hash string'
],
],
/*'cache' => [
@@ -36,62 +37,62 @@ $config = [
],
],
],*/
- ],
- // Database
- 'db' => [
- 'debug' => '{self.debug}',
- 'driver' => 'Pdo_Mysql',
- 'hostname' => '127.0.0.1',
- 'database' => 'tp_220',
- 'username' => 'user',
- 'password' => 'pass',
- 'charset' => 'utf8'
- ],
+ // Database
+ 'db' => [
+ 'debug' => '{self.debug}',
+ 'driver' => 'Pdo_Mysql',
+ 'hostname' => '127.0.0.1',
+ 'database' => 'tp_220',
+ 'username' => 'user',
+ 'password' => 'pass',
+ 'charset' => 'utf8'
+ ],
- // Sphinx
- 'sphinx' => [
- 'debug' => '{self.debug}',
- 'driver' => '{self.db.driver}',
- 'hostname' => '{self.db.hostname}',
- 'username' => 'user',
- 'password' => 'pass',
- 'port' => 9306,
- 'charset' => 'utf8'
- ],
+ // Sphinx
+ 'sphinx' => [
+ 'debug' => '{self.debug}',
+ 'driver' => '{self.db.driver}',
+ 'hostname' => '{self.db.hostname}',
+ 'username' => 'user',
+ 'password' => 'pass',
+ 'port' => 9306,
+ 'charset' => 'utf8'
+ ],
- // Twig
- 'twig' => [
- 'dir_templates' => __DIR__ . '/../templates/default',
- 'dir_cache' => __DIR__ . '/../internal_data/cache',
- ],
+ // Twig
+ 'twig' => [
+ 'dir_templates' => __DIR__ . '/../templates/default',
+ 'dir_cache' => __DIR__ . '/../internal_data/cache',
+ ],
- // Translation
- 'translator' => [
- 'dir_cache' => __DIR__ . '/../internal_data/cache',
- 'resources' => [
- [
- 'resource' => __DIR__ . '/../messages/ru.php',
- 'locale' => 'ru',
- ],
- [
- 'resource' => __DIR__ . '/../messages/en.php',
- 'locale' => 'en',
+ // Translation
+ 'translator' => [
+ 'dir_cache' => __DIR__ . '/../internal_data/cache',
+ 'resources' => [
+ [
+ 'resource' => __DIR__ . '/../messages/ru.php',
+ 'locale' => 'ru',
+ ],
+ [
+ 'resource' => __DIR__ . '/../messages/en.php',
+ 'locale' => 'en',
+ ]
]
- ]
- ],
+ ],
- // Log
- 'log' => [
- 'handlers' => [
- function () {
- return new \Monolog\Handler\StreamHandler(
- __DIR__.'/../internal_data/log/app.log',
- \Monolog\Logger::DEBUG
- );
- }
- ]
- ],
+ // Log
+ 'log' => [
+ 'handlers' => [
+ function () {
+ return new \Monolog\Handler\StreamHandler(
+ __DIR__.'/../internal_data/log/app.log',
+ \Monolog\Logger::DEBUG
+ );
+ }
+ ]
+ ],
+ ],
// Aliases
// TODO: удалить
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 000000000..835767d8e
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,16 @@
+
+
+
+ Codestyle ruleset for TorrentPier
+
+
+
+ src
+
+
+
+
+ tests/*
+ vendor/*
+
+
diff --git a/src/Cache/Adapter.php b/src/Cache/Adapter.php
index f9aa78b9c..850e70838 100644
--- a/src/Cache/Adapter.php
+++ b/src/Cache/Adapter.php
@@ -17,6 +17,11 @@ abstract class Adapter
*/
protected $provider;
+ /**
+ * @var string
+ */
+ protected $prefix = '';
+
/**
* Set options for setting cache provider.
*
@@ -48,6 +53,18 @@ abstract class Adapter
*/
abstract protected function getType();
+ /**
+ * Add prefix to the namespace for security of key.
+ *
+ * @param string $prefix
+ * @return $this
+ */
+ protected function setPrefix($prefix)
+ {
+ $this->prefix = $prefix;
+ return $this;
+ }
+
/**
* Prepare key.
*
@@ -68,7 +85,7 @@ abstract class Adapter
list($namespace, $id) = $result;
}
- $this->getProvider()->setNamespace($namespace);
+ $this->getProvider()->setNamespace($this->prefix . $namespace);
return $id;
}
@@ -89,7 +106,7 @@ abstract class Adapter
* Fetches an entry from the cache.
*
* @param string $key
- * @param mixed|null $defaultValue
+ * @param mixed|\Closure|null $defaultValue
* @return mixed|null
*/
public function get($key, $defaultValue = null)
@@ -98,6 +115,10 @@ abstract class Adapter
$result = $this->getProvider()->fetch($id);
if ($result === false) {
+ if ($defaultValue instanceof \Closure) {
+ return call_user_func($defaultValue, $this, $key);
+ }
+
return $defaultValue;
}
@@ -108,12 +129,13 @@ abstract class Adapter
* Returns an associative array of values for keys is found in cache.
*
* @param array $keys
+ * @param string $namespace
* @return array|\string[]
*/
- public function gets(array $keys)
+ public function gets(array $keys, $namespace = self::DEFAULT_NAMESPACE)
{
- $keys = array_map([$this, 'prepareKey'], $keys);
- return $this->getProvider()->fetchMultiple([$keys]);
+ $this->getProvider()->setNamespace($this->prefix . $namespace);
+ return $this->getProvider()->fetchMultiple($keys);
}
/**
@@ -134,16 +156,13 @@ abstract class Adapter
* Returns a boolean value indicating if the operation succeeded.
*
* @param array $keysAndValues
+ * @param string $namespace
* @param int $timeLeft
* @return bool
*/
- public function sets(array $keysAndValues, $timeLeft)
+ public function sets(array $keysAndValues, $namespace = self::DEFAULT_NAMESPACE, $timeLeft = 0)
{
- foreach ($keysAndValues as $key => $value) {
- $id = $this->prepareKey($key);
- $keysAndValues[$id] = $value;
- unset($keysAndValues[$key]);
- }
+ $this->getProvider()->setNamespace($this->prefix . $namespace);
return $this->getProvider()->saveMultiple($keysAndValues, $timeLeft);
}
@@ -167,7 +186,7 @@ abstract class Adapter
*/
public function deleteAll($namespace = '')
{
- $this->getProvider()->setNamespace($namespace);
+ $this->getProvider()->setNamespace($this->prefix . $namespace);
return $this->getProvider()->deleteAll();
}
diff --git a/src/Cache/FileAdapter.php b/src/Cache/FileAdapter.php
index ecdf352c1..43e7cdefa 100644
--- a/src/Cache/FileAdapter.php
+++ b/src/Cache/FileAdapter.php
@@ -2,7 +2,7 @@
namespace TorrentPier\Cache;
-use Doctrine\Common\Cache\PhpFileCache;
+use Doctrine\Common\Cache\FilesystemCache;
/**
* Class FileAdapter
@@ -18,7 +18,7 @@ class FileAdapter extends Adapter
/**
* @var string The cache file extension.
*/
- protected $extension = PhpFileCache::EXTENSION;
+ protected $extension = FilesystemCache::EXTENSION;
/**
* @var int The cache file umask.
@@ -31,7 +31,7 @@ class FileAdapter extends Adapter
public function getProvider()
{
if (!$this->provider) {
- $this->provider = new PhpFileCache($this->directory, $this->extension, $this->umask);
+ $this->provider = new FilesystemCache($this->directory, $this->extension, $this->umask);
}
return $this->provider;
@@ -42,7 +42,7 @@ class FileAdapter extends Adapter
*/
protected function getType()
{
- return 'Cache in php file';
+ return 'Filesystem Cache';
}
/**
diff --git a/src/Cache/MemoryAdapter.php b/src/Cache/MemoryAdapter.php
index c9ce5c4f5..f9fed2557 100644
--- a/src/Cache/MemoryAdapter.php
+++ b/src/Cache/MemoryAdapter.php
@@ -98,6 +98,6 @@ class MemoryAdapter extends Adapter
*/
protected function getType()
{
- return $this->isMemcached ? 'Cache in memcached' : 'Cache in memcache';
+ return sprintf('Memory Cache (Driver: %s)', $this->isMemcached ? 'memcached' : 'memcache');
}
}
diff --git a/src/Config.php b/src/Config.php
index 091a2a79f..696ccccf4 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -19,7 +19,7 @@ class Config extends ZendConfig
* @param bool $allowModifications
* @param Config|null $root
*/
- public function __construct(array $array, $allowModifications = false, Config $root = null)
+ public function __construct(array $array, $allowModifications = false, Config &$root = null)
{
$this->allowModifications = (bool) $allowModifications;
diff --git a/src/Db/Adapter.php b/src/Db/Adapter.php
index 88049de85..b9a9ecca8 100644
--- a/src/Db/Adapter.php
+++ b/src/Db/Adapter.php
@@ -31,8 +31,12 @@ class Adapter extends \Zend\Db\Adapter\Adapter
/**
* {@inheritdoc}
*/
- public function __construct($driver, PlatformInterface $platform = null, ResultSetInterface $queryResultPrototype = null, ProfilerInterface $profiler = null)
- {
+ public function __construct(
+ $driver,
+ PlatformInterface $platform = null,
+ ResultSetInterface $queryResultPrototype = null,
+ ProfilerInterface $profiler = null
+ ) {
if ($driver instanceof Config) {
$driver = $driver->toArray();
}
@@ -85,7 +89,6 @@ class Adapter extends \Zend\Db\Adapter\Adapter
$table = $this->prepareTable($table);
$sql = $this->getSql();
-
/** @var Insert $sqlInsert */
$sqlInsert = $sql->insert($table);
$sqlInsert->values($values);
diff --git a/src/Di.php b/src/Di.php
index 3522584b7..9d483ceae 100644
--- a/src/Di.php
+++ b/src/Di.php
@@ -10,14 +10,27 @@ use Pimple\Container;
*/
class Di extends Container
{
+ const DELIMITER = '.';
+
private static $instance;
+ /**
+ * Di constructor.
+ *
+ * @param array $values
+ */
public function __construct(array $values = [])
{
parent::__construct($values);
static::$instance = $this;
}
+ /**
+ * Get instance dependency injection container.
+ *
+ * @return self
+ * @throws \RuntimeException
+ */
public static function getInstance()
{
if (static::$instance instanceof Container) {
@@ -27,12 +40,28 @@ class Di extends Container
throw new \RuntimeException('The container has not been initialized');
}
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetGet($id)
+ {
+ try {
+ return parent::offsetGet($id);
+ } catch (\InvalidArgumentException $e) {
+ if (strpos($id, self::DELIMITER)) {
+ list($service, $key) = explode(self::DELIMITER, $id, 2);
+
+ if ($this->offsetExists($service)) {
+ return parent::offsetGet($service)->get($key);
+ }
+ }
+
+ throw new \InvalidArgumentException($e->getMessage(), $e->getCode(), $e->getPrevious());
+ }
+ }
+
public function __get($id)
{
- if ($this->offsetExists($id)) {
- return $this->offsetGet($id);
- }
-
- throw new \RuntimeException("Service '{$id}' is not registered in the container");
+ return $this->offsetGet($id);
}
}
diff --git a/src/ServiceProviders/CacheServiceProvider.php b/src/ServiceProviders/CacheServiceProvider.php
index 16d8723c5..f4d4ed64d 100644
--- a/src/ServiceProviders/CacheServiceProvider.php
+++ b/src/ServiceProviders/CacheServiceProvider.php
@@ -21,7 +21,7 @@ class CacheServiceProvider implements ServiceProviderInterface
$setting = $container['config.services.cache'];
/** @var Adapter $adapter */
$adapter = new $setting['adapter']();
- $adapter->setOptions($setting['options']);
+ $adapter->setOptions($setting['options']->toArray());
return $adapter;
};
}
diff --git a/src/ServiceProviders/CaptchaServiceProvider.php b/src/ServiceProviders/CaptchaServiceProvider.php
index 8a143e551..d951be015 100644
--- a/src/ServiceProviders/CaptchaServiceProvider.php
+++ b/src/ServiceProviders/CaptchaServiceProvider.php
@@ -18,7 +18,7 @@ class CaptchaServiceProvider implements ServiceProviderInterface
public function register(Container $container)
{
$container['captcha'] = function (Container $container) {
- $captcha = new ReCaptcha($container['config.captcha.secret_key']);
+ $captcha = new ReCaptcha($container['config.services.captcha.secret_key']);
return $captcha;
};
}
diff --git a/src/ServiceProviders/ConfigServiceProvider.php b/src/ServiceProviders/ConfigServiceProvider.php
index 6739530ab..7780adf62 100644
--- a/src/ServiceProviders/ConfigServiceProvider.php
+++ b/src/ServiceProviders/ConfigServiceProvider.php
@@ -7,6 +7,10 @@ use Pimple\ServiceProviderInterface;
use TorrentPier\Config;
use Zend\Config\Factory;
+/**
+ * Class ConfigServiceProvider
+ * @package TorrentPier\ServiceProviders
+ */
class ConfigServiceProvider implements ServiceProviderInterface
{
/**
@@ -15,10 +19,10 @@ class ConfigServiceProvider implements ServiceProviderInterface
public function register(Container $container)
{
$container['config'] = function ($container) {
- $config = new Config(Factory::fromFile($container['config.file.system.main']));
+ $config = new Config(Factory::fromFile($container['file.system.main']));
- if (isset($container['config.file.local.main']) && file_exists($container['config.file.local.main'])) {
- $config->merge(new Config(Factory::fromFile($container['config.file.local.main'])));
+ if (isset($container['file.local.main']) && file_exists($container['file.local.main'])) {
+ $config->merge(new Config(Factory::fromFile($container['file.local.main'])));
}
return $config;
diff --git a/src/ServiceProviders/DbServiceProvider.php b/src/ServiceProviders/DbServiceProvider.php
index 714c7a8f7..44593263f 100644
--- a/src/ServiceProviders/DbServiceProvider.php
+++ b/src/ServiceProviders/DbServiceProvider.php
@@ -7,6 +7,10 @@ use Pimple\ServiceProviderInterface;
use TorrentPier\Db\Adapter;
use TorrentPier\Db\Connection;
+/**
+ * Class DbServiceProvider
+ * @package TorrentPier\ServiceProviders
+ */
class DbServiceProvider implements ServiceProviderInterface
{
/**
@@ -15,8 +19,8 @@ class DbServiceProvider implements ServiceProviderInterface
public function register(Container $container)
{
$container['db'] = function ($container) {
- $adapter = new Adapter($container['config.db']);
- unset($container['config.db']);
+ $adapter = new Adapter($container['config.services.db']);
+ unset($container['config.services.db']);
return $adapter;
};
}
diff --git a/src/ServiceProviders/LogServiceProvider.php b/src/ServiceProviders/LogServiceProvider.php
index bbc894d1b..16551d2a5 100644
--- a/src/ServiceProviders/LogServiceProvider.php
+++ b/src/ServiceProviders/LogServiceProvider.php
@@ -26,7 +26,7 @@ class LogServiceProvider implements ServiceProviderInterface
$container['log'] = function ($container) {
/** @var Logger $logger */
$logger = $container['logger']('app');
- foreach ($container['config.log.handlers'] as $logHandler) {
+ foreach ($container['config.services.log.handlers'] as $logHandler) {
$logger->pushHandler(call_user_func($logHandler));
}
diff --git a/src/ServiceProviders/RequestServiceProvider.php b/src/ServiceProviders/RequestServiceProvider.php
index 7813bfce9..4aa598659 100644
--- a/src/ServiceProviders/RequestServiceProvider.php
+++ b/src/ServiceProviders/RequestServiceProvider.php
@@ -6,6 +6,10 @@ use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Symfony\Component\HttpFoundation\Request;
+/**
+ * Class RequestServiceProvider
+ * @package TorrentPier\ServiceProviders
+ */
class RequestServiceProvider implements ServiceProviderInterface
{
public function register(Container $container)
diff --git a/src/ServiceProviders/SettingsServiceProvider.php b/src/ServiceProviders/SettingsServiceProvider.php
new file mode 100644
index 000000000..d5e7cc4e8
--- /dev/null
+++ b/src/ServiceProviders/SettingsServiceProvider.php
@@ -0,0 +1,17 @@
+getDriver();
// Check driver
@@ -34,7 +38,7 @@ class SphinxServiceProvider implements ServiceProviderInterface
}
$platform->setDriver($adapter->getDriver());
- unset($container['config.sphinx']);
+ unset($container['config.services.sphinx']);
return $adapter;
};
diff --git a/src/ServiceProviders/TranslationServiceProvider.php b/src/ServiceProviders/TranslationServiceProvider.php
index a50cf7f35..7d7bbbaf1 100644
--- a/src/ServiceProviders/TranslationServiceProvider.php
+++ b/src/ServiceProviders/TranslationServiceProvider.php
@@ -7,21 +7,29 @@ use Pimple\ServiceProviderInterface;
use Symfony\Component\Translation\Loader\PhpFileLoader;
use Symfony\Component\Translation\Translator;
+/**
+ * Class TranslationServiceProvider
+ * @package TorrentPier\ServiceProviders
+ */
class TranslationServiceProvider implements ServiceProviderInterface
{
+ /**
+ * {@inheritdoc}
+ */
public function register(Container $container)
{
$container['translator'] = function (Container $container) {
$translator = new Translator(
- $container['settings.locale'],
+ $container['visitor.settings.base.locale'] ?: $container['settings.base.locale'],
null,
- null, // $container['config.translator.dir_cache'],
+ null, // $container['config.services.translator.dir_cache'],
$container['config.debug']
);
$translator->addLoader('php', new PhpFileLoader());
- foreach ($container['config.translator.resources'] as $item) {
+ $resources = $container['config.services.translator.resources']->toArray();
+ foreach ($resources as $item) {
$translator->addResource('php', $item['resource'], $item['locale']);
}
diff --git a/src/ServiceProviders/TwigServiceProvider.php b/src/ServiceProviders/TwigServiceProvider.php
index c36ff0cee..8a32cc1a4 100644
--- a/src/ServiceProviders/TwigServiceProvider.php
+++ b/src/ServiceProviders/TwigServiceProvider.php
@@ -5,24 +5,28 @@ namespace TorrentPier\ServiceProviders;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
+use TorrentPier\Twig\Loader\Filesystem;
+/**
+ * Class TwigServiceProvider
+ * @package TorrentPier\ServiceProviders
+ */
class TwigServiceProvider implements ServiceProviderInterface
{
+ /**
+ * {@inheritdoc}
+ */
public function register(Container $container)
{
$container['twig'] = function (Container $container) {
- $loader = new \Twig_Loader_Filesystem($container['config.twig.dir_templates']);
+ $loader = new Filesystem($container['config.services.twig.dir_templates']);
$twig = new \Twig_Environment($loader, [
'debug' => $container['config.debug'],
- 'cache' => $container['config.twig.dir_cache'],
+ 'cache' => $container['config.services.twig.dir_cache'],
]);
- $twig->addExtension(new \Twig_Extension_Core());
- $twig->addExtension(new \Twig_Extension_Escaper());
- $twig->addExtension(new \Twig_Extension_Optimizer());
- $twig->addExtension(new \Twig_Extension_Debug());
-
$twig->addExtension(new TranslationExtension($container['translator']));
+ $twig->addExtension(new \Twig_Extension_Debug());
return $twig;
};
diff --git a/src/ServiceProviders/ViewServiceProvider.php b/src/ServiceProviders/ViewServiceProvider.php
index d8ba1c3d7..435945bd6 100644
--- a/src/ServiceProviders/ViewServiceProvider.php
+++ b/src/ServiceProviders/ViewServiceProvider.php
@@ -6,6 +6,10 @@ use Pimple\Container;
use Pimple\ServiceProviderInterface;
use TorrentPier\View;
+/**
+ * Class ViewServiceProvider
+ * @package TorrentPier\ServiceProviders
+ */
class ViewServiceProvider implements ServiceProviderInterface
{
public function register(Container $container)
diff --git a/src/ServiceProviders/VisitorServiceProvider.php b/src/ServiceProviders/VisitorServiceProvider.php
new file mode 100644
index 000000000..90f00d32d
--- /dev/null
+++ b/src/ServiceProviders/VisitorServiceProvider.php
@@ -0,0 +1,17 @@
+db = $db;
+ $this->cache = $cache;
+ }
+
+ public function get($key)
+ {
+ return null;
+ }
+}
diff --git a/src/Twig/Loader/Filesystem.php b/src/Twig/Loader/Filesystem.php
new file mode 100644
index 000000000..d45f00d96
--- /dev/null
+++ b/src/Twig/Loader/Filesystem.php
@@ -0,0 +1,20 @@
+twig = $twig;
}
+ public function addGlobal($name, $value)
+ {
+ $this->twig->addGlobal($name, $value);
+ }
+
/**
* @param $template
* @param array $params
- *
* @return string
*/
public function make($template, $params = [])
{
- return $this->twig->render($template.'.twig', $params);
+ return $this->twig->render($template, $params);
}
}
diff --git a/src/Visitor.php b/src/Visitor.php
new file mode 100644
index 000000000..5d27e9ace
--- /dev/null
+++ b/src/Visitor.php
@@ -0,0 +1,11 @@
+{{ data }}
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
+
+
+
diff --git a/templates/default/blocks/menu.twig b/templates/default/blocks/menu.twig
new file mode 100644
index 000000000..9c98f6c66
--- /dev/null
+++ b/templates/default/blocks/menu.twig
@@ -0,0 +1,33 @@
+
+
diff --git a/templates/default/layouts/main.twig b/templates/default/layouts/main.twig
new file mode 100644
index 000000000..fcfd25cee
--- /dev/null
+++ b/templates/default/layouts/main.twig
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {##}
+
+
+
+
+
+{% include 'blocks/menu' %}
+
+
+
+{% block content %}
+ Content of the page...
+{% endblock %}
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/src/Cache/AdapterTest.php b/tests/src/Cache/AdapterTest.php
new file mode 100644
index 000000000..e2ba43e40
--- /dev/null
+++ b/tests/src/Cache/AdapterTest.php
@@ -0,0 +1,154 @@
+cacheProvider = $this->getMock(CacheProvider::class,
+ ['doFetch', 'doContains', 'doSave', 'doDelete', 'doFlush', 'doGetStats']);
+
+ $this->adapter = $this->getMock(Adapter::class, ['getProvider', 'getType']);
+ $this->adapter->method('getProvider')->willReturn($this->cacheProvider);
+ $this->adapter->method('getType')->willReturn('Void Cache for tests');
+ }
+
+ /**
+ * @covers TorrentPier\Cache\Adapter::has
+ */
+ public function testHas()
+ {
+ $this->cacheProvider->expects(self::once())->method('doContains')
+ ->with('namespaceTest[keyTest][1]')->willReturn(false);
+
+ self::assertEquals(false, $this->adapter->has('namespaceTest::keyTest'));
+ }
+
+ /**
+ * @covers TorrentPier\Cache\Adapter::get
+ */
+ public function testGet()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doFetch')
+ ->with('DoctrineNamespaceCacheKey[namespaceTest]')->willReturn(false);
+
+ $this->cacheProvider->expects(self::at(1))->method('doFetch')
+ ->with('namespaceTest[keyTest][1]')->willReturn(false);
+
+ self::assertEquals(false, $this->adapter->get('namespaceTest::keyTest'));
+ }
+
+ /**
+ * @covers TorrentPier\Cache\Adapter::get
+ */
+ public function testGetCallback()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doFetch')
+ ->with('DoctrineNamespaceCacheKey[namespaceTest]')->willReturn(false);
+
+ $this->cacheProvider->expects(self::at(1))->method('doFetch')
+ ->with('namespaceTest[keyTest][1]')->willReturn(false);
+
+ $callback = function ($cache, $key) {
+ return [$cache instanceof Adapter, $key];
+ };
+
+ self::assertEquals([true, 'namespaceTest::keyTest'], $this->adapter->get('namespaceTest::keyTest', $callback));
+ }
+
+ /**
+ * @covers TorrentPier\Cache\Adapter::set
+ */
+ public function testSet()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doFetch')
+ ->with('DoctrineNamespaceCacheKey[namespaceTest]')->willReturn(false);
+
+ $this->cacheProvider->expects(self::at(1))->method('doSave')
+ ->with('namespaceTest[keyTest][1]', [1,2,3,4], 10)->willReturn(true);
+
+ self::assertEquals(true, $this->adapter->set('namespaceTest::keyTest', [1,2,3,4], 10));
+ }
+
+ public function testGets()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doFetch')
+ ->with('DoctrineNamespaceCacheKey[namespaceTest]')->willReturn(false);
+
+ $this->cacheProvider->expects(self::at(1))->method('doFetch')
+ ->with('namespaceTest[keyTest][1]')->willReturn('testValue');
+
+ self::assertEquals(['keyTest' => 'testValue'], $this->adapter->gets(['keyTest'], 'namespaceTest'));
+ }
+
+ public function testSets()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doFetch')
+ ->with('DoctrineNamespaceCacheKey[namespaceTest]')->willReturn(false);
+
+ $this->cacheProvider->expects(self::at(1))->method('doSave')
+ ->with('namespaceTest[keyTest][1]', [1,2,3,4], 10)->willReturn(true);
+
+ self::assertEquals(true, $this->adapter->sets(['keyTest' => [1,2,3,4]], 'namespaceTest', 10));
+ }
+
+ /**
+ * @covers TorrentPier\Cache\Adapter::delete
+ */
+ public function testDelete()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doFetch')
+ ->with('DoctrineNamespaceCacheKey[namespaceTest]')->willReturn(false);
+
+ $this->cacheProvider->expects(self::at(1))->method('doDelete')
+ ->with('namespaceTest[keyTest][1]')->willReturn(true);
+
+ self::assertEquals(true, $this->adapter->delete('namespaceTest::keyTest'));
+ }
+
+ /**
+ * @covers TorrentPier\Cache\Adapter::deleteAll
+ */
+ public function testDeleteAll()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doFetch')
+ ->with('DoctrineNamespaceCacheKey[namespaceTest]')->willReturn(false);
+
+ $this->cacheProvider->expects(self::at(1))->method('doSave')
+ ->with('DoctrineNamespaceCacheKey[namespaceTest]', 2)->willReturn(true);
+
+ self::assertEquals(true, $this->adapter->deleteAll('namespaceTest'));
+ }
+
+ /**
+ * @covers TorrentPier\Cache\Adapter::flush
+ */
+ public function testFlush()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doFlush')->willReturn(true);
+
+ self::assertEquals(true, $this->adapter->flush());
+ }
+
+ /**
+ * @covers TorrentPier\Cache\Adapter::stats
+ */
+ public function testStats()
+ {
+ $this->cacheProvider->expects(self::at(0))->method('doGetStats')->willReturn(null);
+
+ self::assertEquals(['type' => 'Void Cache for tests'], $this->adapter->stats());
+ }
+}
diff --git a/tests/src/Cache/FileAdapterTest.php b/tests/src/Cache/FileAdapterTest.php
index 0e41e29d1..5fe9827ae 100644
--- a/tests/src/Cache/FileAdapterTest.php
+++ b/tests/src/Cache/FileAdapterTest.php
@@ -2,7 +2,7 @@
namespace TorrentPier\Cache;
-use Doctrine\Common\Cache\PhpFileCache;
+use Doctrine\Common\Cache\FilesystemCache;
/**
* Class FileAdapterTest
@@ -31,7 +31,7 @@ class FileAdapterTest extends \PHPUnit_Framework_TestCase
*/
public function testAdapterCache()
{
- self::assertInstanceOf(PhpFileCache::class, $this->adapter->getProvider());
+ self::assertInstanceOf(FilesystemCache::class, $this->adapter->getProvider());
}
/**
@@ -39,7 +39,7 @@ class FileAdapterTest extends \PHPUnit_Framework_TestCase
*/
public function testStatsType()
{
- self::assertEquals('Cache in php file', $this->adapter->stats()['type']);
+ self::assertEquals('Filesystem Cache', $this->adapter->stats()['type']);
}
/**
diff --git a/tests/src/ConfigTest.php b/tests/src/ConfigTest.php
index 465101b32..23a74d172 100644
--- a/tests/src/ConfigTest.php
+++ b/tests/src/ConfigTest.php
@@ -31,7 +31,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
}
/**
- * Get value from array by key
+ * Get value from array by key.
*
* @see \TorrentPier\Config::get
*/
diff --git a/tests/src/Db/AdapterTest.php b/tests/src/Db/AdapterTest.php
new file mode 100644
index 000000000..1e554980e
--- /dev/null
+++ b/tests/src/Db/AdapterTest.php
@@ -0,0 +1,209 @@
+getMock(Result::class, ['getGeneratedValue', 'getAffectedRows']);
+ $resultMock->method('getGeneratedValue')->willReturn(self::AFFECTED_ROWS);
+ $resultMock->method('getAffectedRows')->willReturn(self::AFFECTED_ROWS);
+
+ $this->statementMock = $this->getMock(Statement::class, ['execute']);
+ $this->statementMock->method('execute')->willReturn($resultMock);
+
+ $this->adapterMock = $this->getMockBuilder(Adapter::class)
+ ->setMethods(['getSql', 'getPlatform', 'getDriver'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $platformMock = $this->getMock(AbstractPlatform::class, ['getName', 'quoteIdentifier', 'quoteValue']);
+ $platformMock->method('quoteIdentifier')->willReturnCallback(function ($v) { return '`' . $v . '`'; });
+ $platformMock->method('quoteValue')->willReturnCallback(function ($v) {
+ if (is_int($v)) {
+ return $v;
+ } elseif ($v instanceof \DateTime) {
+ $v = $v->format('Y-m-d H:i:s');
+ }
+
+ return '\'' . $v . '\'';
+ });
+ $platformMock->method('getName')->willReturn('platform name');
+ $this->adapterMock->method('getPlatform')->willReturn($platformMock);
+
+ $connectionMock = $this->getMock(Connection::class);
+
+ $driverMock = $this->getMock(Pdo::class, [], [
+ $connectionMock,
+ $this->statementMock,
+ $resultMock,
+ ]);
+ $this->adapterMock->method('getDriver')->willReturn($driverMock);
+
+ $this->sqlMock = $this->getMockBuilder(Sql::class)
+ ->setMethods(['prepareStatementForSqlObject'])
+ ->setConstructorArgs([$this->adapterMock])
+ ->getMock();
+ $this->adapterMock->method('getSql')->willReturn($this->sqlMock);
+ }
+
+ /**
+ * Create sql insert query.
+ * @covers \TorrentPier\Db\Adapter::insert
+ */
+ public function testInsert()
+ {
+ $date = new \DateTime('now', new \DateTimeZone('UTC'));
+
+ $this->sqlMock->expects(static::once())
+ ->method('prepareStatementForSqlObject')
+ ->willReturnCallback(function (Insert $sqlObject) use ($date) {
+ static::assertEquals(
+ join(' ', [
+ "INSERT INTO",
+ "`tableName` (`field_int`, `field_str`, `field_date`)",
+ "VALUES (123, 'string', '{$date->format('Y-m-d H:i:s')}')",
+ ]),
+ $this->sqlMock->buildSqlString($sqlObject)
+ );
+ return $this->statementMock;
+ });
+
+ $actual = $this->adapterMock->insert('tableName', [
+ 'field_int' => 123,
+ 'field_str' => 'string',
+ 'field_date' => $date,
+ ]);
+
+ static::assertEquals(self::AFFECTED_ROWS, $actual);
+ }
+
+ /**
+ * Create sql update query.
+ * @covers \TorrentPier\Db\Adapter::update
+ */
+ public function testUpdate()
+ {
+ $date = new \DateTime('now', new \DateTimeZone('UTC'));
+
+ $this->sqlMock->expects(static::once())
+ ->method('prepareStatementForSqlObject')
+ ->willReturnCallback(function (Update $sqlObject) use ($date) {
+ static::assertEquals(
+ join(' ', [
+ "UPDATE `tableName` SET",
+ "`field_int` = 123, `field_str` = 'string', `field_date` = '{$date->format('Y-m-d H:i:s')}'",
+ "WHERE \"field_id\" = 1"
+ ]),
+ $this->sqlMock->buildSqlString($sqlObject)
+ );
+ return $this->statementMock;
+ });
+
+ $actual = $this->adapterMock->update('tableName', [
+ 'field_int' => 123,
+ 'field_str' => 'string',
+ 'field_date' => $date,
+ ], [
+ 'field_id' => 1
+ ]);
+
+ static::assertEquals(self::AFFECTED_ROWS, $actual);
+ }
+
+ /**
+ * Create sql delete query.
+ * @covers \TorrentPier\Db\Adapter::delete
+ */
+ public function testDelete()
+ {
+ $this->sqlMock->expects(static::once())
+ ->method('prepareStatementForSqlObject')
+ ->willReturnCallback(function (Delete $sqlObject) {
+ static::assertEquals(
+ "DELETE FROM `tableName` WHERE \"field_id\" = 1",
+ $this->sqlMock->buildSqlString($sqlObject)
+ );
+ return $this->statementMock;
+ });
+
+ $actual = $this->adapterMock->delete('tableName', [
+ 'field_id' => 1
+ ]);
+
+ static::assertEquals(self::AFFECTED_ROWS, $actual);
+ }
+
+ /**
+ * Create sql increment query.
+ * @covers \TorrentPier\Db\Adapter::increment
+ */
+ public function testIncrement()
+ {
+ $this->sqlMock->expects(static::once())
+ ->method('prepareStatementForSqlObject')
+ ->willReturnCallback(function (Update $sqlObject) {
+ static::assertEquals(
+ "UPDATE `tableName` SET `inc` = \"inc\" + 1 WHERE \"field_id\" = 1",
+ $this->sqlMock->buildSqlString($sqlObject)
+ );
+ return $this->statementMock;
+ });
+
+ $actual = $this->adapterMock->increment('tableName', 'inc', ['field_id' => 1]);
+
+ static::assertEquals(self::AFFECTED_ROWS, $actual);
+ }
+
+ /**
+ * Create sql decrement query.
+ * @covers \TorrentPier\Db\Adapter::decrement
+ */
+ public function testDecrement()
+ {
+ $this->sqlMock->expects(static::once())
+ ->method('prepareStatementForSqlObject')
+ ->willReturnCallback(function (Update $sqlObject) {
+ static::assertEquals(
+ "UPDATE `tableName` SET `inc` = \"inc\" - 1 WHERE \"field_id\" = 1",
+ $this->sqlMock->buildSqlString($sqlObject)
+ );
+ return $this->statementMock;
+ });
+
+ $actual = $this->adapterMock->decrement('tableName', 'inc', ['field_id' => 1]);
+
+ static::assertEquals(self::AFFECTED_ROWS, $actual);
+ }
+}
diff --git a/tests/src/Db/EntityTest.php b/tests/src/Db/EntityTest.php
deleted file mode 100644
index e7436f137..000000000
--- a/tests/src/Db/EntityTest.php
+++ /dev/null
@@ -1,20 +0,0 @@
-table());
- }
-}
-
-class Model extends Entity
-{
- protected $table = 'table name';
-}
diff --git a/tests/src/DiTest.php b/tests/src/DiTest.php
index 9ea976161..0830cf4f7 100644
--- a/tests/src/DiTest.php
+++ b/tests/src/DiTest.php
@@ -29,8 +29,8 @@ class DiTest extends \PHPUnit_Framework_TestCase
/**
* @depends testGetInstanceIsNotInitialized
- * @expectedException \RuntimeException
- * @expectedExceptionMessage Service 'test' is not registered in the container
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Identifier "test" is not defined.
*/
public function testGetByPropertyIsNotExists()
{
diff --git a/tests/src/ServiceProviders/CaptchaServiceProviderTest.php b/tests/src/ServiceProviders/CaptchaServiceProviderTest.php
index e4a1755f9..08f213f89 100644
--- a/tests/src/ServiceProviders/CaptchaServiceProviderTest.php
+++ b/tests/src/ServiceProviders/CaptchaServiceProviderTest.php
@@ -14,7 +14,7 @@ class CaptchaServiceProviderTest extends \PHPUnit_Framework_TestCase
{
$di = new Di();
$di->register(new CaptchaServiceProvider, [
- 'config.captcha.secret_key' => 'secret key'
+ 'config.services.captcha.secret_key' => 'secret key'
]);
static::assertInstanceOf(ReCaptcha::class, $di->captcha);
diff --git a/tests/src/ViewTest.php b/tests/src/ViewTest.php
index a3517762c..05cf731ca 100644
--- a/tests/src/ViewTest.php
+++ b/tests/src/ViewTest.php
@@ -9,13 +9,14 @@ namespace TorrentPier;
class ViewTest extends \PHPUnit_Framework_TestCase
{
/**
- * @see \TorrentPier\View::make
+ * @covers \TorrentPier\View::make
*/
public function testMake()
{
$templateFileName = 'template';
$templateParam = ['key' => 'value'];
+ /** @var \Twig_Environment|\PHPUnit_Framework_MockObject_MockObject $mockTwig */
$mockTwig = $this
->getMockBuilder(\Twig_Environment::class)
->setMethods(['render'])
@@ -24,7 +25,7 @@ class ViewTest extends \PHPUnit_Framework_TestCase
$mockTwig
->expects(static::once())
->method('render')
- ->with(static::equalTo($templateFileName . '.twig'), static::equalTo($templateParam))
+ ->with(static::equalTo($templateFileName), static::equalTo($templateParam))
->willReturnCallback(function () {
return 'test render';
});