REFACTORING: move content update and create logic into separate interactions

This commit is contained in:
Michal Kváček
2016-10-17 02:52:30 +02:00
parent 6ec692bd1c
commit eabbf48ee0
13 changed files with 271 additions and 141 deletions
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\CMS\Contracts;
use App\Http\Requests\Request;
interface Interaction {
public function handle(Request $request, $parameters);
public function getValidationRules($parameters);
}
@@ -0,0 +1,19 @@
<?php
namespace App\CMS\Exceptions\Validation;
use Exception;
class ValidationFailedException extends \Exception {
protected $validator;
public function __construct($validator, $message = null, $code = null, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->validator = $validator;
}
public function getValidator(){
return $this->validator;
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Cms\Handlers\Interactions;
use App\CMS\Contracts\Interaction as InteractionContract;
use App\CMS\Exceptions\Validation\ValidationFailedException;
use App\Http\Requests\Request;
use Illuminate\Support\Facades\Validator;
class Interaction {
/**
* Handle interaction with application
*
* @param Request $request
* @param InteractionContract $interaction
*
* @param array $parameters
*
* @return mixed
* @throws ValidationFailedException
*/
public static function handle(Request $request, InteractionContract $interaction, ...$parameters) {
$validationRules = $interaction->getValidationRules($parameters);
$validator = Validator::make($request->all(), $validationRules);
if ($validator->fails()) {
throw new ValidationFailedException($validator);
}
return $interaction->handle($request, $parameters);
}
}
@@ -0,0 +1,86 @@
<?php
namespace App\Cms\Interactions\Admin\Content;
use App\CMS\Contracts\Interaction;
use App\CMS\Enumerations\ContentStatuses;
use App\CMS\Helpers\CurrentTemplate;
use App\Events\EditContent as EditContentEvent;
use App\Http\Requests\Request;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
class EditContent implements Interaction
{
public function handle(Request $request, $parameters)
{
$page = $parameters[0];
// upload file - if provided
$file = $page->uploadTitlePhoto($request);
// let template to modify request and content page
call_user_func_array([CurrentTemplate::handler(), 'beforeSave'], [&$page, $request]);
$request->url = Str::slug($request->url);
$request->parentPage = $request->parentPage ? $request->parentPage : null;
$request->publishedFrom = empty($request->publishedFrom) ? null : $request->publishedFrom;
$request->publishedTo = empty($request->publishedTo) ? null : $request->publishedTo;
if (!$file) {
$request->titlePhotoFilename = empty($request->existingTitlePhoto) ? null : $request->existingTitlePhoto;
} else {
$request->titlePhotoFilename = $file['filename'];
}
// array of fields in database and fields from request
$fields = [
'title' => 'title',
'url' => 'url',
'template' => 'template',
'published_from' => 'publishedFrom',
'published_to' => 'publishedTo',
'meta_keywords' => 'metaKeywords',
'meta_description' => 'metaDescription',
'content' => 'pageContent',
'parent_id' => 'parentPage',
'status' => 'status',
'title_photo' => 'titlePhotoFilename',
'category_id' => 'category'
];
// save new values with history
// todo move this method out of the controller!
$data = \App\Http\Controllers\Admin\Contents\EditContent::getFields($request, array_values($fields));
list($revision, $changedColumns) = $page->updateWithHistory($fields, $data);
$changedColumns += call_user_func_array([$page->module_handler, 'edit'], [&$page, $request, $revision]);
$changedColumns += $page->uploadRelatedFiles($request, $revision);
if ($changedColumns > 0) // fire event with
{
Event::fire(new EditContentEvent($page, $revision));
}
return [$page, $revision, $changedColumns];
}
public function getValidationRules($parameters)
{
$id = $parameters[0]->id;
// get all available statuses
$statuses = ContentStatuses::getSimple();
$statuses = implode(',', $statuses);
return [
'title' => 'required',
'url' => 'required|unique:contents,url,' . $id,
'publishedFrom' => 'date',
'publishedTo' => 'date',
'title_photo' => 'exists:files,id',
'status' => 'required|in:' . $statuses,
'parentPage' => 'exists:contents,id'
];
}
}
@@ -0,0 +1,67 @@
<?php
namespace App\Cms\Interactions\Admin\Content;
use App\CMS\Contracts\Interaction;
use App\CMS\Helpers\CurrentTemplate;
use App\Http\Requests\Request;
use App\Models\Content\Content;
use Illuminate\Support\Str;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class NewContent implements Interaction
{
public function handle(Request $request, $parameters)
{
// create new page
$page = new Content();
$page->template = $request->template;
// setup basic info
$page->user_id = \Auth::user()->id;
$page->language = LaravelLocalization::getCurrentLocale();
$page->title = $request->title;
$page->url = Str::slug($request->url);
$page->published_from = empty($request->publishedFrom) ? null : $request->publishedFrom;
$page->published_to = empty($request->publishedTo) ? null : $request->publishedTo;
$page->meta_keywords = $request->metaKeywords;
$page->meta_description = $request->metaDescription;
$page->content = $request->pageContent;
$page->status = $request->status;
$page->module_handler = $request->handler;
$page->category_id = (int)$request->category > 0 ? $request->category : null;
$page->parent_id = $request->parentPage ? $request->parentPage : null;
// upload file - if provided
$file = $page->uploadTitlePhoto($request);
$page->title_photo = $file ? $file['filename'] : null;
// save module-specific stuff
call_user_func_array([$request->handler, 'createNew'], [&$page, $request]);
// let template to modify request and content page
call_user_func_array([CurrentTemplate::handler(), 'beforeSave'], [&$page, $request]);
// save content of page before (possible) uploading related files
$page->save();
// upload files assigned to content page
$page->uploadRelatedFiles($request);
return $page;
}
public function getValidationRules($parameters)
{
return [
'titlePhoto' => 'image',
'title' => 'required',
'url' => 'required|unique:contents,url',
'status' => 'required|in:draft,protected,public',
'title_photo' => 'exists:files,id',
'parentPage' => 'exists:contents,id',
'publishedFrom' => 'date',
'publishedTo' => 'date',
];
}
}
+16 -8
View File
@@ -2,13 +2,14 @@
namespace App\Exceptions;
use App\CMS\Exceptions\Validation\ValidationFailedException;
use Exception;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
class Handler extends ExceptionHandler
{
@@ -29,7 +30,8 @@ class Handler extends ExceptionHandler
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @param \Exception $e
*
* @return void
*/
public function report(Exception $e)
@@ -40,15 +42,21 @@ class Handler extends ExceptionHandler
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
* @param \Illuminate\Http\Request $request
* @param \Exception $e
*
* @return mixed
*/
public function render($request, Exception $e)
{
if ($e instanceof TokenMismatchException){
if ($e instanceof TokenMismatchException) {
//redirect to form an example of how I handle mine
return redirect($request->fullUrl())->with('error', trans('validation.csrf'));
} elseif ($e instanceof ValidationFailedException) {
return redirect()
->back()
->withInput()
->withErrors($e->getValidator());
}
return parent::render($request, $e);
@@ -2,17 +2,17 @@
namespace App\Http\Controllers\Admin\Contents;
use App\CMS\Enumerations\ContentStatuses;
use App\Cms\Handlers\Interactions\Interaction;
use App\Cms\Interactions\Admin\Content\NewContent;
use App\Events\CreateNewContent as CreateNewContentEvent;
use App\CMS\Helpers\CurrentTemplate;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\CreateNewContentRequest;
use App\Http\Requests\Request;
use App\Models\Content\Content;
use App\Models\FileManager\File;
use App\Models\Module;
use App\Models\Templates\Template;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Categories\Entities\Category;
use Pingpong\Modules\Facades\Module as ModuleInstance;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -110,7 +110,7 @@ class CreateNewContent extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postNew(CreateNewContentRequest $request, $moduleId)
public function postNew(Request $request, $moduleId)
{
try {
$module = Module::findOrFail($moduleId);
@@ -121,48 +121,10 @@ class CreateNewContent extends Controller
->with('error', trans('admin/contents.invalidModule'));
}
$request->handler = $module->handler;
// create new page
$page = new Content();
$page->template = $request->template;
// setup basic info
$page->user_id = \Auth::user()->id;
$page->language = LaravelLocalization::getCurrentLocale();
$page->title = $request->title;
$page->url = Str::slug($request->url);
$page->published_from = empty($request->publishedFrom) ? null : $request->publishedFrom;
$page->published_to = empty($request->publishedTo) ? null : $request->publishedTo;
$page->meta_keywords = $request->metaKeywords;
$page->meta_description = $request->metaDescription;
$page->content = $request->pageContent;
$page->status = $request->status;
$page->module_handler = $module->handler;
$page->category_id = (int)$request->category > 0 ? $request->category : null;
// is any parent page specified?
if ($request->parentPage) {
$page->parent_id = $request->parentPage;
}
// upload file - if provided
$file = $page->uploadTitlePhoto($request);
$page->title_photo = $file ? $file['filename'] : null;
// save module-specific stuff
call_user_func_array([$module->handler, 'createNew'], [&$page, $request]);
// let template to modify request and content page
call_user_func_array([CurrentTemplate::handler(), 'beforeSave'], [&$page, $request]);
// save content of page before (possible) uploading related files
$page->save();
// upload files assigned to content page
$page->uploadRelatedFiles($request);
// fire event about creating new content page
Event::fire(new CreateNewContentEvent($page));
Interaction::handle($request, new NewContent());
return redirect()
->route('content.overview')
@@ -2,13 +2,14 @@
namespace App\Http\Controllers\Admin\Contents;
use App\CMS\Enumerations\ContentStatuses;
use App\Cms\Handlers\Interactions\Interaction;
use App\CMS\Helpers\CurrentTemplate;
use App\Cms\Interactions\Admin\Content\EditContent as EditContentInteraction;
use App\Events\AttemptToEditInvalidContent;
use App\Events\DeleteContent;
use App\Events\EditContent as EditContentEvent;
use App\Events\MakeDraftFromContent;
use App\Events\PublishContent;
use App\Events\SetHomepage;
use App\CMS\Helpers\CurrentTemplate;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\EditContentRequest;
use App\Http\Requests\Request;
@@ -18,7 +19,6 @@ use App\Models\FileManager\File;
use App\Models\Module;
use App\Models\Templates\Template;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Modules\Categories\Entities\Category;
use Pingpong\Modules\Facades\Module as ModuleInstance;
@@ -120,7 +120,7 @@ class EditContent extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postEdit(EditContentRequest $request, $id)
public function postEdit(Request $request, $id)
{
try {
/**
@@ -138,47 +138,8 @@ class EditContent extends Controller
->with('error', trans('admin/contents.invalidPage'));
}
// upload file - if provided
$file = $page->uploadTitlePhoto($request);
// let template to modify request and content page
call_user_func_array([CurrentTemplate::handler(), 'beforeSave'], [&$page, $request]);
$request->url = Str::slug($request->url);
$request->parentPage = $request->parentPage ? $request->parentPage : null;
$request->publishedFrom = empty($request->publishedFrom) ? null : $request->publishedFrom;
$request->publishedTo = empty($request->publishedTo) ? null : $request->publishedTo;
if (!$file) {
$request->titlePhotoFilename = empty($request->existingTitlePhoto) ? null : $request->existingTitlePhoto;
} else {
$request->titlePhotoFilename = $file['filename'];
}
// array of fields in database and fields from request
$fields = [
'title' => 'title',
'url' => 'url',
'template' => 'template',
'published_from' => 'publishedFrom',
'published_to' => 'publishedTo',
'meta_keywords' => 'metaKeywords',
'meta_description' => 'metaDescription',
'content' => 'pageContent',
'parent_id' => 'parentPage',
'status' => 'status',
'title_photo' => 'titlePhotoFilename',
'category_id' => 'category'
];
// save new values with history
$data = self::getFields($request, array_values($fields));
list($revision, $changedColumns) = $page->updateWithHistory($fields, $data);
$changedColumns += call_user_func_array([$page->module_handler, 'edit'], [&$page, $request, $revision]);
$changedColumns += $page->uploadRelatedFiles($request, $revision);
// edit page
list($page, $revision, $changedColumns) = Interaction::handle($request, new EditContentInteraction(), $page);
// was something changed?
if ($changedColumns == 0) {
@@ -187,9 +148,6 @@ class EditContent extends Controller
->with('error', trans('admin/contents.nothingToEdit'));
}
// fire event with
Event::fire(new EditContentEvent($page, $revision));
// something was changed, inform user
return redirect()
->route('content.overview')
@@ -272,7 +230,7 @@ class EditContent extends Controller
// change url to something unique
$oldURL = $page->url;
$page->url .= uniqid('deleted_');
$page->url .= uniqid('_deleted_');
$page->save();
// delete page
+5 -10
View File
@@ -2,6 +2,8 @@
namespace App\Http\Requests;
use App\Cms\Interactions\Admin\Content\NewContent;
class CreateNewContentRequest extends Request
{
/**
@@ -11,15 +13,8 @@ class CreateNewContentRequest extends Request
*/
public function rules()
{
return [
'titlePhoto' => 'image',
'title' => 'required',
'url' => 'required|unique:contents,url',
'status' => 'required|in:draft,protected,public',
'title_photo' => 'exists:files,id',
'parentPage' => 'exists:contents,id',
'publishedFrom' => 'date',
'publishedTo' => 'date',
];
$validator = new NewContent();
return $validator->getValidationRules();
}
}
+1 -13
View File
@@ -13,18 +13,6 @@ class EditContentRequest extends Request
*/
public function rules()
{
// get all available statuses
$statuses = ContentStatuses::getSimple();
$statuses = implode(',', $statuses);
return [
'title' => 'required',
'url' => 'required|unique:contents,url,' . $this->id,
'publishedFrom' => 'date',
'publishedTo' => 'date',
'title_photo' => 'exists:files,id',
'status' => 'required|in:' . $statuses,
'parentPage' => 'exists:contents,id'
];
return [];
}
}
+19
View File
@@ -2,6 +2,8 @@
namespace App\Models\Content;
use App\Events\CreateNewContent;
use App\Events\Event;
use App\Models\FileManager\File;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
@@ -108,8 +110,25 @@ class Content extends Model
return $this->belongsToMany(File::class, 'contents_has_files');
}
/**
* Category of content page
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function category()
{
return $this->belongsTo(Category::class);
}
public function save(array $options = [])
{
$saved = parent::save($options);
// fire event about creating new content page
if ($this->wasRecentlyCreated) {
Event::fire(new CreateNewContent($this));
}
return $saved;
}
}
+3 -3
View File
@@ -3,6 +3,8 @@ namespace App\Models\Content\ModelTraits;
use App\CMS\Enumerations\ContentStatuses;
use App\Http\Requests\Request;
use App\Models\Content\ContentHasFile;
use App\Models\Content\ContentHistory;
use App\Models\FileManager\Directory;
use App\Models\FileManager\File;
use Carbon\Carbon;
@@ -352,9 +354,7 @@ trait Content {
public function view()
{
$this->timestamps = false;
$this->viewed++;
$this->save();
$this->timestamps = true;
$this->save(['timestamps' => false]);
}
}
-13
View File
@@ -11,15 +11,10 @@ use App\CMS\Handlers\Search\Content;
use App\CMS\Handlers\Search\Files;
use App\CMS\Handlers\Search\Presenters\AdminContent as AdminContentPresenter;
use App\CMS\Handlers\Search\Presenters\AdminFiles;
use App\Models\Templates\Template;
use App\CMS\Widgets\HtmlCode\HtmlCode;
use App\CMS\Widgets\Menu\Menu;
use App\CMS\Widgets\OrbitSlider\OrbitSlider;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\Process\Exception\InvalidArgumentException;
class AppServiceProvider extends ServiceProvider
{
@@ -65,10 +60,6 @@ class AppServiceProvider extends ServiceProvider
return new WidgetRegistrator($app);
});
$this->app->singleton('registerMenuExtension', function ($app) {
return new MenuExtensionRegistrator($app);
});
// create registrator for template directories
$this->app->singleton('registerTemplateDir', function ($app) {
return new TemplateRegistrator($app);
@@ -96,7 +87,6 @@ class AppServiceProvider extends ServiceProvider
// register all available widgets
$registrator->register(HtmlCode::class);
$registrator->register(Menu::class);
// $registrator->register(OrbitSlider::class);
}
/**
@@ -109,7 +99,6 @@ class AppServiceProvider extends ServiceProvider
$registrator->register('basic', 'admin/settings.basic', 'admin.settings.parts.basic');
$registrator->register('meta', 'admin/settings.meta', 'admin.settings.parts.meta');
$registrator->register('social', 'admin/settings.socialSites', 'admin.settings.parts.social');
}
/**
@@ -122,6 +111,4 @@ class AppServiceProvider extends ServiceProvider
$registrator->register(new Content(), new AdminContentPresenter(), SearchEngineRegistrator::ADMIN);
$registrator->register(new Files(), new AdminFiles(), SearchEngineRegistrator::ADMIN);
}
}