Skip to content

Commit 254cdc9

Browse files
committed
Merge branch 'main' into fix-error-display-in-prefixed-fields
2 parents 7ccad6f + 23586dd commit 254cdc9

File tree

14 files changed

+439
-160
lines changed

14 files changed

+439
-160
lines changed

src/app/Http/Middleware/AuthenticateSession.php

Lines changed: 2 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -2,112 +2,8 @@
22

33
namespace Backpack\CRUD\app\Http\Middleware;
44

5-
use Closure;
6-
use Illuminate\Auth\AuthenticationException;
7-
use Illuminate\Contracts\Auth\Factory as AuthFactory;
8-
use Illuminate\Contracts\Session\Middleware\AuthenticatesSessions;
9-
10-
class AuthenticateSession implements AuthenticatesSessions
11-
{
12-
/**
13-
* The authentication factory implementation.
14-
*
15-
* @var \Illuminate\Contracts\Auth\Factory
16-
*/
17-
protected $auth;
18-
protected $user;
19-
20-
/**
21-
* Create a new middleware instance.
22-
*
23-
* @param \Illuminate\Contracts\Auth\Factory $auth
24-
* @return void
25-
*/
26-
public function __construct(AuthFactory $auth)
27-
{
28-
$this->auth = $auth;
29-
$this->user = backpack_user();
30-
}
31-
32-
/**
33-
* Handle an incoming request.
34-
*
35-
* @param \Illuminate\Http\Request $request
36-
* @param \Closure $next
37-
* @return mixed
38-
*/
39-
public function handle($request, Closure $next)
40-
{
41-
if (! $request->hasSession() || ! $this->user) {
42-
return $next($request);
43-
}
44-
45-
if ($this->guard()->viaRemember()) {
46-
$passwordHash = explode('|', $request->cookies->get($this->guard()->getRecallerName()))[2] ?? null;
47-
48-
if (! $passwordHash || $passwordHash != $this->user->getAuthPassword()) {
49-
$this->logout($request);
50-
}
51-
}
52-
53-
if (! $request->session()->has('password_hash_'.backpack_guard_name())) {
54-
$this->storePasswordHashInSession($request);
55-
}
56-
57-
if ($request->session()->get('password_hash_'.backpack_guard_name()) !== $this->user->getAuthPassword()) {
58-
$this->logout($request);
59-
}
60-
61-
return tap($next($request), function () use ($request) {
62-
if (! is_null($this->guard()->user())) {
63-
$this->storePasswordHashInSession($request);
64-
}
65-
});
66-
}
67-
68-
/**
69-
* Store the user's current password hash in the session.
70-
*
71-
* @param \Illuminate\Http\Request $request
72-
* @return void
73-
*/
74-
protected function storePasswordHashInSession($request)
75-
{
76-
if (! $this->user) {
77-
return;
78-
}
79-
80-
$request->session()->put([
81-
'password_hash_'.backpack_guard_name() => $this->user->getAuthPassword(),
82-
]);
83-
}
84-
85-
/**
86-
* Log the user out of the application.
87-
*
88-
* @param \Illuminate\Http\Request $request
89-
* @return void
90-
*
91-
* @throws \Illuminate\Auth\AuthenticationException
92-
*/
93-
protected function logout($request)
94-
{
95-
$this->guard()->logoutCurrentDevice();
96-
97-
$request->session()->flush();
98-
99-
\Alert::error('Your password was changed in another browser session. Please login again using the new password.')->flash();
100-
101-
throw new AuthenticationException('Unauthenticated.', [backpack_guard_name()], backpack_url('login'));
102-
}
103-
104-
/**
105-
* Get the guard instance that should be used by the middleware.
106-
*
107-
* @return \Illuminate\Contracts\Auth\Factory|\Illuminate\Contracts\Auth\Guard
108-
*/
109-
protected function guard()
5+
if (class_exists('Illuminate\Contracts\Session\Middleware\AuthenticatesSessions', false)) {
6+
class AuthenticateSession extends AuthenticateSessionL9
1107
{
111-
return $this->auth;
1128
}
1139
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
namespace Backpack\CRUD\app\Http\Middleware;
4+
5+
use Closure;
6+
use Illuminate\Auth\AuthenticationException;
7+
use Illuminate\Contracts\Auth\Factory as AuthFactory;
8+
9+
class AuthenticateSessionL9 implements \Illuminate\Contracts\Session\Middleware\AuthenticatesSessions
10+
{
11+
/**
12+
* The authentication factory implementation.
13+
*
14+
* @var \Illuminate\Contracts\Auth\Factory
15+
*/
16+
protected $auth;
17+
18+
protected $user;
19+
20+
/**
21+
* Create a new middleware instance.
22+
*
23+
* @param \Illuminate\Contracts\Auth\Factory $auth
24+
* @return void
25+
*/
26+
public function __construct(AuthFactory $auth)
27+
{
28+
$this->auth = $auth;
29+
$this->user = backpack_user();
30+
}
31+
32+
/**
33+
* Handle an incoming request.
34+
*
35+
* @param \Illuminate\Http\Request $request
36+
* @param \Closure $next
37+
* @return mixed
38+
*/
39+
public function handle($request, Closure $next)
40+
{
41+
if (! $request->hasSession() || ! $this->user) {
42+
return $next($request);
43+
}
44+
45+
if ($this->guard()->viaRemember()) {
46+
$passwordHash = explode('|', $request->cookies->get($this->guard()->getRecallerName()))[2] ?? null;
47+
48+
if (! $passwordHash || $passwordHash != $this->user->getAuthPassword()) {
49+
$this->logout($request);
50+
}
51+
}
52+
53+
if (! $request->session()->has('password_hash_'.backpack_guard_name())) {
54+
$this->storePasswordHashInSession($request);
55+
}
56+
57+
if ($request->session()->get('password_hash_'.backpack_guard_name()) !== $this->user->getAuthPassword()) {
58+
$this->logout($request);
59+
}
60+
61+
return tap($next($request), function () use ($request) {
62+
if (! is_null($this->guard()->user())) {
63+
$this->storePasswordHashInSession($request);
64+
}
65+
});
66+
}
67+
68+
/**
69+
* Store the user's current password hash in the session.
70+
*
71+
* @param \Illuminate\Http\Request $request
72+
* @return void
73+
*/
74+
protected function storePasswordHashInSession($request)
75+
{
76+
if (! $this->user) {
77+
return;
78+
}
79+
80+
$request->session()->put([
81+
'password_hash_'.backpack_guard_name() => $this->user->getAuthPassword(),
82+
]);
83+
}
84+
85+
/**
86+
* Log the user out of the application.
87+
*
88+
* @param \Illuminate\Http\Request $request
89+
* @return void
90+
*
91+
* @throws \Illuminate\Auth\AuthenticationException
92+
*/
93+
protected function logout($request)
94+
{
95+
$this->guard()->logoutCurrentDevice();
96+
97+
$request->session()->flush();
98+
99+
\Alert::error('Your password was changed in another browser session. Please login again using the new password.')->flash();
100+
101+
throw new AuthenticationException('Unauthenticated.', [backpack_guard_name()], backpack_url('login'));
102+
}
103+
104+
/**
105+
* Get the guard instance that should be used by the middleware.
106+
*
107+
* @return \Illuminate\Contracts\Auth\Factory|\Illuminate\Contracts\Auth\Guard
108+
*/
109+
protected function guard()
110+
{
111+
return $this->auth;
112+
}
113+
}

src/app/Library/CrudPanel/CrudColumn.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function key(string $key)
8989
$column['key'] = $key;
9090
}
9191
$this->attributes = $column;
92-
$this->setOperationSetting('columns', array_merge($columns, [$key => $column]));
92+
$this->crud()->setOperationSetting('columns', array_merge($columns, [$key => $column]));
9393

9494
return $this;
9595
}

src/app/Library/CrudPanel/CrudFilter.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,9 @@ public function getNamespacedViewWithFallbacks()
181181
*/
182182
public static function name($name)
183183
{
184-
return new static(compact('name'), null, null, null);
184+
$filter = new static(compact('name'), null, null, null);
185+
186+
return $filter->save();
185187
}
186188

187189
/**

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

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
44

5+
use Illuminate\Foundation\Http\FormRequest;
56
use Illuminate\Support\Str;
67

78
trait Validation
@@ -98,7 +99,7 @@ private function getValidationMessagesFromFieldsAndSubfields($fields)
9899
});
99100

100101
foreach ($subfieldsWithValidationMessages as $subfield) {
101-
foreach ($subfield['validationMessages'] as $rule => $message) {
102+
foreach ($subfield['validationMessages'] ?? [] as $rule => $message) {
102103
$messages[$item['name'].'.*.'.$subfield['name'].'.'.$rule] = $message;
103104
}
104105
}
@@ -133,7 +134,7 @@ public function setValidation($classOrRulesArray = false, $messages = [])
133134
$this->setValidationFromFields();
134135
} elseif (is_array($classOrRulesArray)) {
135136
$this->setValidationFromArray($classOrRulesArray, $messages);
136-
} elseif (is_string($classOrRulesArray) || is_class($classOrRulesArray)) {
137+
} elseif (is_string($classOrRulesArray) && class_exists($classOrRulesArray) && is_a($classOrRulesArray, FormRequest::class, true)) {
137138
$this->setValidationFromRequest($classOrRulesArray);
138139
} else {
139140
abort(500, 'Please pass setValidation() nothing, a rules array or a FormRequest class.');
@@ -202,55 +203,71 @@ public function validateRequest()
202203
return app($formRequest);
203204
}
204205

205-
// create an alias of the provided FormRequest so we can create a new class that extends it.
206-
// we can't use $variables to extend classes.
207-
class_alias(get_class(new $formRequest), 'DeveloperProvidedFormRequest');
206+
$formRequest = (new $formRequest)->createFrom($this->getRequest());
207+
$extendedRules = $this->mergeRules($formRequest, $rules);
208+
$extendedMessages = array_merge($messages, $formRequest->messages());
208209

209-
// create a new anonymous class that will extend the provided developer FormRequest
210-
// in this class we will merge the FormRequest rules() and messages() with the ones provided by developer in fields.
211-
$extendedRequest = new class($rules, $messages) extends \DeveloperProvidedFormRequest
212-
{
213-
private $_rules;
214-
215-
private $_messages;
210+
// validate the complete request with FormRequest + controller validation + field validation (our anonymous class)
211+
return $this->checkRequestValidity($extendedRules, $extendedMessages, $formRequest);
212+
}
216213

217-
public function __construct($rules, $messages)
218-
{
219-
parent::__construct();
220-
$this->_rules = $rules;
221-
$this->_messages = $messages;
222-
}
214+
return ! empty($rules) ? $this->checkRequestValidity($rules, $messages) : $this->getRequest();
215+
}
223216

224-
public function rules()
225-
{
226-
return array_merge(parent::rules(), $this->_rules);
227-
}
217+
/**
218+
* Return an array containing the request rules and the field/controller rules merged.
219+
* The rules in request will take precedence over the ones in controller/fields.
220+
*
221+
* @param \Illuminate\Http\Request $request
222+
* @param array $rules
223+
* @return array
224+
*/
225+
private function mergeRules($request, $rules)
226+
{
227+
$extendedRules = [];
228+
$requestRules = $this->getRequestRulesAsArray($request);
229+
$rules = array_map(function ($ruleDefinition) {
230+
return is_array($ruleDefinition) ? $ruleDefinition : explode('|', $ruleDefinition);
231+
}, $rules);
232+
233+
foreach ($requestRules as $ruleKey => $rule) {
234+
$extendedRules[$ruleKey] = array_key_exists($ruleKey, $rules) ? array_merge($rule, $rules[$ruleKey]) : $rule;
235+
unset($rules[$ruleKey]);
236+
}
228237

229-
public function messages()
230-
{
231-
return array_merge(parent::messages(), $this->_messages);
232-
}
233-
};
238+
return array_merge($rules, $extendedRules);
239+
}
234240

235-
// validate the complete request with FormRequest + controller validation + field validation (our anonymous class)
236-
return app(get_class($extendedRequest), ['rules' => $rules, 'messages' => $messages]);
241+
/**
242+
* Return the request rules as an array of rules if developer provided a rule string configuration.
243+
*
244+
* @param \Illuminate\Http\Request $request
245+
* @return array
246+
*/
247+
private function getRequestRulesAsArray($request)
248+
{
249+
$requestRules = [];
250+
foreach ($request->rules() as $ruleKey => $rule) {
251+
$requestRules[$ruleKey] = is_array($rule) ? $rule : explode('|', $rule);
237252
}
238253

239-
return ! empty($rules) ? $this->checkRequestValidity($rules, $messages) : $this->getRequest();
254+
return $requestRules;
240255
}
241256

242257
/**
243-
* Checks if the current crud request is valid against the provided rules.
258+
* Checks if the request is valid against the rules.
244259
*
245260
* @param array $rules
246261
* @param array $messages
262+
* @param \Illuminate\Http\Request|null $request
247263
* @return \Illuminate\Http\Request
248264
*/
249-
private function checkRequestValidity($rules, $messages)
265+
private function checkRequestValidity($rules, $messages, $request = null)
250266
{
251-
$this->getRequest()->validate($rules, $messages);
267+
$request = $request ?? $this->getRequest();
268+
$request->validate($rules, $messages);
252269

253-
return $this->getRequest();
270+
return $request;
254271
}
255272

256273
/**

0 commit comments

Comments
 (0)