testing brought in

This commit is contained in:
2026-03-17 01:35:40 -07:00
parent 39334d8e4a
commit 4f996eb7d2
20 changed files with 641 additions and 192 deletions

View File

@@ -18,7 +18,17 @@
"cakephp/cakephp": "^5.0" "cakephp/cakephp": "^5.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^10.1" "cakedc/cakephp-phpstan": "^4.1",
"cakephp/bake": "^3.0.0",
"cakephp/cakephp-codesniffer": "^5.0",
"cakephp/debug_kit": "^5.0.0",
"dereuromark/cakephp-ide-helper": "^2.13",
"dereuromark/cakephp-test-helper": "^2.6",
"fig-r/psr2r-sniffer": "^2.7",
"josegonzalez/dotenv": "^4.0",
"php-collective/decimal-object": "^1.3",
"phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^10.5.5 || ^11.1.3 || ^12.1"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@@ -28,7 +38,25 @@
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"CheeseCake\\Test\\": "tests/", "CheeseCake\\Test\\": "tests/",
"Cake\\Test\\": "vendor/cakephp/cakephp/tests/" "Cake\\Test\\": "vendor/cakephp/cakephp/tests/",
"TestApp\\": "tests/test_app/src/"
}
},
"scripts": {
"post-install-cmd": "App\\Console\\Installer::postInstall",
"post-create-project-cmd": "App\\Console\\Installer::postInstall",
"check": [
"@test",
"@cs-check"
],
"test": "phpunit --colors=always",
"cs-check": "vendor/bin/phpcs --colors --parallel=16",
"cs-fix": "vendor/bin/phpcbf --colors --parallel=16",
"stan": "phpstan analyze"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
} }
} }
} }

20
phpcs.xml Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<ruleset name="plugin">
<arg value="nps"/>
<file>src/</file>
<file>tests/</file>
<exclude-pattern>/tests/test_files/</exclude-pattern>
<exclude-pattern>/tests/test_app/</exclude-pattern>
<rule ref="vendor/fig-r/psr2r-sniffer/PSR2R/ruleset.xml"/>
<rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
<exclude-pattern>*/config/Migrations/*</exclude-pattern>
</rule>
<rule ref="PhpCollective.Classes.ClassFileName.NoMatch">
<exclude-pattern>*/config/Migrations/*</exclude-pattern>
</rule>
</ruleset>

10
phpstan.neon Normal file
View File

@@ -0,0 +1,10 @@
includes:
- vendor/cakedc/cakephp-phpstan/extension.neon
parameters:
level: 4
paths:
- src
bootstrapFiles:
- tests/bootstrap.php
treatPhpDocTypesAsCertain: false

View File

@@ -1,22 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" processIsolation="false" stopOnFailure="false" bootstrap="tests/bootstrap.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" cacheDirectory=".phpunit.cache"> <phpunit
<php> colors="true"
<ini name="memory_limit" value="-1"/> processIsolation="false"
<ini name="apc.enable_cli" value="1"/> stopOnFailure="false"
</php> bootstrap="tests/bootstrap.php"
<!-- Add any additional test suites you want to run here --> >
<testsuites> <php>
<testsuite name="CheeseCake"> <ini name="memory_limit" value="-1"/>
<directory>tests/TestCase/</directory> <ini name="apc.enable_cli" value="1"/>
</testsuite> <env name="FIXTURE_SCHEMA_METADATA" value="tests/schema.php"/>
</testsuites> </php>
<!-- Setup the extension for fixtures -->
<extensions> <!-- Add any additional test suites you want to run here -->
<bootstrap class="Cake\TestSuite\Fixture\Extension\PHPUnitExtension"/> <testsuites>
</extensions> <testsuite name="CakeAddresses">
<source> <directory>tests/TestCase/</directory>
<include> </testsuite>
<directory suffix=".php">src/</directory> </testsuites>
</include>
</source> <!-- Setup fixture extension -->
<extensions>
<bootstrap class="Cake\TestSuite\Fixture\Extension\PHPUnitExtension"/>
</extensions>
<source>
<include>
<directory suffix=".php">src/</directory>
</include>
</source>
</phpunit> </phpunit>

15
psalm.xml Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<psalm
errorLevel="2"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>

View File

@@ -13,9 +13,9 @@ use Cake\Routing\RouteBuilder;
/** /**
* Plugin for CheeseCake * Plugin for CheeseCake
*/ */
class CheeseCakePlugin extends BasePlugin class CheeseCakePlugin extends BasePlugin {
{
/** /**
* Load all the plugin configuration and bootstrap logic. * Load all the plugin configuration and bootstrap logic.
* *
* The host application is provided as an argument. This allows you to load * The host application is provided as an argument. This allows you to load
@@ -24,11 +24,10 @@ class CheeseCakePlugin extends BasePlugin
* @param \Cake\Core\PluginApplicationInterface $app The host application * @param \Cake\Core\PluginApplicationInterface $app The host application
* @return void * @return void
*/ */
public function bootstrap(PluginApplicationInterface $app): void public function bootstrap(PluginApplicationInterface $app): void {
{ }
}
/** /**
* Add routes for the plugin. * Add routes for the plugin.
* *
* If your plugin has many routes and you would like to isolate them into a separate file, * If your plugin has many routes and you would like to isolate them into a separate file,
@@ -37,48 +36,45 @@ class CheeseCakePlugin extends BasePlugin
* @param \Cake\Routing\RouteBuilder $routes The route builder to update. * @param \Cake\Routing\RouteBuilder $routes The route builder to update.
* @return void * @return void
*/ */
public function routes(RouteBuilder $routes): void public function routes(RouteBuilder $routes): void {
{ parent::routes($routes);
parent::routes($routes); }
}
/** /**
* Add middleware for the plugin. * Add middleware for the plugin.
* *
* @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to update. * @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to update.
* @return \Cake\Http\MiddlewareQueue * @return \Cake\Http\MiddlewareQueue
*/ */
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue {
{ // Add your middlewares here
// Add your middlewares here
return $middlewareQueue; return $middlewareQueue;
} }
/** /**
* Add commands for the plugin. * Add commands for the plugin.
* *
* @param \Cake\Console\CommandCollection $commands The command collection to update. * @param \Cake\Console\CommandCollection $commands The command collection to update.
* @return \Cake\Console\CommandCollection * @return \Cake\Console\CommandCollection
*/ */
public function console(CommandCollection $commands): CommandCollection public function console(CommandCollection $commands): CommandCollection {
{ // Add your commands here
// Add your commands here
$commands = parent::console($commands); $commands = parent::console($commands);
return $commands; return $commands;
} }
/** /**
* Register application container services. * Register application container services.
* *
* @link https://book.cakephp.org/4/en/development/dependency-injection.html#dependency-injection
* @param \Cake\Core\ContainerInterface $container The Container to update. * @param \Cake\Core\ContainerInterface $container The Container to update.
* @return void * @return void
* @link https://book.cakephp.org/4/en/development/dependency-injection.html#dependency-injection
*/ */
public function services(ContainerInterface $container): void public function services(ContainerInterface $container): void {
{ // Add your services here
// Add your services here }
}
} }

View File

@@ -5,6 +5,5 @@ namespace CheeseCake\Controller;
use App\Controller\AppController as BaseController; use App\Controller\AppController as BaseController;
class AppController extends BaseController class AppController extends BaseController {
{
} }

View File

@@ -6,65 +6,66 @@ use Cake\Core\Configure;
use Cake\ORM\Table; use Cake\ORM\Table;
use Cake\ORM\TableRegistry; use Cake\ORM\TableRegistry;
trait OverrideTableTrait trait OverrideTableTrait {
{
/**
* @var Table|null
*/
protected ?Table $_table = null;
/** /**
* @var \Cake\ORM\Table|null
*/
protected ?Table $_table = null;
/**
* This object's default table alias. * This object's default table alias.
* *
* @var string|null * @var string|null
*/ */
protected ?string $defaultTable = null; protected ?string $defaultTable = null;
/** /**
* @var string * @var string
*/ */
protected string $_tableConfigKey = ''; protected string $_tableConfigKey = '';
/** /**
* Gets the table instance * Gets the table instance
* *
* @return Table * @return \Cake\ORM\Table
*/ */
public function getTable(string|null $tableName) public function getTable(string|null $tableName) {
{ if ($this->_table instanceof Table) {
if ($this->_table instanceof Table) { return $this->_table;
return $this->_table; }
} $this->getTableConfigKey();
$this->getTableConfigKey(); $table = $tableName;
$table = $tableName; if (!isset($table)) {
if (!isset($table)) { $table = $this->defaultTable;
$table = $this->defaultTable; if (Configure::read($this->_tableConfigKey)) {
if (Configure::read($this->_tableConfigKey)) { $table = Configure::read($this->_tableConfigKey);
$table = Configure::read($this->_tableConfigKey); }
} }
} $this->_table = TableRegistry::getTableLocator()->get($table);
$this->_table = TableRegistry::getTableLocator()->get($table);
return $this->_table; return $this->_table;
} }
protected function getTableConfigKey() /**
{ * @return string
if (!$this->_tableConfigKey) { */
$this->_tableConfigKey = $this->getPlugin() . '.' . $this->defaultTable . '.table'; protected function getTableConfigKey() {
} if (!$this->_tableConfigKey) {
$this->_tableConfigKey = $this->getPlugin() . '.' . $this->defaultTable . '.table';
}
return $this->_tableConfigKey; return $this->_tableConfigKey;
} }
/** /**
* Set the users table * Set the users table
* *
* @param Table $table table * @param \Cake\ORM\Table $table table
* @return void * @return void
*/ */
public function setTable(Table $table) public function setTable(Table $table) {
{ $this->_table = $table;
$this->_table = $table; }
}
} }

View File

@@ -8,9 +8,9 @@ use Cake\ORM\Entity;
/** /**
* Secure Entity - must explicitly pass fields that are acceptable to be updated on each newEntity/patchEntity call * Secure Entity - must explicitly pass fields that are acceptable to be updated on each newEntity/patchEntity call
*/ */
class SecureEntity extends Entity class SecureEntity extends Entity {
{
/** /**
* Fields that can be mass assigned using newEntity() or patchEntity(). * Fields that can be mass assigned using newEntity() or patchEntity().
* *
* Note that when '*' is set to true, this allows all unspecified fields to * Note that when '*' is set to true, this allows all unspecified fields to
@@ -19,5 +19,6 @@ class SecureEntity extends Entity
* *
* @var array<string, bool> * @var array<string, bool>
*/ */
protected array $_accessible = []; protected array $_accessible = [];
} }

View File

@@ -3,120 +3,163 @@ declare(strict_types=1);
namespace CheeseCake\View\Helper; namespace CheeseCake\View\Helper;
use Cake\Log\Log;
use Cake\Routing\Router; use Cake\Routing\Router;
use Cake\View\Helper; use Cake\View\Helper;
use Cake\View\View;
/** /**
* ActiveLink helper * ActiveLink helper
*/ */
class ActiveLinkHelper extends Helper class ActiveLinkHelper extends Helper {
{
/** /**
* Default configuration. * Default configuration.
* *
* @var array<string, mixed> * @var array<string, mixed>
*/ */
protected array $_defaultConfig = [ protected array $_defaultConfig = [
'activeClass' => 'active', 'activeClass' => 'active',
]; ];
/**
/**
* List of helpers used by this helper * List of helpers used by this helper
* *
* @var string[] * @var string[]
*/ */
protected array $helpers = [ protected array $helpers = [
'Html', 'Html',
'Url', 'Url',
]; ];
/** /**
* @param array|string $title * @param array|string $title
* @param array|string|null $url * @param array|string|null $url
* @param array $options * @param array $options
* *
* @return string * @return string
*/ */
public function link(array|string $title, array|string|null $url = null, array $options = []): string public function link(array|string $title, array|string|null $url = null, array $options = []): string {
{ $currentUrl = $options['current'] ?? Router::parseRequest($this->getView()->getRequest());
$currentUrl = Router::parseRequest($this->getView()->getRequest()); if (!array_key_exists('target', $options) || !$currentUrl) {
if (!array_key_exists('target', $options) || !$currentUrl) { return $this->Html->link($title, $url, $options);
return $this->Html->link($title, $url, $options); }
} $target = $options['target'];
$target = $options['target']; $activeClass = $options['activeClass'] ?? $this->getConfig('activeClass');
unset($options['target']); unset($options['target']);
if (is_string($target)) { unset($options['activeClass']);
return $this->_linkFromStringTarget($currentUrl, $target, $title, $url, $options);
}
if (!is_array($target)) {
return $this->Html->link($title, $url, $options);
}
if (!array_key_exists('plugin', $currentUrl)) { if (is_string($target)) {
$currentUrl['plugin'] = false; return $this->_linkFromStringTarget($currentUrl, $target, $title, $url, $activeClass, $options);
} }
if (!array_key_exists('prefix', $currentUrl)) { if (!is_array($target)) {
$currentUrl['prefix'] = false; return $this->Html->link($title, $url, $options);
} }
if (isset($target['or']) && $target['or']) {
foreach ($target['or'] as $singleTargetToMatch) {
if ($this->_matchesUrlFromArrayTarget($currentUrl, $singleTargetToMatch)) {
$options['class'] = $this->_addClass($options);
return $this->Html->link($title, $url, $options); if (!array_key_exists('plugin', $currentUrl)) {
} $currentUrl['plugin'] = false;
} }
return $this->Html->link($title, $url, $options); if (!array_key_exists('prefix', $currentUrl)) {
} $currentUrl['prefix'] = false;
}
if (isset($target['or']) && $target['or']) {
foreach ($target['or'] as $singleTargetToMatch) {
if ($this->_matchesUrlFromArrayTarget($currentUrl, $singleTargetToMatch)) {
$options['class'] = $this->_addClass($options, $activeClass);
if (!$this->_matchesUrlFromArrayTarget($currentUrl, $target)) { return $this->Html->link($title, $url, $options);
return $this->Html->link($title, $url, $options); }
} }
$options['class'] = $this->_addClass($options); return $this->Html->link($title, $url, $options);
}
return $this->Html->link($title, $url, $options); if (!$this->doesUrlMatchTarget($target, $currentUrl)) {
} return $this->Html->link($title, $url, $options);
}
/** $options['class'] = $this->_addClass($options, $activeClass);
return $this->Html->link($title, $url, $options);
}
/**
* @param array|string $targetUrl
* @param array|null $current |null current url
*
* @return bool
*/
public function doesUrlMatchTarget(array|string $targetUrl, array|null $current = null) {
if (!isset($current)) {
$current = Router::parseRequest($this->getView()->getRequest());
}
if (is_string($targetUrl) && Router::normalize($current) == Router::normalize($targetUrl)) {
return true;
}
if (is_array($targetUrl)) {
if (isset($targetUrl['or']) && $targetUrl['or']) {
foreach ($targetUrl['or'] as $singleTargetToMatch) {
$matched = $this->_matchesUrlFromArrayTarget($current, $singleTargetToMatch);
if ($matched) {
return true;
}
}
}
return $this->_matchesUrlFromArrayTarget($current, $targetUrl);
}
return false;
}
/**
* @param array $providedOptions * @param array $providedOptions
* *
* @return string * @return string
*/ */
protected function _addClass(array $providedOptions): string protected function _addClass(array $providedOptions, string $toAdd): string {
{ return array_key_exists('class', $providedOptions) ? $providedOptions['class'] . ' ' . $toAdd : $toAdd;
$activeClass = array_key_exists('activeClass', $providedOptions) ? $providedOptions['activeClass'] : $this->getConfig('activeClass'); }
return array_key_exists('class', $providedOptions) ? $providedOptions['class'] . ' ' . $activeClass : $activeClass; /**
} * @param array $current
* @param string $targetString
* @param string $title
* @param array|string|null $url
* @param array $options
*
* @return string
*/
protected function _linkFromStringTarget(array $current, string $targetString, string $title, array|string|null $url, string $activeClass, array $options) {
if (Router::normalize($current) == Router::normalize($targetString)) {
$options['class'] = $this->_addClass($options, $activeClass);
protected function _linkFromStringTarget(array $current, string $targetString, string $title, array|string|null $url, array $options) return $this->Html->link($title, $url, $options);
{ }
if (Router::normalize($current) == Router::normalize($targetString)) {
$options['class'] = $this->_addClass($options);
return $this->Html->link($title, $url, $options); return $this->Html->link($title, $url, $options);
} }
return $this->Html->link($title, $url, $options); /**
} * @param array $current
* @param array $targetUrl
*
* @return bool
*/
protected function _matchesUrlFromArrayTarget(array $current, array $targetUrl) {
foreach ($targetUrl as $targetKey => $targetValue) {
if (is_array($targetValue)) {
if (!in_array($current[$targetKey], $targetValue)) {
return false;
}
protected function _matchesUrlFromArrayTarget(array $current, array $targetUrl) continue;
{ }
foreach ($targetUrl as $targetKey => $targetValue) { if (!array_key_exists($targetKey, $current) || $targetValue != $current[$targetKey]) {
if (is_array($targetValue)) { return false;
if (!in_array($current[$targetKey], $targetValue)) { }
return false; }
}
continue; return true;
} }
if (!array_key_exists($targetKey, $current) || $targetValue != $current[$targetKey]) {
return false;
}
}
return true;
}
} }

View File

@@ -0,0 +1,118 @@
<?php
namespace CheeseCake\Test\TestCase\View\Helper;
use Cake\Http\ServerRequest;
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
use Cake\View\View;
use CheeseCake\View\Helper\ActiveLinkHelper;
class ActiveLinkHelperTest extends TestCase {
use IntegrationTestTrait;
public function setUp(): void {
parent::setUp();
// $this->loadRoutes();
$routeBuilder = Router::createRouteBuilder('/');
$routeBuilder->scope('/', function (RouteBuilder $routes) {
$routes->setRouteClass(DashedRoute::class);
$routes->get(
'/',
['controller' => 'Tests', 'action' => 'index'],
);
$routes->get(
'/admin/users',
['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'index'],
);
$routes->get(
'/admin/users/view',
['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'view'],
);
});
}
/**
* @return void
*/
public function testLinkMatchesString(): void {
$request = new ServerRequest(['url' => '/']);
$view = new View($request);
$helper = new ActiveLinkHelper($view);
$result = $helper->link('goto', '/', [
'target' => '/',
'activeClass' => 'awesome-active-class',
]);
$this->assertStringContainsString('awesome-active-class', $result);
}
/**
* @return void
*/
public function testLinkMatchesArrayFromCurrent(): void {
$request = new ServerRequest();
$view = new View($request);
$helper = new ActiveLinkHelper($view);
// matches specific controller action
$specificActionResult = $helper->link('goto', ['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'index'], [
'target' => ['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'index'],
'current' => ['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'index'],
'activeClass' => 'awesome-active-class',
]);
$this->assertStringContainsString('awesome-active-class', $specificActionResult);
// match whole controller
$wholeControllerResult = $helper->link('goto', [
'plugin' => null,
'prefix' => 'Admin',
'controller' => 'Users',
'action' => 'index',
], [
'current' => ['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'index'],
'target' => ['prefix' => 'Admin', 'controller' => 'Users'],
'activeClass' => 'awesome-active-class',
]);
$this->assertStringContainsString('awesome-active-class', $wholeControllerResult);
// match whole prefix
$wholePrefixResult = $helper->link('goto', [
'prefix' => 'Admin',
'controller' => 'Users',
'action' => 'index',
], [
'current' => ['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'index'],
'target' => ['prefix' => 'Admin'],
'activeClass' => 'awesome-active-class',
]);
$this->assertStringContainsString('awesome-active-class', $wholePrefixResult);
}
/**
* @return void
*/
public function testLinkDoesNotMatchArray(): void {
$request = new ServerRequest();
$request = $request->withParam('prefix', 'Admin');
$request = $request->withParam('controller', 'Users');
$request = $request->withParam('action', 'index');
$view = new View($request);
$helper = new ActiveLinkHelper($view);
// matches specific controller action
$specificActionResult = $helper->link('goto', ['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'index'], [
'target' => ['controller' => 'Events', 'action' => 'index'],
'current' => ['prefix' => 'Admin', 'controller' => 'Users', 'action' => 'index'],
'activeClass' => 'awesome-active-class',
'class' => 'link-class',
]);
$this->assertStringNotContainsString('awesome-active-class', $specificActionResult);
}
}

View File

@@ -1,6 +1,27 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
use Cake\Core\Configure;
//use Cake\TestSuite\Fixture\SchemaLoader;
define('PLUGIN_ROOT', dirname(__DIR__));
define('ROOT', PLUGIN_ROOT . DS . 'tests' . DS . 'test_app');
define('TMP', PLUGIN_ROOT . DS . 'tmp' . DS);
define('LOGS', TMP . 'logs' . DS);
define('CACHE', TMP . 'cache' . DS);
define('APP', ROOT . DS . 'src' . DS);
define('APP_DIR', 'src');
define('CAKE_CORE_INCLUDE_PATH', PLUGIN_ROOT . '/vendor/cakephp/cakephp');
define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
define('CAKE', CORE_PATH . APP_DIR . DS);
define('WWW_ROOT', PLUGIN_ROOT . DS . 'webroot' . DS);
define('TESTS', __DIR__ . DS);
define('CONFIG', TESTS . 'config' . DS);
ini_set('intl.default_locale', 'en-US');
/** /**
* Test suite bootstrap for CheeseCakePlugin. * Test suite bootstrap for CheeseCakePlugin.
* *
@@ -9,15 +30,15 @@ declare(strict_types=1);
* installed as a dependency of an application. * installed as a dependency of an application.
*/ */
$findRoot = function ($root) { $findRoot = function ($root) {
do { do {
$lastRoot = $root; $lastRoot = $root;
$root = dirname($root); $root = dirname($root);
if (is_dir($root . '/vendor/cakephp/cakephp')) { if (is_dir($root . '/vendor/cakephp/cakephp')) {
return $root; return $root;
} }
} while ($root !== $lastRoot); } while ($root !== $lastRoot);
throw new Exception('Cannot find the root of the application, unable to run tests'); throw new Exception('Cannot find the root of the application, unable to run tests');
}; };
$root = $findRoot(__FILE__); $root = $findRoot(__FILE__);
unset($findRoot); unset($findRoot);
@@ -34,11 +55,21 @@ require_once $root . '/vendor/autoload.php';
require_once $root . '/vendor/cakephp/cakephp/tests/bootstrap.php'; require_once $root . '/vendor/cakephp/cakephp/tests/bootstrap.php';
if (file_exists($root . '/config/bootstrap.php')) { if (file_exists($root . '/config/bootstrap.php')) {
require $root . '/config/bootstrap.php'; require $root . '/config/bootstrap.php';
return; return;
} }
Configure::write('App', [
'namespace' => 'TestApp',
'encoding' => 'UTF-8',
'paths' => [
'testWebroot' => PLUGIN_ROOT . DS . 'tests' . DS . 'test_app' . DS . 'webroot' . DS,
'webroot' => PLUGIN_ROOT . DS . 'webroot' . DS,
'templates' => [
PLUGIN_ROOT . DS . 'tests' . DS . 'test_app' . DS . 'templates' . DS,
],
],
]);
/** /**
* Load schema from a SQL dump file. * Load schema from a SQL dump file.
* *
@@ -49,7 +80,6 @@ if (file_exists($root . '/config/bootstrap.php')) {
* using migrations to provide schema for your plugin, * using migrations to provide schema for your plugin,
* and using \Migrations\TestSuite\Migrator to load schema. * and using \Migrations\TestSuite\Migrator to load schema.
*/ */
use Cake\TestSuite\Fixture\SchemaLoader;
// Load a schema dump file. // Load a schema dump file.
(new SchemaLoader())->loadSqlFiles('tests/schema.sql', 'test'); //(new SchemaLoader())->loadSqlFiles('tests/schema.sql', 'test');

View File

@@ -0,0 +1 @@
<?php

View File

@@ -0,0 +1,95 @@
<?php
/**
* Routes configuration.
*
* In this file, you set up routes to your controllers and their actions.
* Routes are very important mechanism that allows you to freely connect
* different URLs to chosen controllers and their actions (functions).
*
* It's loaded within the context of `Application::routes()` method which
* receives a `RouteBuilder` instance `$routes` as method argument.
*
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;
/*
* This file is loaded in the context of the `Application` class.
* So you can use `$this` to reference the application class instance
* if required.
*/
return function (RouteBuilder $routes): void {
/*
* The default class to use for all routes
*
* The following route classes are supplied with CakePHP and are appropriate
* to set as the default:
*
* - Route
* - InflectedRoute
* - DashedRoute
*
* If no call is made to `Router::defaultRouteClass()`, the class used is
* `Route` (`Cake\Routing\Route\Route`)
*
* Note that `Route` does not do any inflections on URLs which will result in
* inconsistently cased URLs when used with `{plugin}`, `{controller}` and
* `{action}` markers.
*/
$routes->setRouteClass(DashedRoute::class);
$routes->scope('/', function (RouteBuilder $builder): void {
/*
* Here, we are connecting '/' (base path) to a controller called 'Pages',
* its action called 'display', and we pass a param to select the view file
* to use (in this case, templates/Pages/home.php)...
*/
$builder->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
$builder->prefix('Admin', function (RouteBuilder $adminRouteBuilder): void {
$adminRouteBuilder->connect('/users/view', ['controller' => 'Pages', 'action' => 'view']);
$adminRouteBuilder->connect('/users/index', ['controller' => 'Pages', 'action' => 'index']);
});
/*
* Connect catchall routes for all controllers.
*
* The `fallbacks` method is a shortcut for
*
* ```
* $builder->connect('/{controller}', ['action' => 'index']);
* $builder->connect('/{controller}/{action}/*', []);
* ```
*
* You can remove these routes once you've connected the
* routes you want in your application.
*/
$builder->fallbacks();
});
/*
* If you need a different set of middleware or none at all,
* open new scope and define routes there.
*
* ```
* $routes->scope('/api', function (RouteBuilder $builder): void {
* // No $builder->applyMiddleware() here.
*
* // Parse specified extensions from URLs
* // $builder->setExtensions(['json', 'xml']);
*
* // Connect API actions here.
* });
* ```
*/
};

View File

@@ -0,0 +1,16 @@
<?php
namespace TestApp\Controller;
use Cake\Controller\Controller;
class AppController extends Controller {
/**
* @return void
*/
public function initialize(): void {
parent::initialize();
$this->loadComponent('Flash');
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace TestApp\View;
use Cake\View\View;
/**
* @property \TinyAuth\View\Helper\AuthUserHelper $AuthUser
*/
class AppView extends View {
}

View File

@@ -0,0 +1,44 @@
<?php
use Cake\Core\Configure;
use Cake\Error\Debugger;
$this->layout = 'error';
if (Configure::read('debug')):
$this->layout = 'dev_error';
$this->assign('title', $message);
$this->assign('templateName', 'error500.ctp');
$this->start('file');
?>
<?php if (!empty($error->queryString)) : ?>
<p class="notice">
<strong>SQL Query: </strong>
<?= h($error->queryString) ?>
</p>
<?php endif; ?>
<?php if (!empty($error->params)) : ?>
<strong>SQL Query Params: </strong>
<?php Debugger::dump($error->params) ?>
<?php endif; ?>
<?php if ($error instanceof Error) : ?>
<strong>Error in: </strong>
<?= sprintf('%s, line %s', str_replace(ROOT, 'ROOT', $error->getFile()), $error->getLine()) ?>
<?php endif; ?>
<?php
echo $this->element('auto_table_warning');
if (extension_loaded('xdebug')):
xdebug_print_function_stack();
endif;
$this->end();
endif;
?>
<h2><?= __d('cake', 'An Internal Error Has Occurred') ?></h2>
<p class="error">
<strong><?= __d('cake', 'Error') ?>: </strong>
<?= h($message) ?>
</p>

View File

@@ -0,0 +1,6 @@
<?php
/**
* @var \App\View\AppView $this
*/
?>
<?= $this->fetch('content') ?>

View File

@@ -0,0 +1,6 @@
<?php
/**
* @var \App\View\AppView $this
*/
?>
<?= $this->fetch('content') ?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B