Skip to content

Commit c4a3744

Browse files
authored
Merge pull request #4220 from Laravel-Backpack/validation-for-subfields
Always apply field validation, on top of array & formRequest validation
2 parents ec24c10 + 20b3204 commit c4a3744

File tree

9 files changed

+302
-100
lines changed

9 files changed

+302
-100
lines changed

src/BackpackServiceProvider.php

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
use Backpack\CRUD\app\Library\CrudPanel\CrudPanel;
77
use Illuminate\Routing\Router;
88
use Illuminate\Support\Collection;
9-
use Illuminate\Support\Facades\App;
10-
use Illuminate\Support\Facades\Route;
119
use Illuminate\Support\ServiceProvider;
1210

1311
class BackpackServiceProvider extends ServiceProvider
@@ -57,6 +55,9 @@ public function boot(\Illuminate\Routing\Router $router)
5755
*/
5856
public function register()
5957
{
58+
// load the macros
59+
include_once __DIR__.'/macros.php';
60+
6061
// Bind the CrudPanel object to Laravel's service container
6162
$this->app->singleton('crud', function ($app) {
6263
return new CrudPanel($app);
@@ -67,12 +68,6 @@ public function register()
6768
return new Collection();
6869
});
6970

70-
// load a macro for Route,
71-
// helps developers load all routes for a CRUD resource in one line
72-
if (! Route::hasMacro('crud')) {
73-
$this->addRouteMacro();
74-
}
75-
7671
// register the helper functions
7772
$this->loadHelpers();
7873

@@ -179,47 +174,6 @@ public function setupCustomRoutes(Router $router)
179174
}
180175
}
181176

182-
/**
183-
* The route macro allows developers to generate the routes for a CrudController,
184-
* for all operations, using a simple syntax: Route::crud().
185-
*
186-
* It will go to the given CrudController and get the setupRoutes() method on it.
187-
*/
188-
private function addRouteMacro()
189-
{
190-
Route::macro('crud', function ($name, $controller) {
191-
// put together the route name prefix,
192-
// as passed to the Route::group() statements
193-
$routeName = '';
194-
if ($this->hasGroupStack()) {
195-
foreach ($this->getGroupStack() as $key => $groupStack) {
196-
if (isset($groupStack['name'])) {
197-
if (is_array($groupStack['name'])) {
198-
$routeName = implode('', $groupStack['name']);
199-
} else {
200-
$routeName = $groupStack['name'];
201-
}
202-
}
203-
}
204-
}
205-
// add the name of the current entity to the route name prefix
206-
// the result will be the current route name (not ending in dot)
207-
$routeName .= $name;
208-
209-
// get an instance of the controller
210-
if ($this->hasGroupStack()) {
211-
$groupStack = $this->getGroupStack();
212-
$groupNamespace = $groupStack && isset(end($groupStack)['namespace']) ? end($groupStack)['namespace'].'\\' : '';
213-
} else {
214-
$groupNamespace = '';
215-
}
216-
$namespacedController = $groupNamespace.$controller;
217-
$controllerInstance = App::make($namespacedController);
218-
219-
return $controllerInstance->setupRoutes($name, $routeName, $controller);
220-
});
221-
}
222-
223177
public function loadViewsWithFallbacks()
224178
{
225179
$customBaseFolder = resource_path('views/vendor/backpack/base');

src/app/Library/CrudPanel/CrudField.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
* @method self wrapper(array $value)
2626
* @method self fake(bool $value)
2727
* @method self store_in(string $value)
28+
* @method self validationRules(string $value)
29+
* @method self validationMessages(array $value)
2830
*/
2931
class CrudField
3032
{
@@ -195,6 +197,40 @@ public function subfields($subfields)
195197
return $this->save();
196198
}
197199

200+
/**
201+
* Save the validation rules on the CrudPanel per field basis.
202+
*
203+
* @param string $rules the field rules: required|min:1|max:5
204+
* @return self
205+
*/
206+
public function validationRules(string $rules)
207+
{
208+
$this->attributes['validationRules'] = $rules;
209+
$this->crud()->setValidationFromArray([$this->attributes['name'] => $rules]);
210+
211+
return $this;
212+
}
213+
214+
/**
215+
* Save the validation messages on the CrudPanel per field basis.
216+
*
217+
* @param array $messages the messages for field rules: [required => please input something, min => the minimum allowed is 1]
218+
* @return self
219+
*/
220+
public function validationMessages(array $messages)
221+
{
222+
$this->attributes['validationMessages'] = $messages;
223+
224+
// append the field name to the rule name of validationMessages array.
225+
// eg: ['required => 'This field is required']
226+
// will be transformed into: ['field_name.required' => 'This field is required]
227+
$this->crud()->setValidationFromArray([], array_merge(...array_map(function ($rule, $message) {
228+
return [$this->attributes['name'].'.'.$rule => $message];
229+
}, array_keys($messages), $messages)));
230+
231+
return $this;
232+
}
233+
198234
// ---------------
199235
// PRIVATE METHODS
200236
// ---------------

src/app/Library/CrudPanel/Traits/Fields.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public function makeSureFieldHasNecessaryAttributes($field)
5858
$field = $this->makeSureFieldHasType($field);
5959
$field = $this->makeSureSubfieldsHaveNecessaryAttributes($field);
6060

61+
$this->setupFieldValidation($field, $field['parentFieldName'] ?? false);
62+
6163
return $field;
6264
}
6365

src/app/Library/CrudPanel/Traits/FieldsProtectedMethods.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ protected function makeSureSubfieldsHaveNecessaryAttributes($field)
268268
$subfield = ['name' => $subfield];
269269
}
270270

271+
$subfield['parentFieldName'] = $field['name'];
272+
271273
if (! isset($field['model'])) {
272274
// we're inside a simple 'repeatable' with no model/relationship, so
273275
// we assume all subfields are supposed to be text fields
@@ -292,6 +294,7 @@ protected function makeSureSubfieldsHaveNecessaryAttributes($field)
292294
case 'MorphToMany':
293295
case 'BelongsToMany':
294296
$pivotSelectorField = static::getPivotFieldStructure($field);
297+
$this->setupFieldValidation($pivotSelectorField, $field['name']);
295298
$field['subfields'] = Arr::prepend($field['subfields'], $pivotSelectorField);
296299
break;
297300
case 'MorphMany':

src/app/Library/CrudPanel/Traits/Relationships.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,10 @@ private static function getPivotFieldStructure($field)
299299
$pivotSelectorField['delay'] = 500;
300300
$pivotSelectorField['placeholder'] = trans('backpack::crud.select_entry');
301301
$pivotSelectorField['label'] = \Str::of($field['name'])->singular()->ucfirst();
302+
$pivotSelectorField['validationRules'] = 'required';
303+
$pivotSelectorField['validationMessages'] = [
304+
'required' => trans('backpack::crud.pivot_selector_required_validation_message'),
305+
];
302306

303307
if (isset($field['baseModel'])) {
304308
$pivotSelectorField['baseModel'] = $field['baseModel'];

0 commit comments

Comments
 (0)