diff --git a/app/CMS/Contracts/Content/AdvancedContentModifier.php b/app/CMS/Contracts/Content/AdvancedContentModifier.php index eef8c9d7..a8b43da1 100644 --- a/app/CMS/Contracts/Content/AdvancedContentModifier.php +++ b/app/CMS/Contracts/Content/AdvancedContentModifier.php @@ -21,12 +21,11 @@ interface AdvancedContentModifier { * Reason why it is separated from createNew() method is simple - we need to save history of changes. * * @param Content $content - * @param Request $request - * @param string $revisionId + * @param $request * * @return mixed */ - public static function edit(Content &$content, Request $request, $revisionId); + public static function edit(Content $content, $request); /** * Method called right after content page is marked as deleted * diff --git a/app/CMS/Contracts/Interaction.php b/app/CMS/Contracts/Interaction.php index 6ae65a66..f4bb27c6 100644 --- a/app/CMS/Contracts/Interaction.php +++ b/app/CMS/Contracts/Interaction.php @@ -1,9 +1,21 @@ $statuses[$changeset->new_value] ]); break; - case 'is_homepage': + case 'isHomepage': return trans('admin/history.setupAsHomepage'); break; default: diff --git a/app/CMS/Handlers/Interaction.php b/app/CMS/Handlers/Interaction.php index d2f08439..25b0fb35 100644 --- a/app/CMS/Handlers/Interaction.php +++ b/app/CMS/Handlers/Interaction.php @@ -3,30 +3,37 @@ 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\App; use Illuminate\Support\Facades\Validator; -class Interaction { +class Interaction +{ /** * Handle interaction with application * - * @param Request $request - * @param InteractionContract $interaction - * @param array $parameters + * @param string $interactionClass + * @param array $data + * @param array $extraParameters * * @return mixed * @throws ValidationFailedException */ - public static function handle(Request $request, InteractionContract $interaction, ...$parameters) { + public static function handle($interactionClass, $data, ...$extraParameters) + { + /** + * @var $interaction InteractionContract + */ + $interaction = App::make($interactionClass); // validate interaction - $validator = Validator::make($request->all(), $interaction->getValidationRules($parameters)); + $validator = Validator::make($data, $interaction->getValidationRules($extraParameters)); if ($validator->fails()) { throw new ValidationFailedException($validator); } // handle it - return $interaction->handle($request, $parameters); + + return $interaction->handle($data, $extraParameters); } } \ No newline at end of file diff --git a/app/CMS/Helpers/CurrentTemplate.php b/app/CMS/Helpers/CurrentTemplate.php index a9670900..68b8fec0 100644 --- a/app/CMS/Helpers/CurrentTemplate.php +++ b/app/CMS/Helpers/CurrentTemplate.php @@ -1,12 +1,13 @@ where('enabled', true) - ->first(); + self::$template = Module::where('is_template', true) + ->where('enabled', true) + ->first(); } catch (QueryException $e) { throw new \ErrorException('DB not migrated, please, do so!'); } if (self::$template) { - self::$template->module_settings = json_decode(self::$template->module_settings); + self::$template->moduleSettings = json_decode(self::$template->moduleSettings); } self::$initialized = true; @@ -60,4 +61,68 @@ class CurrentTemplate { self::$initialized = false; } + + /** + * Register admin menu (or multiple ones) + * + * This cannot be in ServiceProvider because Session is started at middleware. And ServiceProvider is called before + * starting any middleware.. + * + * @param User $user model of logged user + */ + public static function registerAdminMenu(User $user) + { + call_user_func_array([self::handler(), 'registerAdminMenu'], [$user]); + } + + /** + * Get list of registered templates and supported modules. + * + * Returned array is expected to be array of arrays with following items: module, namespace and templateName. + * Example: + * return [ + * ['module' => 'Article', 'templateName' => 'article::template.name'] + * ]; + * + * When no "namespace" is specified, value strtolower(module) is used instaed. + * + * @return array + */ + public static function getPublicTemplatePaths() + { + return call_user_func([self::handler(), 'getPublicTemplatePaths']); + } + + /** + * Prepare Content object to be rendered using Blade template + * + * @param Content $content + */ + public static function beforeRender(Content & $content) + { + call_user_func_array([self::handler(), 'beforeRender'], [&$content]); + } + + /** + * Modify input data into format which can be understood by edit template + * + * @param Content $content + */ + public static function beforePopulatingEditForm(Content & $content) + { + call_user_func_array([self::handler(), 'beforePopulatingEditForm'], [&$content]); + } + + /** + * Slightly modify Content object before saving into database. + * + * This way we can do almost whatever we want - even in template + * + * @param Content $content + * @param $request + */ + public static function beforeSave(Content & $content, $request) + { + call_user_func_array([self::handler(), 'beforeSave'], [&$content, $request]); + } } \ No newline at end of file diff --git a/app/CMS/Helpers/PageRenderer.php b/app/CMS/Helpers/PageRenderer.php index a9b0702a..63ccd665 100644 --- a/app/CMS/Helpers/PageRenderer.php +++ b/app/CMS/Helpers/PageRenderer.php @@ -24,7 +24,7 @@ class PageRenderer public static function render(Content $page) { // decode module settings - $page->module_settings = json_decode($page->module_settings); + $page->moduleSettings = json_decode($page->moduleSettings); // do something template-specific $parameters = call_user_func_array([CurrentTemplate::handler(), 'beforeRender'], [&$page]); @@ -33,7 +33,7 @@ class PageRenderer * @var $handler AppHandler */ // get handler - $handler = new $page->module_handler; + $handler = new $page->moduleHandler; $page->content = Shortcode::compile($page->content); diff --git a/app/CMS/Helpers/Traits/Nullable.php b/app/CMS/Helpers/Traits/Nullable.php new file mode 100644 index 00000000..7221d013 --- /dev/null +++ b/app/CMS/Helpers/Traits/Nullable.php @@ -0,0 +1,33 @@ +toDateTimeString(); + } + + /** + * Get null or input value + * + * @param $string + * + * @return null + */ + public function nullable($string) { + return empty($string) ? null : $string; + } +} \ No newline at end of file diff --git a/app/CMS/Helpers/functions.php b/app/CMS/Helpers/functions.php index c7b4002e..e758d6f7 100644 --- a/app/CMS/Helpers/functions.php +++ b/app/CMS/Helpers/functions.php @@ -27,4 +27,8 @@ function setting($key, $default = null) { function asset_path($path) { return env('SITE_URL').'/assets/'.$path; +} + +function template_name($name, $throwExceptions = true) { + return \App\CMS\Helpers\Template::name($name, $throwExceptions); } \ No newline at end of file diff --git a/app/CMS/Interactions/Admin/Content/ChangeStatus.php b/app/CMS/Interactions/Admin/Content/ChangeStatus.php index e69de29b..07386aa4 100644 --- a/app/CMS/Interactions/Admin/Content/ChangeStatus.php +++ b/app/CMS/Interactions/Admin/Content/ChangeStatus.php @@ -0,0 +1,24 @@ +route('content.overview') + ->with('error', trans('admin/contents.invalidStatus')); + } + } + + public function getValidationRules($parameters) + { + // TODO: Implement getValidationRules() method. + } +} \ No newline at end of file diff --git a/app/CMS/Interactions/Admin/Content/EditContent.php b/app/CMS/Interactions/Admin/Content/EditContent.php index dbe34624..897d3098 100644 --- a/app/CMS/Interactions/Admin/Content/EditContent.php +++ b/app/CMS/Interactions/Admin/Content/EditContent.php @@ -7,6 +7,8 @@ use App\CMS\Enumerations\ContentStatuses; use App\CMS\Helpers\CurrentTemplate; use App\Events\EditContent as EditContentEvent; use App\Http\Requests\Request; +use App\Models\Content\Content; +use App\Models\FileManager\File; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; @@ -17,74 +19,59 @@ class EditContent implements Interaction * @var Module */ protected $module; + /** + * @var File + */ + protected $file; + public function __construct() { $this->module = App::make(Module::class); + $this->file = App::make(File::class); } - public function handle(Request $request, $parameters) + /** + * Edit page + * + * @param array $data + * @param array $parameters + * + * @return mixed|void + */ + public function handle($data, $parameters) { - $page = $parameters[0]; - - // upload file - if provided - // todo use interaction - $file = $page->uploadTitlePhoto($request); + /** + * @var $page Content + */ + list($page, $titlePhoto, $relatedFiles) = $parameters; // let template to modify request and content page - call_user_func_array([CurrentTemplate::handler(), 'beforeSave'], [&$page, $request]); + CurrentTemplate::beforeSave($page, $data); - $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; + // upload file - if provided + $data['titlePhoto'] = isset($data['existingTitlePhoto']) ? $data['existingTitlePhoto'] : null; - if (!$file) { - $request->titlePhotoFilename = empty($request->existingTitlePhoto) ? null : $request->existingTitlePhoto; - } else { - $request->titlePhotoFilename = $file['filename']; + if (!is_null($titlePhoto)) { + $file = $this->file->upload($titlePhoto); + $data['titlePhoto'] = $file ? $file['filename'] : null; } - // 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)); - - // todo use Model Observer and model::original attributes - - list($revision, $changedColumns) = $page->updateWithHistory($fields, $data); - - $module = $this->module->getByHandler($page->module_handler); - - - $changedColumns += $this->module->call($module, 'edit', [&$page, $request, $revision]); - + $page->update($data); + $this->module->callOnString($page->moduleHandler, 'edit', [$page, $data]); // move to interaction - $changedColumns += $page->uploadRelatedFiles($request, $revision); - - if ($changedColumns > 0) { - Event::fire(new EditContentEvent($page, $revision)); - } - - return [$page, $revision, $changedColumns]; + $keepAssigned = isset($data->keepAssigned) ? $data->keepAssigned : []; + $page->uploadRelatedFiles($relatedFiles, $keepAssigned); } - public function getValidationRules($parameters) + /** + * Validate this interaction + * + * @param array $parameters + * + * @return array + */ + public function getValidationRules($parameters = []) { $id = $parameters[0]->id; @@ -97,7 +84,7 @@ class EditContent implements Interaction 'url' => 'required|unique:contents,url,' . $id, 'publishedFrom' => 'date', 'publishedTo' => 'date', - 'title_photo' => 'exists:files,id', + 'titlePhoto' => 'exists:files,id', 'status' => 'required|in:' . $statuses, 'parentPage' => 'exists:contents,id' ]; diff --git a/app/CMS/Interactions/Admin/Content/NewContent.php b/app/CMS/Interactions/Admin/Content/NewContent.php index 3e8a25f6..14713e0c 100644 --- a/app/CMS/Interactions/Admin/Content/NewContent.php +++ b/app/CMS/Interactions/Admin/Content/NewContent.php @@ -2,10 +2,13 @@ namespace App\Cms\Interactions\Admin\Content; use App\CMS\Contracts\Interaction; +use App\CMS\Contracts\Repositories\Content as ContentRepository; +use App\CMS\Contracts\Repositories\Module; use App\CMS\Helpers\CurrentTemplate; use App\Events\CreateNewContent; -use App\Http\Requests\Request; use App\Models\Content\Content; +use App\Models\FileManager\File; +use Carbon\Carbon; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; @@ -13,73 +16,70 @@ use Mcamara\LaravelLocalization\Facades\LaravelLocalization; class NewContent implements Interaction { + /** + * @var ContentRepository + */ protected $content; + /** + * @var File + */ + protected $file; + /** + * @var Module + */ + protected $module; public function __construct() { - $this->content = App::make(\App\CMS\Contracts\Repositories\Content::class); + $this->content = App::make(ContentRepository::class); + $this->module = App::make(Module::class); + $this->file = App::make(File::class); } /** - * @param Request $request + * Create new content page + * + * @param array $data * @param $parameters * * @return Content */ - public function handle(Request $request, $parameters) + public function handle($data, $parameters) { - list($moduleHandler) = $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 = $moduleHandler; - $page->category_id = (int)$request->category > 0 ? $request->category : null; - $page->parent_id = $request->parentPage ? $request->parentPage : null; + list($moduleHandler, $titlePhoto, $relatedFiles) = $parameters; // upload file - if provided - $file = $page->uploadTitlePhoto($request); + $file = !is_null($titlePhoto) ? $this->file->upload($titlePhoto) : null; - $page->title_photo = $file ? $file['filename'] : null; + $data['userId'] = \Auth::user()->id; + $data['language'] = LaravelLocalization::getCurrentLocale(); + $data['titlePhoto'] = $file ? $file['filename'] : null; + $data['moduleHandler'] = $moduleHandler; + + $page = Content::create($data); // save module-specific stuff - call_user_func_array([$request->handler, 'createNew'], [&$page, $request]); + $this->module->callOnString($moduleHandler, 'createNew', [&$page, $data]); - // let template to modify request and content page - call_user_func_array([CurrentTemplate::handler(), 'beforeSave'], [&$page, $request]); + // let template to modify data and content page + CurrentTemplate::beforeSave($page, $data); // save content of page before (possible) uploading related files $page->save(); // upload files assigned to content page - $page->uploadRelatedFiles($request); - - Event::fire(new CreateNewContent($this)); - + $page->uploadRelatedFiles($relatedFiles); return $page; } - public function getValidationRules($parameters) + 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', diff --git a/app/CMS/Observers/Content.php b/app/CMS/Observers/Content.php new file mode 100644 index 00000000..a44a88be --- /dev/null +++ b/app/CMS/Observers/Content.php @@ -0,0 +1,102 @@ +changeset = uniqid(); + } + + /** + * @param ContentModel $content + */ + public function created(ContentModel $content) + { + Event::fire(new CreateNewContent($content)); + } + + /** + * Get all dirty changed from model. + * + * If user did not change moduleSettings column, return result from ContentModel::getDirty(). Otherwise append all + * changed columns from module settings. + * + * @param $changed + * @param $original + * + * @return array + */ + protected function getDirtyFields($changed, $original) + { + unset($changed['updated_at']); + + $changes = $this->getNewAndOldValues(array_keys($changed), $changed, $original); + + if (!isset($changed['moduleSettings'])) + return $changes; + + $moduleSettings = (array)json_decode($changed['moduleSettings']); + $originalSettings = (array)json_decode($original['moduleSettings']); + unset($changed['moduleSettings']); + + $settingChanged = array_keys(array_diff_assoc($moduleSettings, $originalSettings)); + $changesInSettings = $this->getNewAndOldValues($settingChanged, $moduleSettings, $originalSettings); + + return array_merge($changes, $changesInSettings); + } + + /** + * + * + * @param $fields + * @param $new + * @param $original + * + * @return array + */ + protected function getNewAndOldValues($fields, $new, $original) { + $changes = []; + foreach ($fields as $field) { + $changes[$field] = [ + 'new' => isset($new[$field]) ? $new[$field] : null, + 'old' => isset($original[$field])? $original[$field] : null + ]; + } + + return $changes; + } + + public function updated(ContentModel $content) + { + $fields = $this->getDirtyFields($content->getDirty(), $content->getOriginal()); + + foreach ($fields as $field => $change) { + $history = [ + 'user_id' => \Auth::user()->id, + 'content_id' => $content->id, + 'edit_batch' => $this->changeset, + 'column' => $field, + 'old_value' => $change['old'], + 'new_value' => $change['new'] + ]; + + // save history + ContentHistory::create($history); + } + } + + /** + * @param ContentModel $content + */ + public function deleted(ContentModel $content) + { + } +} \ No newline at end of file diff --git a/app/CMS/Repositories/Content/Content.php b/app/CMS/Repositories/Content/Content.php index 4270c21f..b810d397 100644 --- a/app/CMS/Repositories/Content/Content.php +++ b/app/CMS/Repositories/Content/Content.php @@ -29,14 +29,14 @@ class Content extends Repository implements IContent return ContentModel::where('status', '!=', IContent::STATUS_DRAFT) ->select('contents.*') ->with('author') - ->join('modules', 'modules.handler', '=', 'contents.module_handler') + ->join('modules', 'modules.handler', '=', 'contents.moduleHandler') ->where(function ($query) { - $query->where('published_from', '<', Carbon::now()) - ->orWhereNull('published_from'); + $query->where('publishedFrom', '<=', Carbon::now()) + ->orWhereNull('publishedFrom'); }) ->where(function ($query) { - $query->where('published_to', '>', Carbon::now()) - ->orWhereNull('published_to'); + $query->where('publishedTo', '>=', Carbon::now()) + ->orWhereNull('publishedTo'); }) ->where('language', LaravelLocalization::getCurrentLocale()) ->whereNull('contents.deleted_at') @@ -46,9 +46,14 @@ class Content extends Repository implements IContent public function all() { return $this->getPageQuery() - ->get(); + ->get(); } + /** + * @param int $id + * + * @return mixed + */ public function getOne($id = null) { if (is_null($id)) { @@ -56,16 +61,9 @@ class Content extends Repository implements IContent $page->user_id = \Auth::user()->id; $page->language = LaravelLocalization::getCurrentLocale(); $page->status = IContent::STATUS_DRAFT; - $page->module_settings = []; + $page->moduleSettings = []; } else { - if (is_numeric($id)) { $page = $this->model->findOrFail($id); - } else { - $page = $this->model->where('language', LaravelLocalization::getCurrentLocale()) - ->where('url', $id) - ->firstOrFail(); - } - $page->module_settings = json_decode($page->module_settings); } return $page; @@ -78,8 +76,9 @@ class Content extends Repository implements IContent public function getHomepage() { return $this->getPageQuery() - ->where('is_homepage', 1) - ->first(); + ->where('isHomepage', 1) + ->first(); + } /** @@ -91,9 +90,17 @@ class Content extends Repository implements IContent */ public function getByURL($url) { - return $this->getPageQuery() - ->where('url', $url) - ->first(); + $page = $this->getPageQuery() + ->where('url', $url) + ->first(); + + if (is_null($page)) { + return null; + } + + $page->moduleSettings = json_decode($page->moduleSettings); + + return $page; } /** @@ -108,8 +115,8 @@ class Content extends Repository implements IContent public function getOverview($handler = null, $statuses = null) { $query = ContentModel::select('contents.*', 'modules.name AS module_name', 'modules.id AS module_id') - ->join('modules', 'modules.handler', '=', 'contents.module_handler') - ->join('users', 'users.id', '=', 'contents.user_id') + ->join('modules', 'modules.handler', '=', 'contents.moduleHandler') + ->join('users', 'users.id', '=', 'contents.userId') ->addSelect(DB::raw('COALESCE(users.name, users.email) AS author_name')) ->addSelect('users.email AS author_email') ->whereNull('contents.deleted_at') @@ -119,7 +126,7 @@ class Content extends Repository implements IContent // filter results using handler if (!is_null($handler)) { - $query = $query->where('contents.module_handler', $handler); + $query = $query->where('contents.moduleHandler', $handler); } // add filtering by status @@ -127,6 +134,8 @@ class Content extends Repository implements IContent $query = $query->whereIn('contents.status', $statuses); } - return $query->paginate(20); + $pages = $query->paginate(setting('paginatedResults', 20)); + + return $pages; } } \ No newline at end of file diff --git a/app/CMS/Repositories/Module.php b/app/CMS/Repositories/Module.php index ac82725f..b8320d39 100644 --- a/app/CMS/Repositories/Module.php +++ b/app/CMS/Repositories/Module.php @@ -36,8 +36,8 @@ class Module extends Repository implements IModule public function getUpdateContentTitle(ModuleModel $module, Content $content = null) { - $pageHeading = trans('admin/contents.new', ['name' => trans($module->name)]); - $moduleHeading = $this->call($module, 'getEditTitle', $content); + $pageHeading = trans('admin/contents.edit', ['name' => trans($module->name)]); + $moduleHeading = $this->call($module, 'getEditTitle', [$content]); return is_null($moduleHeading) ? $pageHeading : $moduleHeading; } @@ -62,7 +62,7 @@ class Module extends Repository implements IModule ->firstOrFail(); } - public function call(ModuleModel $module, $method, ...$parameters) + public function call(ModuleModel $module, $method, $parameters = []) { if (!is_null($module) && is_callable([$module->handler, $method])) { return call_user_func_array([$module->handler, $method], $parameters); @@ -70,4 +70,13 @@ class Module extends Repository implements IModule return null; } + + public function callOnString($moduleHandler, $method, $parameters = []) + { + if (is_callable([$moduleHandler, $method])) { + return call_user_func_array([$moduleHandler, $method], $parameters); + } + + return null; + } } \ No newline at end of file diff --git a/app/CMS/Widgets/Menu/Presenters/Menu.php b/app/CMS/Widgets/Menu/Presenters/Menu.php index b10e8858..567848b0 100644 --- a/app/CMS/Widgets/Menu/Presenters/Menu.php +++ b/app/CMS/Widgets/Menu/Presenters/Menu.php @@ -54,8 +54,8 @@ class Menu implements WidgetRenderer } $page = $pages[$pageId]; - $active = ($page->is_homepage && $route == 'page.index') || ($route == 'page.content' && isset($parameters['url']) && $parameters['url'] == $page->url); - $route = $page->is_homepage ? route('page.index') : route('page.content', ['url' => $page->url]); + $active = ($page->isHomepage && $route == 'page.index') || ($route == 'page.content' && isset($parameters['url']) && $parameters['url'] == $page->url); + $route = $page->isHomepage ? route('page.index') : route('page.content', ['url' => $page->url]); $code .= 'module_settings); + $info = json_decode($current->moduleSettings); $this->line('Template is already installed. Currently using template ' . trans($current->name) . ' located in /templates/' . $info->staticName . '.'); $confirm = $this->confirm('Uninstall it and install *' . trans($config['name']) . '*? All data associated with installed template will be lost!'); diff --git a/app/Http/Controllers/Admin/Contents/ContentActions.php b/app/Http/Controllers/Admin/Contents/ContentActions.php index be6e6bc4..7fdd4773 100644 --- a/app/Http/Controllers/Admin/Contents/ContentActions.php +++ b/app/Http/Controllers/Admin/Contents/ContentActions.php @@ -36,18 +36,17 @@ class ContentActions extends Controller ->with('error', trans('admin/contents.invalidStatus')); } - try { // try to find this page $page = Content::findOrFail($id); - } catch (NotFoundHttpException $e) { - // page not found - return redirect() - ->route('content.overview') - ->with('error', trans('admin/contents.invalidPage')); - } // try to change the page list ($revision, $changedColumns) = $page->updateWithHistory(['status' => 'status'], ['status' => $status]); + // fire events + if ($status != Content::STATUS_DRAFT) { + Event::fire(new PublishContent($page, $revision)); + } else { + Event::fire(new MakeDraftFromContent($page, $revision)); + } // was something changed? if ($changedColumns == 0) { @@ -56,12 +55,7 @@ class ContentActions extends Controller ->with('error', trans('admin/contents.nothingToEdit')); } - // fire events - if ($status != Content::STATUS_DRAFT) { - Event::fire(new PublishContent($page, $revision)); - } else { - Event::fire(new MakeDraftFromContent($page, $revision)); - } + // redirect back to overview with info for user return redirect() @@ -97,7 +91,7 @@ class ContentActions extends Controller $page->delete(); // let module to delete some extra content created during page's life - call_user_func([$page->module_handler, 'delete'], $page); + call_user_func([$page->moduleHandler, 'delete'], $page); // trigger delete event Event::fire(new DeleteContent($page)); @@ -134,12 +128,12 @@ class ContentActions extends Controller } // disable any other existing homepage - Content::where('is_homepage', 1) + Content::where('isHomepage', 1) ->where('language', LaravelLocalization::getCurrentLocale()) - ->update(['is_homepage' => 0]); + ->update(['isHomepage' => 0]); // set new homepage - list ($revision, $changedColumns) = $page->updateWithHistory(['is_homepage' => 'is_homepage'], ['is_homepage' => 1]); + list ($revision, $changedColumns) = $page->updateWithHistory(['isHomepage' => 'isHomepage'], ['isHomepage' => 1]); // was something changed? if ($changedColumns == 0) { diff --git a/app/Http/Controllers/Admin/Contents/CreateNewContent.php b/app/Http/Controllers/Admin/Contents/CreateNewContent.php index d9e6fb02..6abe97e5 100644 --- a/app/Http/Controllers/Admin/Contents/CreateNewContent.php +++ b/app/Http/Controllers/Admin/Contents/CreateNewContent.php @@ -103,8 +103,11 @@ class CreateNewContent extends Controller { $module = $this->module->getOne($moduleId); + $titlePhoto = $request->file('titlePhoto'); + $relatedFiles = $request->all()['files']; + // create new page - Interaction::handle($request, new NewContent(), $module->handler); + Interaction::handle(NewContent::class, $request->all(), $module->handler, $titlePhoto, $relatedFiles); return redirect() ->route('content.overview') diff --git a/app/Http/Controllers/Admin/Contents/EditContent.php b/app/Http/Controllers/Admin/Contents/EditContent.php index 952ed303..fe760795 100644 --- a/app/Http/Controllers/Admin/Contents/EditContent.php +++ b/app/Http/Controllers/Admin/Contents/EditContent.php @@ -71,24 +71,24 @@ class EditContent extends Controller /** * Display form for editing static page * - * @param $url + * @param $id * * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ - public function edit($url) + public function edit($id) { $statuses = ContentStatuses::getWithTranslations(); - $page = $this->content->getOne($url); + $page = $this->content->getOne($id); // get module ID - $module = $this->module->getByHandler($page->module_handler); + $module = $this->module->getByHandler($page->moduleHandler); $pageHeading = $this->module->getUpdateContentTitle($module, $page); $templates = $this->template->getForModule($module); $categories = $this->category->getForModule($module); $history = $this->history->getStructuredHistoryOf($page); // modify data for edit form according to installed template - call_user_func_array([CurrentTemplate::handler(), 'beforePopulatingEditForm'], [&$page]); + CurrentTemplate::beforePopulatingEditForm($page); // render view return view('admin.content.edit', [ @@ -132,14 +132,10 @@ class EditContent extends Controller } // edit page - list($page, $revision, $changedColumns) = Interaction::handle($request, new EditContentInteraction(), $page); + $titlePhoto = $request->file('titlePhoto'); + $relatedFiles = $request->all()['files']; - // was something changed? - if ($changedColumns == 0) { - return redirect() - ->route('content.edit', ['id' => $page->id]) - ->with('error', trans('admin/contents.nothingToEdit')); - } + Interaction::handle(EditContentInteraction::class, $request->all(), $page, $titlePhoto, $relatedFiles); // something was changed, inform user return redirect() @@ -150,12 +146,12 @@ class EditContent extends Controller /** * Convert object of all request data into array of only wanted fields * - * @param Request $request + * @param $request * @param $fields * * @return array */ - public static function getFields(Request $request, $fields) + public static function getFields($request, $fields) { $requestData = []; diff --git a/app/Http/Controllers/Sitemap.php b/app/Http/Controllers/Sitemap.php index 8d42930d..fe5c4360 100644 --- a/app/Http/Controllers/Sitemap.php +++ b/app/Http/Controllers/Sitemap.php @@ -2,8 +2,8 @@ namespace App\Http\Controllers; +use App\CMS\Contracts\Repositories\Content; use App\Http\Requests; -use App\Models\Content\Content; class Sitemap extends Controller { @@ -30,14 +30,13 @@ class Sitemap extends Controller public function getMap() { // load all public pages - $pages = $this->content->getPageQuery() - ->get(); + $pages = $this->content->all(); // iterate over all pages and add tag for each of them foreach ($pages as $page) { // is this page a homepage? because of URL - if ($page->is_homepage) { + if ($page->isHomepage) { $route = route('page.index'); $priority = 1; } else { diff --git a/app/Http/routes/admin/contents.php b/app/Http/routes/admin/contents.php index 712cb998..54b70c6b 100644 --- a/app/Http/routes/admin/contents.php +++ b/app/Http/routes/admin/contents.php @@ -9,7 +9,7 @@ Route::group(['namespace' => 'Contents'], function () { ->name('content.new'); // form for editing existing static page - Route::get('content/edit/{url}', 'EditContent@edit') + Route::get('content/edit/{id}', 'EditContent@edit') ->name('content.edit'); // post method for creating new static page diff --git a/app/Models/Content/Content.php b/app/Models/Content/Content.php index 93d1e5f7..fce60e27 100644 --- a/app/Models/Content/Content.php +++ b/app/Models/Content/Content.php @@ -2,10 +2,14 @@ namespace App\Models\Content; +use App\CMS\Contracts\Repositories\Content as ContentContract; +use App\CMS\Helpers\Traits\Nullable; +use App\CMS\Observers\Content as ContentObserver; use App\Models\FileManager\File; use App\Models\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Str; use Modules\Categories\Entities\Category; /** @@ -13,27 +17,41 @@ use Modules\Categories\Entities\Category; */ class Content extends Model { - use SoftDeletes, ModelTraits\Content; + use SoftDeletes, ModelTraits\Content, Nullable; public $timestamps = true; protected $fillable = [ - 'user_id', - 'parent_id', - 'category_id', + 'userId', + 'parentId', + 'categoryId', 'language', - 'module_handler', - 'published_from', - 'published_to', - 'title_photo', + 'moduleHandler', + 'publishedFrom', + 'publishedTo', + 'titlePhoto', 'template', - 'is_homepage', + 'isHomepage', 'title', 'url', - 'meta_keywords', - 'meta_description', - 'content', - 'module_settings', + 'metaKeywords', + 'metaDescription', + 'pageContent', + 'moduleSettings', 'status' ]; + protected $casts = [ + 'isHomepage' => 'boolean', + 'moduleSettings' => 'array' + ]; + + /** + * Assign observer for this model for logging + */ + protected static function boot() + { + parent::boot(); + + self::observe(ContentObserver::class); + } /** * Mark relationship with its historical records @@ -52,7 +70,7 @@ class Content extends Model */ public function author() { - return $this->belongsTo(User::class, 'user_id'); + return $this->belongsTo(User::class, 'userId'); } /** @@ -74,4 +92,75 @@ class Content extends Model { return $this->belongsTo(Category::class); } + + /** + * Subpages assigned to page + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function subpages() + { + return $this->hasMany(Content::class, 'parentId'); + } + + /** + * Parent page + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function parentPage() + { + return $this->belongsTo(Content::class, 'parentId'); + } + + /** + * Is current content draft? + * + * @return bool + */ + public function isDraft() + { + return $this->status == ContentContract::STATUS_DRAFT; + } + + /** + * Is current content visible for all visitors? + * + * @return bool + */ + public function isPublic() + { + return $this->status == ContentContract::STATUS_PUBLIC; + } + + /** + * Is current content visible only for logged users? + * + * @return bool + */ + public function isProtected() + { + return $this->status == ContentContract::STATUS_PROTECTED; + } + + /** + * Is current content visible for logged user OR for everyone? + * + * @return bool + */ + public function isVisible() + { + return $this->isPublic() || $this->isProtected(); + } + + public function save(array $options = []) + { + $this->parentId = $this->nullable($this->parentId); + $this->categoryId = $this->nullable($this->categoryId); + $this->publishedFrom = $this->nullableDate($this->publishedFrom); + $this->publishedTo = $this->nullableDate($this->publishedTo); + $this->url = Str::slug($this->url); + + return parent::save($options); + } } diff --git a/app/Models/Content/ContentHasFile.php b/app/Models/Content/ContentHasFile.php index 688f35e1..d6fb39f6 100644 --- a/app/Models/Content/ContentHasFile.php +++ b/app/Models/Content/ContentHasFile.php @@ -2,15 +2,25 @@ namespace App\Models\Content; +use App\Models\FileManager\File; use Illuminate\Database\Eloquent\Model; class ContentHasFile extends Model { public $timestamps = false; public $table = 'contents_has_files'; - protected $fillable = [ 'content_id', 'file_id' ]; + + public function content() + { + return $this->hasOne(Content::class); + } + + public function file() + { + return $this->hasOne(File::class); + } } \ No newline at end of file diff --git a/app/Models/Content/ModelTraits/Content.php b/app/Models/Content/ModelTraits/Content.php index 16069185..ae8c210f 100644 --- a/app/Models/Content/ModelTraits/Content.php +++ b/app/Models/Content/ModelTraits/Content.php @@ -1,215 +1,29 @@ file = App::make(File::class); - } - - /** - * Is current content draft? - * - * @return bool - */ - public function isDraft() - { - return $this->status == IContent::STATUS_DRAFT; - } - - /** - * Is current content visible for all visitors? - * - * @return bool - */ - public function isPublic() - { - return $this->status == IContent::STATUS_PUBLIC; - } - - /** - * Is current content visible only for logged users? - * - * @return bool - */ - public function isProtected() - { - return $this->status == IContent::STATUS_PROTECTED; - } - - /** - * Is current content visible for logged user OR for everyone? - * - * @return bool - */ - public function isVisible() - { - return $this->isPublic() || $this->isProtected(); - } - - /** - * Get list of all subpages - * - * @param bool $orderBy - * @param bool $orderDirection - * - * @return array - */ - public function subpages($orderBy = false, $orderDirection = false) - { - if (!$this->subpagesInit) { - $subpages = $this->getPageQuery() - ->where('contents.parent_id', $this->id); - - if ($orderBy) { - $subpages->orderBy($orderBy, $orderDirection ? $orderDirection : 'ASC'); - } - - $subpages = $subpages->get(); - - // convert JSON settings into stdClass - foreach ($subpages as $i => $subpage) { - $subpages[$i]->module_settings = json_decode($subpage->module_settings); - } - - $this->subpagesInit = true; - $this->foundSubpages = $subpages; - } - - return $this->foundSubpages; - } - - /** - * Returns list of all root pages - those pages, which parent_id is null - * - * @return mixed - */ - public function rootPages() - { - $rootPages = $this->getPageQuery() - ->where('parent_id', null); - - if ($this->id) { - $rootPages = $rootPages->where('id', '!=', $this->id); - } - - return $rootPages->get(); - } - - /** - * Updates current model with information about changed columns - * - * @param array $fields - * @param array $request - * @param string $revisionId - * - * @return array revisionID and number of changed columns - */ - public function updateWithHistory(array $fields, array $request, $revisionId = null) - { - if (!$revisionId) { - $revisionId = uniqid(); - } - - $changed = 0; - - foreach ($fields as $fieldDB => $fieldRequest) { - // ignore non-existing fields - if (!isset($request[$fieldRequest]) && !is_null($request[$fieldRequest])) { - continue; - } - - // if module settings is still JSON, decode it to normal stdClass - if (is_string($this->module_settings)) { - $this->module_settings = json_decode($this->module_settings); - } - - // are we editing common settings, or module-specific settings? - if (!in_array($fieldDB, $this->fillable)) { - // this field is not part of "core" content - probably it will be module settings - $commonField = false; - $fieldValue = isset($this->module_settings->$fieldDB) ? $this->module_settings->$fieldDB : null; - } else { - $commonField = true; - $fieldValue = $this->$fieldDB; - } - - // remove any whitespaces around real content - if (!is_null($request[$fieldRequest])) { - $request[$fieldRequest] = trim($request[$fieldRequest]); - } - - if (trim($fieldValue) != $request[$fieldRequest]) { - - $this->saveHistory($revisionId, $fieldRequest, $fieldValue, $request); - - // save change into database - if ($commonField) { - $this->$fieldDB = $request[$fieldRequest]; - } else { - $this->module_settings->$fieldDB = $request[$fieldRequest]; - } - - $changed++; - } - } - - // make JSON from stdClass - if (!is_string($this->module_settings)) { - $this->module_settings = json_encode($this->module_settings); - } - - $this->save(); - - return [$revisionId, $changed]; - } - - /** - * Upload and set some image as title photo - * - * @param Request $request - */ - public function uploadTitlePhoto(Request $request) - { - if ($request->hasFile('titlePhoto')) { - return $this->file->upload($request->file('titlePhoto'), $request); - } - - return null; - } - /** * Upload and assign files to newly created content page * - * @param Request $request - * @param null $revisionId + * @param $files + * @param $assignedFiles + * @param null $revisionId * * @return int */ - public function uploadRelatedFiles(Request $request, $revisionId = null) + public function uploadRelatedFiles($files, $assignedFiles = [], $revisionId = null) { - $files = $request->all()['files']; $changed = 0; // check if any file was removed if ($revisionId) { - $changed += $this->removeRelatedFiles($revisionId, $request); + $changed += $this->removeRelatedFiles($revisionId, $assignedFiles); } // allow uploading only on created pages @@ -222,13 +36,16 @@ trait Content 'name' => '.content_files', 'hidden' => true ]); - $request->directoryId = $directory->id; + $data = new \stdClass(); + $data->directoryId = $directory->id; + + $fileModel = App::make(File::class); foreach ($files as $file) { if (!$file) { continue; } - $uploaded = $this->file->upload($file, $request); + $uploaded = $fileModel->upload($file, $data); // add assignement ContentHasFile::create([ @@ -250,16 +67,13 @@ trait Content * Delete files from association * * @param $revisionId - * @param $request * * @return int */ - private function removeRelatedFiles($revisionId, $request) + private function removeRelatedFiles($revisionId, $assignedFiles) { - $files = array_keys((array)$request->keepAssigned); - $allFiles = $this->files() - ->whereNotIn('id', $files) + ->whereNotIn('id', $assignedFiles) ->get(); foreach ($allFiles as $file) { @@ -273,29 +87,6 @@ trait Content return count($allFiles); } - /** - * Save history entry into database - * - * @param $revisionId - * @param $fieldRequest - * @param $fieldValue - * @param $request - */ - private function saveHistory($revisionId, $fieldRequest, $fieldValue, $request) - { // setup history object - $history = [ - 'user_id' => \Auth::user()->id, - 'content_id' => $this->id, - 'edit_batch' => $revisionId, - 'column' => $fieldRequest, - 'old_value' => $fieldValue, - 'new_value' => $request[$fieldRequest] - ]; - - // save history - ContentHistory::create($history); - } - public function view() { $this->viewed++; diff --git a/app/Models/Content/ModelTraits/ContentHistory.php b/app/Models/Content/ModelTraits/ContentHistory.php index ee852408..84f58489 100644 --- a/app/Models/Content/ModelTraits/ContentHistory.php +++ b/app/Models/Content/ModelTraits/ContentHistory.php @@ -18,7 +18,7 @@ trait ContentHistory public function getStructuredHistoryOf(Content $content) { $data = $content->history() - ->select('content_history.*', 'contents.module_handler', 'users.email AS user_email', 'users.name AS user_name') + ->select('content_history.*', 'contents.moduleHandler', 'users.email AS user_email', 'users.name AS user_name') ->join('users', 'users.id', '=', 'content_history.user_id') ->join('contents', 'contents.id', '=', 'content_history.content_id') ->orderBy('changed_at', 'DESC') @@ -61,7 +61,7 @@ trait ContentHistory */ // get handler of given content page - $handler = $change->module_handler; + $handler = $change->moduleHandler; return $handler::getHistoryHandler(); } diff --git a/app/Models/CustomFields/ModuleHasCustomField.php b/app/Models/CustomFields/ModuleHasCustomField.php index 56b306a6..69236ded 100644 --- a/app/Models/CustomFields/ModuleHasCustomField.php +++ b/app/Models/CustomFields/ModuleHasCustomField.php @@ -13,7 +13,7 @@ class ModuleHasCustomField extends Model public $timestamps = false; protected $fillable = [ - 'module_handler', + 'moduleHandler', 'custom_field_id' ]; diff --git a/app/Models/FileManager/ModelTraits/File.php b/app/Models/FileManager/ModelTraits/File.php index aea2fe73..a35fa861 100644 --- a/app/Models/FileManager/ModelTraits/File.php +++ b/app/Models/FileManager/ModelTraits/File.php @@ -3,7 +3,6 @@ namespace App\Models\FileManager\ModelTraits; use App\Events\UploadFile; -use App\Http\Requests\Request; use App\Models\FileManager\File as FileModel; use Franzose\ClosureTable\Extensions\Str; use Illuminate\Support\Facades\Auth; @@ -34,13 +33,15 @@ trait File * Saves file into FS and creates new record in database * * @param UploadedFile $file - * @param Request $request + * @param $data * * @return array associative array - key 'file' is type of SymphonyFile and contains info about real file, key 'id' * is ID of row in files table */ - public function upload(UploadedFile $file, Request $request) + public function upload(UploadedFile $file, $data = []) { + $data = (object)$data; + $destination = config('app.upload_path'); $filename = $this->getFilename($file); @@ -54,7 +55,7 @@ trait File } // insert record into database - $id = $this->saveIntoDatabase($uploadedFile, $request, $file->getClientOriginalName()); + $id = $this->saveIntoDatabase($uploadedFile, $data, $file->getClientOriginalName()); // fire event about new file Event::fire(new UploadFile($uploadedFile, $id)); @@ -72,12 +73,12 @@ trait File * This file saves new record into database. It also calculates hash of given file, obtains MIME type etc. * * @param SymphonyFile $file - * @param Request $request + * @param $request * @param $originalFilename * * @return mixed */ - protected function saveIntoDatabase(SymphonyFile $file, Request $request, $originalFilename) + protected function saveIntoDatabase(SymphonyFile $file, $request, $originalFilename) { // get path and hash of uploaded file $path = config('app.upload_path') . DIRECTORY_SEPARATOR . $file->getFilename(); @@ -92,10 +93,10 @@ trait File 'hash_algorithm' => FileModel::HASH_ALGORITHM, 'mime_type' => $file->getMimeType(), 'file_size' => $file->getSize(), - 'name' => $request->name, - 'description' => $request->description, - 'directory_id' => $request->directoryId ? $request->directoryId : null, - 'keywords' => $request->keywords + 'name' => isset($request->name) ? $request->name : '', + 'description' => isset($request->description) ? $request->description : '', + 'directory_id' => isset($request->directoryId) ? $request->directoryId ? $request->directoryId : null : null, + 'keywords' => isset($request->keyword) ? $request->keyword : '' ]); return $newFile->id; diff --git a/app/Models/ModelTraits/Module.php b/app/Models/ModelTraits/Module.php index 938f3b73..7f206f2b 100644 --- a/app/Models/ModelTraits/Module.php +++ b/app/Models/ModelTraits/Module.php @@ -44,7 +44,7 @@ trait Module { 'manages_content' => $managesContent, 'support_categories' => $supportCategories, 'alias' => $alias, - 'module_settings' => json_encode($settings), + 'moduleSettings' => json_encode($settings), 'parent_id' => $parentModuleId ? $parentModuleId : null, 'enabled' => 1, 'is_template' => $isTemplate diff --git a/app/Models/Module.php b/app/Models/Module.php index f6940aad..ab569966 100644 --- a/app/Models/Module.php +++ b/app/Models/Module.php @@ -17,7 +17,7 @@ class Module extends Model 'name', 'description', 'alias', - 'module_settings', + 'moduleSettings', 'enabled', 'support_categories', 'manages_content', diff --git a/app/Models/User.php b/app/Models/User.php index 4ffbea03..35d4911f 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -20,6 +20,7 @@ class User extends Model implements AuthenticableInterface 'username', 'password', 'name', + 'role' ]; /** * The attributes excluded from the model's JSON form. diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index f5b55649..d48a6a6f 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -32,18 +32,16 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - // ignore running from artisan - if (App::runningInConsole()) { - return; - } - - $this->registerWidgets(); - $this->registerSettings(); - $this->registerSearch(); - $this->app->bind(IContent::class, ContentRepository::class); $this->app->bind(IModule::class, ModuleRepository::class); $this->app->bind(ITemplate::class, TemplateRepository::class); + + // ignore running from artisan + if (!App::runningInConsole()) { + $this->registerWidgets(); + $this->registerSettings(); + $this->registerSearch(); + } } /** diff --git a/app/Providers/LaravelLocalizationServiceProvider.php b/app/Providers/LaravelLocalizationServiceProvider.php index 94f761fc..00b3db64 100644 --- a/app/Providers/LaravelLocalizationServiceProvider.php +++ b/app/Providers/LaravelLocalizationServiceProvider.php @@ -1,7 +1,5 @@ env('LOCALE_NATIVE_NAME'), - 'script' => env('LOCALE_SCRIPT'), - 'name' => env('LOCALE_TRANSLATED_NAME'), + 'native' => env('LOCALE_NATIVE_NAME', config('app.locale')), + 'script' => env('LOCALE_SCRIPT', 'Latn'), + 'name' => env('LOCALE_TRANSLATED_NAME', config('app.locale')), 'code' => config('app.locale'), ]; - // create default language - Language::create($supportedLocales[config('app.locale')]); + DB::table('languages') + ->insert($supportedLocales[config('app.locale')]); } foreach ($languages as $language) { diff --git a/app/Providers/ModuleManager.php b/app/Providers/ModuleManager.php index f925aec1..369ddd6c 100644 --- a/app/Providers/ModuleManager.php +++ b/app/Providers/ModuleManager.php @@ -26,12 +26,12 @@ class ModuleManager extends ServiceProvider // iterate over all modules and enable or disable them foreach ($modules as $module) { - $module->module_settings = json_decode($module->module_settings); + $module->moduleSettings = json_decode($module->moduleSettings); if ($module->is_template) { - if (isset($module->module_settings->providers) && !empty($module->module_settings->providers)) { - foreach ($module->module_settings->providers as $provider) { + if (isset($module->moduleSettings->providers) && !empty($module->moduleSettings->providers)) { + foreach ($module->moduleSettings->providers as $provider) { $this->app->register($provider); } } @@ -61,7 +61,7 @@ class ModuleManager extends ServiceProvider */ private function createModulesJson(Module $module) { - $config = $module->module_settings; + $config = $module->moduleSettings; if (is_null($config)) { return; diff --git a/app/Providers/TemplateServiceProvider.php b/app/Providers/TemplateServiceProvider.php index 10fbdd71..d61eecf5 100644 --- a/app/Providers/TemplateServiceProvider.php +++ b/app/Providers/TemplateServiceProvider.php @@ -2,9 +2,9 @@ namespace App\Providers; +use App\CMS\Contracts\Repositories\Template as TemplateContract; use App\CMS\Handlers\Registrators\TemplateRegistrator; use App\CMS\Helpers\CurrentTemplate; -use App\Models\Templates\Template; use Illuminate\Support\Facades\App; use Illuminate\Support\ServiceProvider; @@ -13,7 +13,7 @@ class TemplateServiceProvider extends ServiceProvider public function boot() { // ignore running from artisan - if (App::runningInConsole()) { + if (App::runningInConsole() || App::environment('testing')) { $this->publishViewResources(); return; @@ -26,19 +26,24 @@ class TemplateServiceProvider extends ServiceProvider } // include files - $files = isset($template->module_settings->files) ? $template->module_settings->files : []; + $files = isset($template->moduleSettings->files) ? $template->moduleSettings->files : []; foreach ($files as $file) { include_once $file; } // register templates - $publicTemplates = call_user_func([CurrentTemplate::handler(), 'getPublicTemplatePaths']); + $publicTemplates = CurrentTemplate::getPublicTemplatePaths(); if (!is_array($publicTemplates)) { throw new \ErrorException(CurrentTemplate::handler() . '::getPublicTemplatePaths() must return array!'); } + $this->registerTemplatePaths($publicTemplates); + } + + public function registerTemplatePaths($publicTemplates) + { /** * @var $registrator TemplateRegistrator */ @@ -76,12 +81,12 @@ class TemplateServiceProvider extends ServiceProvider private function publishViewResources() { $template = CurrentTemplate::get(); - if (!$template) { + if (!$template || is_null($template->moduleSettings)) { return; } - $templateDir = base_path('templates/' . $template->module_settings->staticName . '/Resources'); - $assetsDir = $templateDir . '/' . Template::ASSETS_DIRECTORY; + $templateDir = base_path('templates/' . $template->moduleSettings->staticName . '/Resources'); + $assetsDir = $templateDir . '/' . TemplateContract::ASSETS_DIRECTORY; $viewsDir = $templateDir . '/views'; // publish assets if exists for current theme diff --git a/config/database.php b/config/database.php index dace41ee..3e451f83 100644 --- a/config/database.php +++ b/config/database.php @@ -55,8 +55,8 @@ return [ 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), + 'database' => env('DB_DATABASE'), + 'username' => env('DB_USERNAME'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'collation' => 'utf8_general_ci', @@ -64,6 +64,18 @@ return [ 'strict' => false, ], + 'mysqlTesting' => [ + 'driver' => 'mysql', + 'host' => env('DB_UNIT_TESTS_HOST', 'localhost'), + 'database' => env('DB_UNIT_TESTS_DATABASE'), + 'username' => env('DB_UNIT_TESTS_USERNAME'), + 'password' => env('DB_UNIT_TESTS_PASSWORD', ''), + 'charset' => 'utf8', + 'collation' => 'utf8_general_ci', + 'prefix' => '', + 'strict' => false, + ], + 'pgsql' => [ 'driver' => 'pgsql', 'host' => env('DB_HOST', 'localhost'), @@ -74,17 +86,6 @@ return [ 'prefix' => '', 'schema' => 'public', ], - - 'sqlsrv' => [ - 'driver' => 'sqlsrv', - 'host' => env('DB_HOST', 'localhost'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), - 'password' => env('DB_PASSWORD', ''), - 'charset' => 'utf8', - 'prefix' => '', - ], - ], /* diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 0876c70c..96f72d25 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -11,11 +11,32 @@ | */ -$factory->define(App\User::class, function (Faker\Generator $faker) { +use App\CMS\Contracts\Repositories\Content as ContentContract; +use App\Models\Content\Content; +use App\Models\User; +use Carbon\Carbon; + +$factory->define(User::class, function (Faker\Generator $faker) { + $email = $faker->email; return [ - 'name' => $faker->name, - 'email' => $faker->email, + 'username' => $email, + 'email' => $email, + 'name' => $faker->name, 'password' => bcrypt(str_random(10)), - 'remember_token' => str_random(10), + 'role' => 'admin', ]; }); + +$factory->define(Content::class, function (Faker\Generator $faker) { + return [ + 'title' => $faker->sentence(5), + 'userId' => 1, + 'url' => $faker->slug(5), + 'pageContent' => $faker->text(1500), + 'metaDescription' => $faker->text, + 'moduleHandler' => config('staticpages.handler'), + 'language' => env('LOCALES'), + 'publishedFrom' => Carbon::now(), + 'status' => ContentContract::STATUS_PUBLIC + ]; +}); \ No newline at end of file diff --git a/database/migrations/2016_10_11_135756_AddUniqueCodeToWidgets.php b/database/migrations/2016_10_11_135756_AddUniqueCodeToWidgets.php index 36141a15..c8456ba9 100644 --- a/database/migrations/2016_10_11_135756_AddUniqueCodeToWidgets.php +++ b/database/migrations/2016_10_11_135756_AddUniqueCodeToWidgets.php @@ -26,7 +26,7 @@ class AddUniqueCodeToWidgets extends Migration }); // migrate data - $widgets = \App\Models\Widget::all(); + $widgets = \App\Models\Widgets\Widget::all(); foreach ($widgets as $widget) { $widget->settings = json_decode($widget->settings); if (isset($widget->settings->containerClass)) { diff --git a/database/migrations/2016_10_25_071455_rename_column_in_contents.php b/database/migrations/2016_10_25_071455_rename_column_in_contents.php new file mode 100644 index 00000000..45b03e33 --- /dev/null +++ b/database/migrations/2016_10_25_071455_rename_column_in_contents.php @@ -0,0 +1,67 @@ +getDoctrineSchemaManager()->getDatabasePlatform(); + $platform->registerDoctrineTypeMapping('enum', 'string'); + + $this->columns = [ + 'user_id', + 'parent_id', + 'category_id', + 'language', + 'module_handler', + 'published_from', + 'published_to', + 'title_photo', + 'template', + 'is_homepage', + 'title', + 'url', + 'meta_keywords', + 'meta_description', + 'content', + 'module_settings', + 'status' + ]; + } + + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('contents', function (Blueprint $table) { + foreach ($this->columns as $column) { + $table->renameColumn($column, camel_case($column)); + } + + $table->renameColumn('content', 'pageContent'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('contents', function (Blueprint $table) { + foreach ($this->columns as $column) { + $table->renameColumn(camel_case($column), $column); + } + + $table->renameColumn('pageContent', 'content'); + }); + } +} diff --git a/modules/Blog/Article/Handlers/Article.php b/modules/Blog/Article/Handlers/Article.php index 7365f423..901eaa2b 100644 --- a/modules/Blog/Article/Handlers/Article.php +++ b/modules/Blog/Article/Handlers/Article.php @@ -5,7 +5,6 @@ use App\CMS\Contracts\Content\AdvancedContentModifier; use App\CMS\Contracts\Content\ContentTitles; use App\CMS\Contracts\Modules\InstallableModule; use App\CMS\Handlers\Handler; -use App\Http\Controllers\Admin\Contents\EditContent; use App\Http\Controllers\Controller; use App\Http\Requests\Request; use App\Models\ActionLog\ActionLogType; @@ -27,7 +26,7 @@ class Article extends Handler implements ContentTitles, AdvancedContentModifier, public function render(Content $content, $parameters) { $content->comments = []; - if (isset($content->module_settings->allowComments) && $content->module_settings->allowComments) { + if (isset($content->moduleSettings->allowComments) && $content->moduleSettings->allowComments) { $content->comments = Comment::where('content_id', $content->id) ->with('author') ->where('approved', 1) @@ -62,7 +61,7 @@ class Article extends Handler implements ContentTitles, AdvancedContentModifier, */ public static function createNew(Content &$content, Request $request) { - $content->module_settings = json_encode(['allowComments' => (int)$request->has('allowComments')]); + $content->moduleSettings = ['allowComments' => (int)$request->has('allowComments')]; } /** @@ -73,23 +72,18 @@ class Article extends Handler implements ContentTitles, AdvancedContentModifier, * @param Content $content * @param Request $request * - * @param $revisionID string ID of revision used - * - * @return int number of edited fields + * @return void */ - public static function edit(Content &$content, Request $request, $revisionID) + public static function edit(Content $content, $request) { - $fields = ['allowComments' => 'allowComments']; + $settings = $content->moduleSettings; + if (!is_object($settings)) + $settings = new \stdClass(); - // get data and try to save them - $data = EditContent::getFields($request, $fields); + $settings->allowComments = isset($request['allowComments']) ? (int)$request['allowComments'] : 0; - $data['allowComments'] = (int)$data['allowComments']; - - list($revision, $changedColumns) = $content->updateWithHistory($fields, $data, $revisionID); - - // return amount of changed columns - return $changedColumns; + $content->moduleSettings = $settings; + $content->save(); } /** @@ -99,8 +93,6 @@ class Article extends Handler implements ContentTitles, AdvancedContentModifier, */ public static function registerAdminMenu(User $user) { - parent::registerAdminMenu($user); - $menu = \Menu::instance('mainMenu'); $blogSubmenu = $menu->whereTitle(trans('article::module.blog')); diff --git a/modules/Blog/Article/Http/Controllers/Visitor/CreateNewComment.php b/modules/Blog/Article/Http/Controllers/Visitor/CreateNewComment.php index 6811187b..8af7ba9b 100644 --- a/modules/Blog/Article/Http/Controllers/Visitor/CreateNewComment.php +++ b/modules/Blog/Article/Http/Controllers/Visitor/CreateNewComment.php @@ -14,12 +14,12 @@ class CreateNewComment extends Controller public function postNew(\Modules\Blog\Article\Http\Requests\CreateNewComment $request, $articleId) { $article = Content::where('id', $articleId) - ->where('module_handler', Article::class) + ->where('moduleHandler', Article::class) ->firstOrFail(); - $article->module_settings = json_decode($article->module_settings); + $article->moduleSettings = json_decode($article->moduleSettings); - if (!isset($article->module_settings->allowComments) || !$article->module_settings->allowComments) { + if (!isset($article->moduleSettings->allowComments) || !$article->moduleSettings->allowComments) { return redirect() ->route('page.content', ['url' => $article->url]) ->with('error', trans('article::comments.disabledComments')); diff --git a/modules/Blog/Article/Resources/views/admin/content/basicInfo.blade.php b/modules/Blog/Article/Resources/views/admin/content/basicInfo.blade.php index ec02b51e..dd808110 100644 --- a/modules/Blog/Article/Resources/views/admin/content/basicInfo.blade.php +++ b/modules/Blog/Article/Resources/views/admin/content/basicInfo.blade.php @@ -37,12 +37,12 @@ @include('admin.snippets.hasError', ['field' => 'status'])
- @foreach($rootPages as $rootPage) @endforeach @@ -54,7 +54,7 @@
@@ -62,11 +62,11 @@ @if($module->support_categories && count($categories))
- @foreach($categories as $category) @endforeach @@ -78,7 +78,7 @@
diff --git a/modules/Blog/ArticleList/Handlers/ArticleList.php b/modules/Blog/ArticleList/Handlers/ArticleList.php index d1f6d1cf..2b3dfa10 100644 --- a/modules/Blog/ArticleList/Handlers/ArticleList.php +++ b/modules/Blog/ArticleList/Handlers/ArticleList.php @@ -96,18 +96,18 @@ class ArticleList extends Handler */ public function render(Content $content, $parameters) { - $articles = ArticleModel::where('module_handler', Article::class) + $articles = ArticleModel::where('moduleHandler', Article::class) ->with('comments') ->with('category') ->where(function ($query) { - $query->where('published_from', '<', Carbon::now()) - ->orWhereNull('published_from'); + $query->where('publishedFrom', '<', Carbon::now()) + ->orWhereNull('publishedFrom'); }) ->where(function ($query) { - $query->where('published_to', '>', Carbon::now()) - ->orWhereNull('published_to'); + $query->where('publishedTo', '>', Carbon::now()) + ->orWhereNull('publishedTo'); }) - ->orderBy('published_from', 'DESC') + ->orderBy('publishedFrom', 'DESC') ->orderBy('created_at', 'DESC'); // show articles for not-logged users of even for logged onew? @@ -135,7 +135,7 @@ class ArticleList extends Handler // decode module settings foreach ($articles as $article) { - $article->module_settings = json_decode($article->module_settings); + $article->moduleSettings = json_decode($article->moduleSettings); } return Controller::VisitorsView($content->template, [ diff --git a/modules/ContactForm/Handlers/ContactForm.php b/modules/ContactForm/Handlers/ContactForm.php index ee9218d0..695ca5b8 100644 --- a/modules/ContactForm/Handlers/ContactForm.php +++ b/modules/ContactForm/Handlers/ContactForm.php @@ -40,7 +40,7 @@ class ContactForm extends Handler implements ContentTitles, AdvancedContentModif ]; // save settings - $content->module_settings = json_encode($settings); + $content->moduleSettings = json_encode($settings); } /** @@ -55,7 +55,7 @@ class ContactForm extends Handler implements ContentTitles, AdvancedContentModif * * @return int number of edited fields */ - public static function edit(Content &$content, Request $request, $revisionID) + public static function edit(Content $content, $request) { $fields = [ 'phone' => 'phone', @@ -70,7 +70,7 @@ class ContactForm extends Handler implements ContentTitles, AdvancedContentModif // get data and try to save them $data = EditContent::getFields($request, $fields); - list($revision, $changedColumns) = $content->updateWithHistory($fields, $data, $revisionID); + list($revision, $changedColumns) = $content->updateWithHistory($fields, $data); // return amount of changed columns return $changedColumns; diff --git a/modules/ContactForm/Http/Controllers/Visitor/CreateNewMessage.php b/modules/ContactForm/Http/Controllers/Visitor/CreateNewMessage.php index 0326a2e0..2f4135b7 100644 --- a/modules/ContactForm/Http/Controllers/Visitor/CreateNewMessage.php +++ b/modules/ContactForm/Http/Controllers/Visitor/CreateNewMessage.php @@ -21,22 +21,22 @@ class CreateNewMessage extends Controller public function postMessage(SendNewEmailRequest $request, $formId) { // load form settings - $form = Content::where('module_handler', config('contactform.handler')) + $form = Content::where('moduleHandler', config('contactform.handler')) ->findOrFail($formId); - $form->module_settings = json_decode($form->module_settings); + $form->moduleSettings = json_decode($form->moduleSettings); // select template - $template = isset($form->module_settings->emailTemplate) ? $form->module_settings->emailTemplate : 'contactform::emails.default'; + $template = isset($form->moduleSettings->emailTemplate) ? $form->moduleSettings->emailTemplate : 'contactform::emails.default'; // send email $status = Mail::send(Template::name($template), ['data' => $request], function (Message $message) use ($request, $form) { $message->from($request->email, $request->name); // get message subject - $subject = isset($form->module_settings->subject) ? $form->module_settings->subject : trans('contactform::admin/contents.defaultSubject'); + $subject = isset($form->moduleSettings->subject) ? $form->moduleSettings->subject : trans('contactform::admin/contents.defaultSubject'); - $message->to($form->module_settings->email) + $message->to($form->moduleSettings->email) ->subject($subject); }); diff --git a/modules/ContactForm/Resources/views/admin/form/basicInfo.blade.php b/modules/ContactForm/Resources/views/admin/form/basicInfo.blade.php index a67fa532..ceeb0a5b 100644 --- a/modules/ContactForm/Resources/views/admin/form/basicInfo.blade.php +++ b/modules/ContactForm/Resources/views/admin/form/basicInfo.blade.php @@ -55,11 +55,11 @@ @if($module->support_categories && count($categories))
- @foreach($categories as $category) @endforeach @@ -77,26 +77,26 @@ @lang('contactform::admin/content.email') - + - + + value="{{$page->moduleSettings->companyName or ""}}" /> - +
@@ -105,14 +105,14 @@ + value="{{$page->moduleSettings->contactEmail or \Auth::user()->email}}" /> + value="{{$page->moduleSettings->subject or trans('contactform::admin/content.defaultSubject')}}" />
@@ -120,7 +120,7 @@ @lang('contactform::admin/content.gpsLat') -
@@ -128,7 +128,7 @@ @lang('contactform::admin/content.gpsLng') -
diff --git a/modules/ContactForm/Widgets/Address/Presenter.php b/modules/ContactForm/Widgets/Address/Presenter.php index 6814621d..568cf176 100644 --- a/modules/ContactForm/Widgets/Address/Presenter.php +++ b/modules/ContactForm/Widgets/Address/Presenter.php @@ -24,7 +24,7 @@ class Presenter implements WidgetRenderer if (!$form) return null; - $formData = json_decode($form->module_settings); + $formData = json_decode($form->moduleSettings); $code = '
container_id) { @@ -47,7 +47,7 @@ class Presenter implements WidgetRenderer */ public static function renderAddForm(WidgetType $type) { - $contactForms = Content::where('module_handler', config('contactform.handler')) + $contactForms = Content::where('moduleHandler', config('contactform.handler')) ->get(); return view('contactform::admin.widgets.address.new', [ @@ -66,7 +66,7 @@ class Presenter implements WidgetRenderer */ public static function renderEditForm(Widget $widget) { - $contactForms = Content::where('module_handler', config('contactform.handler')) + $contactForms = Content::where('moduleHandler', config('contactform.handler')) ->get(); return view('contactform::admin.widgets.address.edit', [ 'widget' => $widget, diff --git a/modules/ContactForm/Widgets/Form/Presenter.php b/modules/ContactForm/Widgets/Form/Presenter.php index 78ee2569..32e20cbc 100644 --- a/modules/ContactForm/Widgets/Form/Presenter.php +++ b/modules/ContactForm/Widgets/Form/Presenter.php @@ -32,7 +32,7 @@ class Presenter implements WidgetRenderer return null; } - $form->module_settings = json_decode($form->module_settings); + $form->moduleSettings = json_decode($form->moduleSettings); return view(self::$template, ['widget' => $widget, 'form' => $form]); } @@ -46,7 +46,7 @@ class Presenter implements WidgetRenderer */ public static function renderAddForm(WidgetType $type) { - $contactForms = Content::where('module_handler', config('contactform.handler')) + $contactForms = Content::where('moduleHandler', config('contactform.handler')) ->get(); return view('contactform::admin.widgets.form.new', [ @@ -65,7 +65,7 @@ class Presenter implements WidgetRenderer */ public static function renderEditForm(Widget $widget) { - $contactForms = Content::where('module_handler', config('contactform.handler')) + $contactForms = Content::where('moduleHandler', config('contactform.handler')) ->get(); return view('contactform::admin.widgets.address.edit', [ 'widget' => $widget, diff --git a/modules/Gallery/Handlers/Gallery.php b/modules/Gallery/Handlers/Gallery.php index c414be26..20f6c62f 100644 --- a/modules/Gallery/Handlers/Gallery.php +++ b/modules/Gallery/Handlers/Gallery.php @@ -29,7 +29,7 @@ class Gallery implements AppHandler public function render(Content $content, $parameters) { // get directory ID - $directoryId = $content->module_settings->directoryId; + $directoryId = $content->moduleSettings->directoryId; // get all images in given directory $images = File::where('directory_id', $directoryId) @@ -56,12 +56,12 @@ class Gallery implements AppHandler */ public static function loadExtraData(Content $content) { - if (is_string($content->module_settings)) { - $content->module_settings = json_decode($content->module_settings); + if (is_string($content->moduleSettings)) { + $content->moduleSettings = json_decode($content->moduleSettings); } $extra = [ - 'slider' => isset($content->module_settings->slider) ? $content->module_settings->slider : false + 'slider' => isset($content->moduleSettings->slider) ? $content->moduleSettings->slider : false ]; return $extra; @@ -91,7 +91,7 @@ class Gallery implements AppHandler $settings = ['directoryId' => $directory->id]; // save settings - $content->module_settings = json_encode($settings); + $content->moduleSettings = json_encode($settings); } /** @@ -224,13 +224,13 @@ class Gallery implements AppHandler */ public static function delete(Content $content) { - // try to convert module_settings into something more accessible - if (is_string($content->module_settings)) { - $content->module_settings = json_decode($content->module_settings); + // try to convert moduleSettings into something more accessible + if (is_string($content->moduleSettings)) { + $content->moduleSettings = json_decode($content->moduleSettings); } // get directory id - $directoryId = $content->module_settings->directoryId; + $directoryId = $content->moduleSettings->directoryId; $directory = Directory::find($directoryId); diff --git a/modules/Gallery/Resources/views/admin/content/editUpload.blade.php b/modules/Gallery/Resources/views/admin/content/editUpload.blade.php index 1b25903e..75f03669 100644 --- a/modules/Gallery/Resources/views/admin/content/editUpload.blade.php +++ b/modules/Gallery/Resources/views/admin/content/editUpload.blade.php @@ -1,5 +1,5 @@
diff --git a/resources/views/admin/content/formParts/appearance.blade.php b/resources/views/admin/content/formParts/appearance.blade.php index 2e54de54..253db68f 100644 --- a/resources/views/admin/content/formParts/appearance.blade.php +++ b/resources/views/admin/content/formParts/appearance.blade.php @@ -1,9 +1,9 @@ -@if($page->title_photo) +@if($page->titlePhoto) \ No newline at end of file diff --git a/resources/views/admin/content/formParts/publicationSetup.blade.php b/resources/views/admin/content/formParts/publicationSetup.blade.php index 8664f708..c8f61727 100644 --- a/resources/views/admin/content/formParts/publicationSetup.blade.php +++ b/resources/views/admin/content/formParts/publicationSetup.blade.php @@ -1,22 +1,22 @@
- + - @include('admin.snippets.hasError', ['field' => 'published_from']) + @include('admin.snippets.hasError', ['field' => 'publishedFrom'])
- - @include('admin.snippets.hasError', ['field' => 'published_to']) + + @include('admin.snippets.hasError', ['field' => 'publishedTo'])
\ No newline at end of file diff --git a/resources/views/admin/content/overview.blade.php b/resources/views/admin/content/overview.blade.php index eea9d19e..8c7d9f86 100644 --- a/resources/views/admin/content/overview.blade.php +++ b/resources/views/admin/content/overview.blade.php @@ -1,6 +1,6 @@ @extends('admin.layoutWithNavigation') -@section('pageHeading', @trans(isset($pageHeading) ? $pageHeading : 'admin/contents.overview')) +@section('pageHeading', @trans($pageHeading)) @section('headerButtons') @if($module->exists === true) @@ -34,13 +34,13 @@ @foreach($pages as $page)
- + {{$page->title}} - @if($page->is_homepage) @lang('admin/contents.homepage') @endif + @if($page->isHomepage) @lang('admin/contents.homepage') @endif