Merge branch 'develop' into wip/laravel-6

This commit is contained in:
Ben Thomson 2020-03-27 14:52:15 +08:00
commit ef606c76c5
No known key found for this signature in database
GPG Key ID: E2B9C73B52D15AA0
16 changed files with 241 additions and 41 deletions

View File

@ -43,7 +43,7 @@
"phpunit/phpunit": "^8.0|^9.0",
"fzaninotto/faker": "~1.9",
"squizlabs/php_codesniffer": "3.*",
"jakub-onderka/php-parallel-lint": "^1.0",
"php-parallel-lint/php-parallel-lint": "^1.0",
"meyfa/phpunit-assert-gd": "^2.0.0",
"dms/phpunit-arraysubset-asserts": "^0.1.0"
},

View File

@ -474,7 +474,7 @@ class FormController extends ControllerBehavior
}
if (post('redirect', true)) {
$redirectUrl = $this->getRedirectUrl($context);
$redirectUrl = $this->controller->formGetRedirectUrl($context, $model);
}
if ($model && $redirectUrl) {
@ -493,13 +493,15 @@ class FormController extends ControllerBehavior
}
/**
* Internal method that returns a redirect URL from the config based on
* supplied context. Otherwise the default redirect is used.
* Returns a redirect URL from the config based on supplied context.
* Otherwise the default redirect is used. Relative URLs are treated as
* backend URLs.
*
* @param string $context Redirect context, eg: create, update, delete.
* @param Model $model The active model.
* @return string
*/
protected function getRedirectUrl($context = null)
public function formGetRedirectUrl($context = null, $model = null)
{
$redirectContext = explode('-', $context, 2)[0];
$redirectSource = ends_with($context, '-close') ? 'redirectClose' : 'redirect';

View File

@ -619,6 +619,7 @@ class ImportExportController extends ControllerBehavior
* Prepare CSV
*/
$csv = CsvWriter::createFromFileObject(new SplTempFileObject);
$csv->setOutputBOM(CsvWriter::BOM_UTF8);
$csv->setDelimiter($options['delimiter']);
$csv->setEnclosure($options['enclosure']);
$csv->setEscape($options['escape']);

View File

@ -42,17 +42,17 @@ class ListController extends ControllerBehavior
protected $listConfig = [];
/**
* @var \Backend\Classes\WidgetBase Reference to the list widget object.
* @var \Backend\Classes\WidgetBase[] Reference to the list widget object.
*/
protected $listWidgets = [];
/**
* @var \Backend\Classes\WidgetBase Reference to the toolbar widget objects.
* @var \Backend\Classes\WidgetBase[] Reference to the toolbar widget objects.
*/
protected $toolbarWidgets = [];
/**
* @var \Backend\Classes\WidgetBase Reference to the filter widget objects.
* @var \Backend\Classes\WidgetBase[] Reference to the filter widget objects.
*/
protected $filterWidgets = [];
@ -114,7 +114,7 @@ class ListController extends ControllerBehavior
/**
* Prepare the widgets used by this action
* @return void
* @return \Backend\Widgets\Lists
*/
public function makeList($definition = null)
{
@ -165,7 +165,7 @@ class ListController extends ControllerBehavior
/*
* List Widget with extensibility
*/
$widget = $this->makeWidget('Backend\Widgets\Lists', $columnConfig);
$widget = $this->makeWidget(\Backend\Widgets\Lists::class, $columnConfig);
$widget->bindEvent('list.extendColumns', function () use ($widget) {
$this->controller->listExtendColumns($widget);
@ -203,7 +203,7 @@ class ListController extends ControllerBehavior
if (isset($listConfig->toolbar)) {
$toolbarConfig = $this->makeConfig($listConfig->toolbar);
$toolbarConfig->alias = $widget->alias . 'Toolbar';
$toolbarWidget = $this->makeWidget('Backend\Widgets\Toolbar', $toolbarConfig);
$toolbarWidget = $this->makeWidget(\Backend\Widgets\Toolbar::class, $toolbarConfig);
$toolbarWidget->bindToController();
$toolbarWidget->cssClasses[] = 'list-header';
@ -236,7 +236,7 @@ class ListController extends ControllerBehavior
$filterConfig = $this->makeConfig($listConfig->filter);
$filterConfig->alias = $widget->alias . 'Filter';
$filterWidget = $this->makeWidget('Backend\Widgets\Filter', $filterConfig);
$filterWidget = $this->makeWidget(\Backend\Widgets\Filter::class, $filterConfig);
$filterWidget->bindToController();
/*
@ -286,6 +286,7 @@ class ListController extends ControllerBehavior
/**
* Bulk delete records.
* @return void
* @throws \October\Rain\Exception\ApplicationException when the parent definition is missing.
*/
public function index_onDelete()
{
@ -353,6 +354,7 @@ class ListController extends ControllerBehavior
* Renders the widget collection.
* @param string $definition Optional list definition.
* @return string Rendered HTML for the list.
* @throws \October\Rain\Exception\ApplicationException when there are no list widgets set.
*/
public function listRender($definition = null)
{
@ -455,7 +457,7 @@ class ListController extends ControllerBehavior
/**
* Called after the list columns are defined.
* @param \Backend\Widgets\List $host The hosting list widget
* @param \Backend\Widgets\Lists $host The hosting list widget
* @return void
*/
public function listExtendColumns($host)
@ -473,8 +475,9 @@ class ListController extends ControllerBehavior
/**
* Controller override: Extend supplied model
* @param Model $model
* @return Model
* @param \October\Rain\Database\Model $model
* @param string|null $definition
* @return \October\Rain\Database\Model
*/
public function listExtendModel($model, $definition = null)
{
@ -485,6 +488,7 @@ class ListController extends ControllerBehavior
* Controller override: Extend the query used for populating the list
* before the default query is processed.
* @param \October\Rain\Database\Builder $query
* @param string|null $definition
*/
public function listExtendQueryBefore($query, $definition = null)
{
@ -494,6 +498,7 @@ class ListController extends ControllerBehavior
* Controller override: Extend the query used for populating the list
* after the default query is processed.
* @param \October\Rain\Database\Builder $query
* @param string|null $definition
*/
public function listExtendQuery($query, $definition = null)
{
@ -502,7 +507,8 @@ class ListController extends ControllerBehavior
/**
* Controller override: Extend the records used for populating the list
* after the query is processed.
* @param Illuminate\Contracts\Pagination\LengthAwarePaginator|Illuminate\Database\Eloquent\Collection $records
* @param \Illuminate\Contracts\Pagination\LengthAwarePaginator|\Illuminate\Database\Eloquent\Collection $records
* @param string|null $definition
*/
public function listExtendRecords($records, $definition = null)
{
@ -520,9 +526,9 @@ class ListController extends ControllerBehavior
/**
* Returns a CSS class name for a list row (<tr class="...">).
* @param Model $record The populated model used for the column
* @param string $definition List definition (optional)
* @return string CSS class name
* @param \October\Rain\Database\Model $record The populated model used for the column
* @param string|null $definition List definition (optional)
* @return string|void CSS class name
*/
public function listInjectRowClass($record, $definition = null)
{
@ -530,10 +536,10 @@ class ListController extends ControllerBehavior
/**
* Replace a table column value (<td>...</td>)
* @param Model $record The populated model used for the column
* @param \October\Rain\Database\Model $record The populated model used for the column
* @param string $columnName The column name to override
* @param string $definition List definition (optional)
* @return string HTML view
* @param string|null $definition List definition (optional)
* @return string|void HTML view
*/
public function listOverrideColumnValue($record, $columnName, $definition = null)
{
@ -542,8 +548,8 @@ class ListController extends ControllerBehavior
/**
* Replace the entire table header contents (<th>...</th>) with custom HTML
* @param string $columnName The column name to override
* @param string $definition List definition (optional)
* @return string HTML view
* @param string|null $definition List definition (optional)
* @return string|void HTML view
*/
public function listOverrideHeaderValue($columnName, $definition = null)
{
@ -557,7 +563,7 @@ class ListController extends ControllerBehavior
public static function extendListColumns($callback)
{
$calledClass = self::getCalledExtensionClass();
Event::listen('backend.list.extendColumns', function ($widget) use ($calledClass, $callback) {
Event::listen('backend.list.extendColumns', function (\Backend\Widgets\Lists $widget) use ($calledClass, $callback) {
if (!is_a($widget->getController(), $calledClass)) {
return;
}
@ -565,7 +571,7 @@ class ListController extends ControllerBehavior
});
}
/**
/**
* Static helper for extending filter scopes.
* @param callable $callback
* @return void
@ -573,7 +579,7 @@ class ListController extends ControllerBehavior
public static function extendListFilterScopes($callback)
{
$calledClass = self::getCalledExtensionClass();
Event::listen('backend.filter.extendScopes', function ($widget) use ($calledClass, $callback) {
Event::listen('backend.filter.extendScopes', function (\Backend\Widgets\Filter $widget) use ($calledClass, $callback) {
if (!is_a($widget->getController(), $calledClass)) {
return;
}

View File

@ -24,7 +24,8 @@
data-read-only="<?= $readOnly ? 'true' : 'false' ?>"
data-language="<?= $language ?>"
data-margin="<?= $margin ?>"
data-vendor-path="<?= Url::asset('/modules/backend/formwidgets/codeeditor/assets/vendor/ace') ?>">
data-vendor-path="<?= Url::asset('/modules/backend/formwidgets/codeeditor/assets/vendor/ace') ?>"
<?= $this->formField->getAttributes() ?>>
<div class="editor-toolbar">
<ul>
<li class="searchbox-enable">

View File

@ -19,7 +19,7 @@ trait WidgetMaker
* Makes a widget object with the supplied configuration file.
* @param string $class Widget class name
* @param array $widgetConfig An array of config.
* @return \Backend\Classes\WidgetBase The widget object
* @return mixed|\Backend\Classes\WidgetBase The widget object
*/
public function makeWidget($class, $widgetConfig = [])
{

View File

@ -7,9 +7,10 @@
name="<?= $field->getName() ?>"
id="<?= $field->getId() ?>"
value=""
placeholder="<?= e(trans($field->placeholder)) ?>"
class="form-control"
autocomplete="off"
<?= $field->hasAttribute('maxlength') ? '' : 'maxlength="255"' ?>
<?= $field->getAttributes() ?>
/>
<?php endif ?>
<?php endif ?>

View File

@ -203,7 +203,7 @@ class OctoberEnv extends Command
private function saveEnvSettings($key, $value)
{
if (! $this->envKeyExists($key)) {
$line = sprintf("%s=%s\n", $key, $this->stripQuotes($value));
$line = sprintf("%s=%s\n", $key, $value);
if ($this->config == 'database' && $key != 'DB_CONNECTION') {
$this->writeDbEnvSettings($line);
@ -266,7 +266,11 @@ class OctoberEnv extends Command
private function normalize($value)
{
if (is_string($value)) {
return "'$value'";
if (preg_match('/["\'#]/', $value)) {
return '"' . str_replace('"', '\\"', $value) . '"';
} else {
return $value;
}
} elseif (is_bool($value)) {
return $value ? 'true' : 'false';
} elseif ($value === null) {
@ -276,15 +280,6 @@ class OctoberEnv extends Command
return $value;
}
/**
* @param $string
* @return string
*/
private function stripQuotes($string)
{
return strtr($string, ['"' => '', "'" => '']);
}
/**
* @param $matches
* @return bool

9
tests/fixtures/config/app.php vendored Normal file
View File

@ -0,0 +1,9 @@
<?php
// Fixture used for `october:env` unit tests in `tests/unit/system/console/OctoberEnvTest.php
return [
'debug' => true,
'url' => 'https://localhost',
'key' => 'CHANGE_ME!!!!!!!!!!!!!!!!!!!!!!!',
'timezone' => 'UTC',
];

6
tests/fixtures/config/cache.php vendored Normal file
View File

@ -0,0 +1,6 @@
<?php
// Fixture used for `october:env` unit tests in `tests/unit/system/console/OctoberEnvTest.php
return [
'default' => 'file',
];

10
tests/fixtures/config/cms.php vendored Normal file
View File

@ -0,0 +1,10 @@
<?php
// Fixture used for `october:env` unit tests in `tests/unit/system/console/OctoberEnvTest.php
return [
'enableRoutesCache' => false,
'enableAssetCache' => false,
'databaseTemplates' => false,
'linkPolicy' => 'detect',
'enableCsrfProtection' => true,
];

16
tests/fixtures/config/database.php vendored Normal file
View File

@ -0,0 +1,16 @@
<?php
// Fixture used for `october:env` unit tests in `tests/unit/system/console/OctoberEnvTest.php
return [
'default' => 'mysql',
'connections' => [
'mysql' => [
'host' => 'localhost',
'port' => 3306,
'database' => 'data#base',
'username' => 'teal\'c',
'password' => 'test"quotes\'test',
],
],
'useConfigForTesting' => false,
];

11
tests/fixtures/config/mail.php vendored Normal file
View File

@ -0,0 +1,11 @@
<?php
// Fixture used for `october:env` unit tests in `tests/unit/system/console/OctoberEnvTest.php
return [
'driver' => 'smtp',
'host' => 'smtp.mailgun.org',
'port' => 587,
'encryption' => 'tls',
'username' => null,
'password' => null,
];

6
tests/fixtures/config/queue.php vendored Normal file
View File

@ -0,0 +1,6 @@
<?php
// Fixture used for `october:env` unit tests in `tests/unit/system/console/OctoberEnvTest.php
return [
'default' => 'sync',
];

6
tests/fixtures/config/session.php vendored Normal file
View File

@ -0,0 +1,6 @@
<?php
// Fixture used for `october:env` unit tests in `tests/unit/system/console/OctoberEnvTest.php
return [
'driver' => 'file',
];

View File

@ -0,0 +1,130 @@
<?php
use October\Rain\Foundation\Bootstrap\LoadConfiguration;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use System\Console\OctoberEnv;
class OctoberEnvTest extends TestCase
{
/** @var bool If the config fixtures have been copied */
public static $fixturesCopied = false;
/** @var string Stores the original config path from the app container */
public static $origConfigPath;
protected function setUp()
{
parent::setUp();
$this->setUpConfigFixtures();
$this->stubOutEnvFile();
}
public function testCommand()
{
$command = new OctoberEnv();
$command->setLaravel($this->app);
$command->run(new ArrayInput([]), new NullOutput);
// Check environment file
$envFile = file_get_contents(base_path('.env'));
// Forward compatible assertions
// @TODO: Use only `assertStringContainsString` after L6 upgrade
if (method_exists($this, 'assertStringContainsString')) {
$this->assertStringContainsString('APP_DEBUG=true', $envFile);
$this->assertStringContainsString('APP_URL=https://localhost', $envFile);
$this->assertStringContainsString('DB_CONNECTION=mysql', $envFile);
$this->assertStringContainsString('DB_DATABASE="data#base"', $envFile);
$this->assertStringContainsString('DB_USERNAME="teal\'c"', $envFile);
$this->assertStringContainsString('DB_PASSWORD="test\\"quotes\'test"', $envFile);
$this->assertStringContainsString('DB_PORT=3306', $envFile);
} else {
$this->assertContains('APP_DEBUG=true', $envFile);
$this->assertContains('APP_URL=https://localhost', $envFile);
$this->assertContains('DB_CONNECTION=mysql', $envFile);
$this->assertContains('DB_DATABASE="data#base"', $envFile);
$this->assertContains('DB_USERNAME="teal\'c"', $envFile);
$this->assertContains('DB_PASSWORD="test\\"quotes\'test"', $envFile);
$this->assertContains('DB_PORT=3306', $envFile);
}
}
protected function tearDown()
{
$this->tearDownConfigFixtures();
$this->restoreEnvFile();
parent::tearDown();
}
protected function setUpConfigFixtures()
{
// Mock config path and copy fixtures
if (!is_dir(storage_path('temp/tests/config'))) {
mkdir(storage_path('temp/tests/config'), 0777, true);
}
foreach (glob(base_path('tests/fixtures/config/*.php')) as $file) {
$path = pathinfo($file);
copy($file, storage_path('temp/tests/config/' . $path['basename']));
}
static::$fixturesCopied = true;
// Store original config path
static::$origConfigPath = $this->app->make('path.config');
$this->app->instance('path.config', storage_path('temp/tests/config'));
// Re-load configuration
$configBootstrap = new LoadConfiguration;
$configBootstrap->bootstrap($this->app);
}
protected function tearDownConfigFixtures()
{
// Remove copied config fixtures
if (static::$fixturesCopied) {
foreach (glob(storage_path('temp/tests/config/*.php')) as $file) {
unlink($file);
}
rmdir(storage_path('temp/tests/config'));
rmdir(storage_path('temp/tests'));
static::$fixturesCopied = false;
}
// Restore config path
if (self::$origConfigPath) {
$this->app->instance('path.config', static::$origConfigPath);
static::$origConfigPath = null;
}
// Re-load configuration
$configBootstrap = new LoadConfiguration;
$configBootstrap->bootstrap($this->app);
}
protected function stubOutEnvFile()
{
if (file_exists(base_path('.env.stub'))) {
unlink(base_path('.env.stub'));
}
if (file_exists(base_path('.env'))) {
rename(base_path('.env'), base_path('.env.stub'));
}
}
protected function restoreEnvFile()
{
unlink(base_path('.env'));
if (file_exists(base_path('.env.stub'))) {
rename(base_path('.env.stub'), base_path('.env'));
}
}
}