Skip to content

Commit

Permalink
Merge pull request #1246 from creative-commoners/pulls/1/pjax-validat…
Browse files Browse the repository at this point in the history
…ion-result

ENH Pass form validation result to client
  • Loading branch information
michalkleiner authored May 16, 2023
2 parents 2e2983b + a802828 commit c0d05af
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 3 deletions.
2 changes: 1 addition & 1 deletion client/dist/js/bundle.js

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions client/src/legacy/LeftAndMain.js
Original file line number Diff line number Diff line change
Expand Up @@ -489,13 +489,12 @@ $.entwine('ss', function($) {
// Save tab selections so we can restore them later
this.saveTabState();


// Standard Pjax behaviour is to replace the submitted form with new content.
// The returned view isn't always decided upon when the request
// is fired, so the server might decide to change it based on its own logic,
// sending back different `X-Pjax` headers and content
jQuery.ajax(jQuery.extend({
headers: {"X-Pjax" : "CurrentForm,Breadcrumbs"},
headers: {"X-Pjax" : "CurrentForm,Breadcrumbs,ValidationResult"},
url: form.attr('action'),
data: formData,
type: 'POST',
Expand Down
26 changes: 26 additions & 0 deletions code/LeftAndMain.php
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,12 @@ public function getResponseNegotiator()
'SilverStripe\\Admin\\CMSBreadcrumbs'
]);
},
'ValidationResult' => function () {
return $this->prepareDataForPjax([
'isValid' => true,
'messages' => []
]);
},
'default' => function () {
return $this->renderWith($this->getViewer('show'));
}
Expand Down Expand Up @@ -1492,6 +1498,12 @@ public function getEditForm($id = null, $fields = null)
return $negotiator->respond($request, [
'CurrentForm' => function () use ($result) {
return $result;
},
'ValidationResult' => function () use ($errors) {
return $this->prepareDataForPjax([
'isValid' => $errors->isValid(),
'messages' => $errors->getMessages()
]);
}
]);
}
Expand Down Expand Up @@ -1530,6 +1542,20 @@ public function getEditForm($id = null, $fields = null)
return $form;
}

/**
* Convert an array of data to JSON and wrap it in an HTML tag as pjax is used and jQuery will parse this
* as an element on the client side in LeftAndMain.js handleAjaxResponse()
* The attribute type="application/json" denotes this is a data block and won't be processed by a browser
* https://html.spec.whatwg.org/#the-script-element
*
* @param array $data
* @return string
*/
private function prepareDataForPjax(array $data): string
{
return '<script type="application/json">' . json_encode($data) . '</script>';
}

/**
* Returns a placeholder form, used by {@link getEditForm()} if no record is selected.
* Our javascript logic always requires a form to be present in the CMS interface.
Expand Down
48 changes: 48 additions & 0 deletions tests/php/LeftAndMainTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,22 @@
use SilverStripe\View\Requirements;
use SilverStripe\Core\Manifest\VersionedProvider;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Admin\Tests\LeftAndMainTest\MyTree;
use SilverStripe\Admin\Tests\LeftAndMainTest\MyTreeController;
use stdClass;

class LeftAndMainTest extends FunctionalTest
{
protected static $fixture_file = 'LeftAndMainTest.yml';

protected static $extra_dataobjects = [
MyTree::class
];

protected static $extra_controllers = [
MyTreeController::class
];

protected $backupCombined;

protected function setUp(): void
Expand Down Expand Up @@ -238,4 +249,41 @@ public function provideTestCMSVersionNumber()
['myfork', 'myfork'],
];
}

public function testValidationResult()
{
$this->logInAs('admin');

$obj = MyTree::create();
$obj->write();

$getValidationResult = function ($content) use ($obj): stdClass {
$response = $this->post(
"admin/mytree/edit/EditForm/{$obj->ID}/",
[
'ID' => $obj->ID,
'Content' => $content,
'ajax' => 1,
'action_save' => 1
],
[
'X-Pjax' => 'ValidationResult',
]
);
$validationResultPjax = json_decode($response->getBody())->ValidationResult;
return json_decode(preg_replace('#</?script[^>]*?>#', '', $validationResultPjax));
};

// Test valid content
$result = $getValidationResult('Valid content');
$this->assertTrue($result->isValid);
$this->assertSame(0, count($result->messages));

// Test invalid content
$result = $getValidationResult(MyTree::INVALID_CONTENT);
$this->assertFalse($result->isValid);
$this->assertSame(1, count($result->messages));
$this->assertSame($result->messages[0]->fieldName, 'Content');
$this->assertSame($result->messages[0]->message, MyTree::INVALID_CONTENT_MESSAGE);
}
}
26 changes: 26 additions & 0 deletions tests/php/LeftAndMainTest/MyTree.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace SilverStripe\Admin\Tests\LeftAndMainTest;

use SilverStripe\ORM\DataObject;
use SilverStripe\Dev\TestOnly;

class MyTree extends DataObject implements TestOnly
{
public const INVALID_CONTENT = 'INVALID_CONTENT';

public const INVALID_CONTENT_MESSAGE = 'INVALID_CONTENT_MESSAGE';

private static $db = [
'Content' => 'Varchar'
];

public function validate()
{
$validationResult = parent::validate();
if ($this->Content === static::INVALID_CONTENT) {
$validationResult->addFieldError('Content', static::INVALID_CONTENT_MESSAGE);
}
return $validationResult;
}
}
21 changes: 21 additions & 0 deletions tests/php/LeftAndMainTest/MyTreeController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace SilverStripe\Admin\Tests\LeftAndMainTest;

use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Dev\TestOnly;

class MyTreeController extends LeftAndMain implements TestOnly
{
private static $url_segment = 'mytree/edit';

private static $tree_class = MyTree::class;

private static $allowed_actions = [
'EditForm'
];

private static $url_handlers = [
'EditForm/$ID' => 'EditForm',
];
}

0 comments on commit c0d05af

Please sign in to comment.