diff --git a/src/Api/Actions/JsonApiAction.php b/src/Api/Actions/JsonApiAction.php index 54ff48abc..406a51f11 100644 --- a/src/Api/Actions/JsonApiAction.php +++ b/src/Api/Actions/JsonApiAction.php @@ -1,6 +1,7 @@ respond($request); - } catch (ValidationFailureException $e) { + } catch (ValidationException $e) { $errors = []; - foreach ($e->getErrors()->getMessages() as $field => $messages) { + foreach ($e->errors()->toArray() as $field => $messages) { $errors[] = [ 'detail' => implode("\n", $messages), 'path' => $field diff --git a/src/Core/CoreServiceProvider.php b/src/Core/CoreServiceProvider.php index 6bb2b461f..a33ebda76 100644 --- a/src/Core/CoreServiceProvider.php +++ b/src/Core/CoreServiceProvider.php @@ -19,8 +19,6 @@ class CoreServiceProvider extends ServiceProvider return get_class($command).'Handler@handle'; }); - Model::setValidator($this->app['validator']); - Forum::allow('*', function (Forum $forum, User $user, $action) { return $user->hasPermission('forum.'.$action) ?: null; }); diff --git a/src/Core/Discussions/Discussion.php b/src/Core/Discussions/Discussion.php index 8ad0b36da..b07679ab9 100755 --- a/src/Core/Discussions/Discussion.php +++ b/src/Core/Discussions/Discussion.php @@ -12,19 +12,28 @@ use Flarum\Core\Users\User; use Flarum\Core\Support\EventGenerator; use Flarum\Core\Support\Locked; use Flarum\Core\Support\VisibleScope; +use Flarum\Core\Support\ValidatesBeforeSave; class Discussion extends Model { use EventGenerator; use Locked; use VisibleScope; + use ValidatesBeforeSave; + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'discussions'; /** * The validation rules for this model. * * @var array */ - public static $rules = [ + protected $rules = [ 'title' => 'required', 'start_time' => 'required|date', 'comments_count' => 'integer', @@ -37,13 +46,6 @@ class Discussion extends Model 'last_post_number' => 'integer' ]; - /** - * The table associated with the model. - * - * @var string - */ - protected $table = 'discussions'; - /** * The attributes that should be mutated to dates. * diff --git a/src/Core/Discussions/DiscussionsServiceProvider.php b/src/Core/Discussions/DiscussionsServiceProvider.php index 12e6dd3eb..53b4cc828 100644 --- a/src/Core/Discussions/DiscussionsServiceProvider.php +++ b/src/Core/Discussions/DiscussionsServiceProvider.php @@ -19,6 +19,8 @@ class DiscussionsServiceProvider extends ServiceProvider new Extend\EventSubscriber('Flarum\Core\Discussions\Listeners\DiscussionMetadataUpdater') ]); + Discussion::setValidator($this->app->make('validator')); + Discussion::allow('*', function (Discussion $discussion, User $user, $action) { return $user->hasPermission('discussion.'.$action) ?: null; }); diff --git a/src/Core/Exceptions/ValidationFailureException.php b/src/Core/Exceptions/ValidationFailureException.php deleted file mode 100644 index dd2534cfc..000000000 --- a/src/Core/Exceptions/ValidationFailureException.php +++ /dev/null @@ -1,68 +0,0 @@ -errors = new MessageBag; - } - - /** - * @param MessageBag $errors - * @return $this - */ - public function setErrors(MessageBag $errors) - { - $this->errors = $errors; - - return $this; - } - - /** - * @return MessageBag - */ - public function getErrors() - { - return $this->errors; - } - - /** - * @param array $input - * @return $this - */ - public function setInput(array $input) - { - $this->input = $input; - - return $this; - } - - /** - * @return array - */ - public function getInput() - { - return $this->input; - } -} diff --git a/src/Core/Model.php b/src/Core/Model.php index cc5a369db..62b52936b 100755 --- a/src/Core/Model.php +++ b/src/Core/Model.php @@ -35,13 +35,6 @@ abstract class Model extends Eloquent */ protected static $dateAttributes = []; - /** - * The validation rules for this model. - * - * @var array - */ - public static $rules = []; - /** * An array of custom relation methods, grouped by subclass. * @@ -49,124 +42,6 @@ abstract class Model extends Eloquent */ protected static $relationMethods = []; - /** - * The validation factory instance. - * - * @var \Illuminate\Contracts\Validation\Factory - */ - protected static $validator; - - /** - * Boot the model. - * - * @return void - */ - public static function boot() - { - parent::boot(); - - // Before the model is saved, validate it. If validation fails, an - // exception will be thrown, preventing the model from saving. - static::saving(function ($model) { - $model->assertValid(); - }); - } - - /** - * Set the validation factory instance. - * - * @param \Illuminate\Contracts\Validation\Factory $validator - */ - public static function setValidator(Factory $validator) - { - static::$validator = $validator; - } - - /** - * Check whether the model is valid in its current state. - * - * @return boolean - */ - public function valid() - { - return $this->makeValidator()->passes(); - } - - /** - * Throw an exception if the model is not valid in its current state. - * - * @return void - * - * @throws \Flarum\Core\ValidationFailureException - */ - public function assertValid() - { - $validator = $this->makeValidator(); - if ($validator->fails()) { - $this->throwValidationFailureException($validator); - } - } - - protected function throwValidationFailureException($validator) - { - throw (new ValidationFailureException) - ->setErrors($validator->errors()) - ->setInput($validator->getData()); - } - - /** - * Make a new validator instance for this model. - * - * @return \Illuminate\Contracts\Validation\Validator - */ - protected function makeValidator() - { - $dirty = $this->getDirty(); - - $rules = $this->expandUniqueRules(array_only(static::$rules, array_keys($dirty))); - - // TODO: translation - $messages = [ - 'unique' => 'That :attribute has already been taken.', - 'email' => 'The :attribute must be a valid email address.', - 'alpha_num' => 'The :attribute may only contain letters and numbers.' - ]; - - return static::$validator->make($dirty, $rules, $messages); - } - - /** - * Expand 'unique' rules in a set of validation rules into a fuller form - * that Laravel's validator can understand. - * - * @param array $rules - * @return array - */ - protected function expandUniqueRules($rules) - { - foreach ($rules as $column => &$ruleset) { - if (is_string($ruleset)) { - $ruleset = explode('|', $ruleset); - } - foreach ($ruleset as &$rule) { - if (strpos($rule, 'unique') === 0) { - $parts = explode(':', $rule); - $key = $this->getKey() ?: 'NULL'; - $rule = 'unique:'.$this->getTable().','.$column.','.$key.','.$this->getKeyName(); - if (! empty($parts[1])) { - $wheres = explode(',', $parts[1]); - foreach ($wheres as &$where) { - $where .= ','.$this->$where; - } - $rule .= ','.implode(',', $wheres); - } - } - } - } - - return $rules; - } - /** * Get the attributes that should be converted to dates. * @@ -216,7 +91,7 @@ abstract class Model extends Eloquent * * @throws \LogicException */ - public function getCustomRelationship($name) + protected function getCustomRelationship($name) { $relation = static::$relationMethods[get_called_class()][$name]($this); @@ -225,7 +100,7 @@ abstract class Model extends Eloquent . 'Illuminate\Database\Eloquent\Relations\Relation'); } - return $this->relations[$method] = $relation->getResults(); + return $this->relations[$name] = $relation->getResults(); } /** diff --git a/src/Core/Posts/Post.php b/src/Core/Posts/Post.php index d6fb1e486..e852340c5 100755 --- a/src/Core/Posts/Post.php +++ b/src/Core/Posts/Post.php @@ -4,21 +4,27 @@ use DomainException; use Flarum\Core\Posts\Events\PostWasDeleted; use Flarum\Core\Model; use Flarum\Core\Support\Locked; -use Flarum\Core\Exceptions\ValidationFailureException; use Flarum\Core\Support\EventGenerator; +use Flarum\Core\Support\ValidatesBeforeSave; use Illuminate\Database\Eloquent\Builder; class Post extends Model { use EventGenerator; use Locked; + use ValidatesBeforeSave; + + /** + * {@inheritdoc} + */ + protected $table = 'posts'; /** * The validation rules for this model. * * @var array */ - public static $rules = [ + protected $rules = [ 'discussion_id' => 'required|integer', 'time' => 'required|date', 'content' => 'required', @@ -30,11 +36,6 @@ class Post extends Model 'hide_user_id' => 'integer', ]; - /** - * {@inheritdoc} - */ - protected $table = 'posts'; - /** * {@inheritdoc} */ diff --git a/src/Core/Posts/PostsServiceProvider.php b/src/Core/Posts/PostsServiceProvider.php index 7208a349d..765fbfa38 100644 --- a/src/Core/Posts/PostsServiceProvider.php +++ b/src/Core/Posts/PostsServiceProvider.php @@ -19,6 +19,8 @@ class PostsServiceProvider extends ServiceProvider new Extend\PostType('Flarum\Core\Posts\DiscussionRenamedPost') ]); + Post::setValidator($this->app->make('validator')); + CommentPost::setFormatter($this->app->make('flarum.formatter')); Post::allow('*', function ($post, $user, $action) { diff --git a/src/Core/Support/ValidatesBeforeSave.php b/src/Core/Support/ValidatesBeforeSave.php new file mode 100644 index 000000000..8a816437c --- /dev/null +++ b/src/Core/Support/ValidatesBeforeSave.php @@ -0,0 +1,143 @@ +assertValid(); + }); + } + + /** + * Set the validation factory instance. + * + * @param Factory $validator + */ + public static function setValidator(Factory $validator) + { + static::$validator = $validator; + } + + /** + * Check whether the model is valid in its current state. + * + * @return boolean + */ + public function valid() + { + return $this->makeValidator()->passes(); + } + + /** + * Throw an exception if the model is not valid in its current state. + * + * @return void + * + * @throws ValidationException + */ + public function assertValid() + { + $validator = $this->makeValidator(); + + if ($validator->fails()) { + $this->throwValidationException($validator); + } + } + + /** + * @param Validator $validator + * @throws ValidationException + */ + protected function throwValidationException(Validator $validator) + { + throw new ValidationException($validator); + } + + /** + * Make a new validator instance for this model. + * + * @return \Illuminate\Validation\Validator + */ + protected function makeValidator() + { + $dirty = $this->getDirty(); + + $rules = $this->expandUniqueRules(array_only($this->rules, array_keys($dirty))); + + $validator = static::$validator->make($dirty, $rules); + + // TODO: event + + return $validator; + } + + /** + * Expand 'unique' rules in a set of validation rules into a fuller form + * that Laravel's validator can understand. + * + * @param array $rules + * @return array + */ + protected function expandUniqueRules($rules) + { + foreach ($rules as $attribute => &$ruleset) { + if (is_string($ruleset)) { + $ruleset = explode('|', $ruleset); + } + + foreach ($ruleset as &$rule) { + if (strpos($rule, 'unique') === 0) { + $rule = $this->expandUniqueRule($attribute, $rule); + } + } + } + + return $rules; + } + + /** + * Expand a 'unique' rule into a fuller form that Laravel's validator can + * understand, based on this model's properties. + * + * @param string $attribute + * @param string $rule + * @return string + */ + protected function expandUniqueRule($attribute, $rule) + { + $parts = explode(':', $rule); + $key = $this->getKey() ?: 'NULL'; + $rule = 'unique:'.$this->getTable().','.$attribute.','.$key.','.$this->getKeyName(); + + if (! empty($parts[1])) { + $wheres = explode(',', $parts[1]); + + foreach ($wheres as &$where) { + $where .= ','.$this->$where; + } + + $rule .= ','.implode(',', $wheres); + } + + return $rule; + } +} \ No newline at end of file diff --git a/src/Core/Users/User.php b/src/Core/Users/User.php index 3e59e457f..19a44d76a 100755 --- a/src/Core/Users/User.php +++ b/src/Core/Users/User.php @@ -17,18 +17,35 @@ use Flarum\Core\Users\Events\UserEmailChangeWasRequested; use Flarum\Core\Support\Locked; use Flarum\Core\Support\VisibleScope; use Flarum\Core\Support\EventGenerator; +use Flarum\Core\Support\ValidatesBeforeSave; class User extends Model { use EventGenerator; use Locked; use VisibleScope; + use ValidatesBeforeSave; /** * {@inheritdoc} */ protected $table = 'users'; + /** + * The validation rules for this model. + * + * @var array + */ + protected $rules = [ + 'username' => 'required|alpha_dash|unique', + 'email' => 'required|email|unique', + 'password' => 'required', + 'join_time' => 'date', + 'last_seen_time' => 'date', + 'discussions_count' => 'integer', + 'posts_count' => 'integer', + ]; + /** * {@inheritdoc} */ @@ -46,21 +63,6 @@ class User extends Model */ protected static $formatter; - /** - * The validation rules for this model. - * - * @var array - */ - public static $rules = [ - 'username' => 'required|alpha_dash|unique', - 'email' => 'required|email|unique', - 'password' => 'required', - 'join_time' => 'date', - 'last_seen_time' => 'date', - 'discussions_count' => 'integer', - 'posts_count' => 'integer', - ]; - /** * The hasher with which to hash passwords. * @@ -158,13 +160,13 @@ class User extends Model public function requestEmailChange($email) { if ($email !== $this->email) { - $validator = static::$validator->make( - compact('email'), - $this->expandUniqueRules(array_only(static::$rules, 'email')) - ); + $validator = $this->makeValidator(); + + $validator->setRules(array_only($validator->getRules(), 'email')); + $validator->setData(compact('email')); if ($validator->fails()) { - $this->throwValidationFailureException($validator); + $this->throwValidationException($validator); } $this->raise(new UserEmailChangeWasRequested($this, $email)); diff --git a/src/Core/Users/UsersServiceProvider.php b/src/Core/Users/UsersServiceProvider.php index 73cd35eb1..d7be4d49b 100644 --- a/src/Core/Users/UsersServiceProvider.php +++ b/src/Core/Users/UsersServiceProvider.php @@ -21,6 +21,7 @@ class UsersServiceProvider extends ServiceProvider User::setHasher($this->app->make('hash')); User::setFormatter($this->app->make('flarum.formatter')); + User::setValidator($this->app->make('validator')); User::addPreference('discloseOnline', 'boolval', true); User::addPreference('indexProfile', 'boolval', true);