diff --git a/app/CMS/Contracts/Widgets/PublicWidget.php b/app/CMS/Contracts/Widgets/PublicWidget.php index 103f4a0c..4a600afa 100644 --- a/app/CMS/Contracts/Widgets/PublicWidget.php +++ b/app/CMS/Contracts/Widgets/PublicWidget.php @@ -1,6 +1,7 @@ code) || empty($data->code)) { throw new MissingParameterException('code'); } - $widgetSettings = [ - 'code' => $data->code, - 'containerClass' => isset($data->containerClass) ? $data->containerClass : '' - ]; - - $widget->settings = json_encode($widgetSettings); - - return $widget; + return ['code' => $data->code]; } } \ No newline at end of file diff --git a/app/CMS/Widgets/Menu/Menu.php b/app/CMS/Widgets/Menu/Menu.php index f3653b8d..8dde5374 100644 --- a/app/CMS/Widgets/Menu/Menu.php +++ b/app/CMS/Widgets/Menu/Menu.php @@ -4,8 +4,8 @@ namespace App\CMS\Widgets\Menu; use App\CMS\Contracts\Widgets\PublicWidget; use App\CMS\Widgets\Contracts\WidgetRenderer; use App\CMS\Widgets\Exceptions\MissingParameterException; +use App\Http\Requests\Request; use App\Models\Content\Content; -use App\Models\Widgets\Widget; use Mcamara\LaravelLocalization\Facades\LaravelLocalization; class Menu implements PublicWidget @@ -46,7 +46,7 @@ class Menu implements PublicWidget * * @return mixed */ - public static function save(Widget $widget, \stdClass $data) + public static function save(Request $data) { if (!isset($data->settings) || empty($data->settings) || !json_decode($data->settings)) { throw new MissingParameterException('settings'); @@ -61,14 +61,7 @@ class Menu implements PublicWidget } } - $settings = [ - 'links' => $links, - 'containerClass' => $data->containerClass - ]; - - $widget->settings = json_encode($settings); - - return $widget; + return ['links' => $links]; } public static function selectContentPages($ids) diff --git a/app/Http/Controllers/Admin/Contents/CreateNewContent.php b/app/Http/Controllers/Admin/Contents/CreateNewContent.php index 4fa8535d..8a595663 100644 --- a/app/Http/Controllers/Admin/Contents/CreateNewContent.php +++ b/app/Http/Controllers/Admin/Contents/CreateNewContent.php @@ -9,7 +9,7 @@ use App\Http\Requests\CreateNewContentRequest; use App\Models\Content\Content; use App\Models\FileManager\File; use App\Models\Module; -use App\Models\Template; +use App\Models\Templates\Template; use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; use Mcamara\LaravelLocalization\Facades\LaravelLocalization; diff --git a/app/Http/Controllers/Admin/Contents/EditContent.php b/app/Http/Controllers/Admin/Contents/EditContent.php index eb3416ed..46fd73fd 100644 --- a/app/Http/Controllers/Admin/Contents/EditContent.php +++ b/app/Http/Controllers/Admin/Contents/EditContent.php @@ -16,7 +16,7 @@ use App\Models\Content\Content; use App\Models\Content\ContentHistory; use App\Models\FileManager\File; use App\Models\Module; -use App\Models\Template; +use App\Models\Templates\Template; use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; use Mcamara\LaravelLocalization\Facades\LaravelLocalization; diff --git a/app/Http/Controllers/Admin/Templates/CopyTemplate.php b/app/Http/Controllers/Admin/Templates/CopyTemplate.php index 1a407547..41701e16 100644 --- a/app/Http/Controllers/Admin/Templates/CopyTemplate.php +++ b/app/Http/Controllers/Admin/Templates/CopyTemplate.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\Admin\Templates; use App\Http\Controllers\Admin\Controller; use App\Http\Requests\CopyTemplateRequest; -use App\Models\Template; +use App\Models\Templates\Template; class CopyTemplate extends Controller { diff --git a/app/Http/Controllers/Admin/Templates/EditTemplate.php b/app/Http/Controllers/Admin/Templates/EditTemplate.php index fb372b83..7170b4f8 100644 --- a/app/Http/Controllers/Admin/Templates/EditTemplate.php +++ b/app/Http/Controllers/Admin/Templates/EditTemplate.php @@ -5,7 +5,7 @@ namespace App\Http\Controllers\Admin\Templates; use App\Http\Controllers\Controller; use App\Http\Requests; use App\Http\Requests\EditTemplateRequest; -use App\Models\Template; +use App\Models\Templates\Template; use Illuminate\Http\Request; use Illuminate\Support\Facades\File; diff --git a/app/Http/Controllers/Admin/Templates/TemplateOverview.php b/app/Http/Controllers/Admin/Templates/TemplateOverview.php index 8baf7300..6576b76a 100644 --- a/app/Http/Controllers/Admin/Templates/TemplateOverview.php +++ b/app/Http/Controllers/Admin/Templates/TemplateOverview.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Admin\Templates; use App\Http\Controllers\Admin\Controller; -use App\Models\TemplatePath; +use App\Models\Templates\TemplatePath; class TemplateOverview extends Controller { diff --git a/app/Http/Controllers/Admin/Widgets/Areas/CreateNewWidgetArea.php b/app/Http/Controllers/Admin/Widgets/Areas/CreateNewWidgetArea.php index 91c22e35..a9ec44e3 100644 --- a/app/Http/Controllers/Admin/Widgets/Areas/CreateNewWidgetArea.php +++ b/app/Http/Controllers/Admin/Widgets/Areas/CreateNewWidgetArea.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\Admin\Widgets\Areas; use App\Http\Controllers\Admin\Controller; use App\Http\Requests\NewWidgetAreaRequest; -use App\Models\WidgetArea; +use App\Models\Widgets\WidgetArea; use Illuminate\Support\Facades\Event; class CreateNewWidgetArea extends Controller diff --git a/app/Http/Controllers/Admin/Widgets/Areas/EditWidgetArea.php b/app/Http/Controllers/Admin/Widgets/Areas/EditWidgetArea.php index 788957f1..a512334c 100644 --- a/app/Http/Controllers/Admin/Widgets/Areas/EditWidgetArea.php +++ b/app/Http/Controllers/Admin/Widgets/Areas/EditWidgetArea.php @@ -5,8 +5,8 @@ namespace App\Http\Controllers\Admin\Widgets\Areas; use App\Http\Controllers\Admin\Controller; use App\Http\Requests\EditWidgetAreaRequest; use App\Models\Widgets\Widget; -use App\Models\WidgetArea; -use App\Models\WidgetInWidgetArea; +use App\Models\Widgets\WidgetArea; +use App\Models\Widgets\WidgetInWidgetArea; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Event; use Mcamara\LaravelLocalization\Facades\LaravelLocalization; diff --git a/app/Http/Controllers/Admin/Widgets/Areas/WidgetAreaOverview.php b/app/Http/Controllers/Admin/Widgets/Areas/WidgetAreaOverview.php index d813d1f2..d80aae63 100644 --- a/app/Http/Controllers/Admin/Widgets/Areas/WidgetAreaOverview.php +++ b/app/Http/Controllers/Admin/Widgets/Areas/WidgetAreaOverview.php @@ -3,8 +3,7 @@ namespace App\Http\Controllers\Admin\Widgets\Areas; use App\Http\Controllers\Admin\Controller; -use App\Http\Requests; -use App\Models\WidgetArea; +use App\Models\Widgets\WidgetArea; class WidgetAreaOverview extends Controller { diff --git a/app/Http/Controllers/Admin/Widgets/CreateNewWidget.php b/app/Http/Controllers/Admin/Widgets/CreateNewWidget.php index 628ac738..f4d90621 100644 --- a/app/Http/Controllers/Admin/Widgets/CreateNewWidget.php +++ b/app/Http/Controllers/Admin/Widgets/CreateNewWidget.php @@ -50,7 +50,7 @@ class CreateNewWidget extends Controller // try to save this widget try { - $this->widget->createNew($widgetType, $request->all()); + $this->widget->createNew($widgetType, $request); } catch (MissingParameterException $e) { // user omitted some value return $this->invalidWidget($type, $e->getMessage()); diff --git a/app/Models/ActionLog/ActionLog.php b/app/Models/ActionLog/ActionLog.php index 0844654c..cbdb19ae 100644 --- a/app/Models/ActionLog/ActionLog.php +++ b/app/Models/ActionLog/ActionLog.php @@ -3,13 +3,14 @@ namespace App\Models\ActionLog; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\Auth; /** * Class ActionLog */ class ActionLog extends Model { + use ModelTraits\ActionLog; + protected $table = 'action_log'; public $timestamps = false; protected $fillable = [ @@ -19,71 +20,4 @@ class ActionLog extends Model 'user_agent', 'parameters' ]; - protected $guarded = []; - - /** - * Query factory for loading action logs with their type (therefore with name and value) - * - * @param bool $joinUser - * - * @return mixed - */ - public function getLogActionsQuery($joinUser = false) - { - $actions = \DB::table('action_log') - ->select('action_log.*', 'action_log_types.*') - ->join('action_log_types', 'action_log_types.id', '=', 'action_log.type_id') - ->orderBy('action_log.created_at', 'DESC'); - - if ($joinUser) { - - $actions = $actions->join('users', 'users.id', '=', 'action_log.user_id') - ->select('action_log.*', 'action_log_types.*', 'users.email', 'users.name as user_name'); - } - - return $actions; - } - - /** - * Get last N user actions - * - * @param null $id - * @param int $limit - * - * @return array - */ - public function getUserActions($id = null, $limit = 15) - { - // if user is not specified, use logged one - if (is_null($id)) { - $id = Auth::user()->id; - } - - // load last N actions of selected user - $actions = $this->getLogActionsQuery() - ->limit($limit) - ->where('user_id', $id) - ->get(); - - // translate and return result - $this->translateLogMessages($actions); - - return $actions; - } - - /** - * Method used for translating and filling parameters into value of log. - * - * @param $messages - * - * @return array - */ - public function translateLogMessages(&$messages) - { - // translate name and value of each record - foreach ($messages as $i => $action) { - $messages[$i]->name = trans($action->name); - $messages[$i]->value = trans($action->value, (array)json_decode($action->parameters)); - } - } } \ No newline at end of file diff --git a/app/Models/ActionLog/ModelTraits/ActionLog.php b/app/Models/ActionLog/ModelTraits/ActionLog.php new file mode 100644 index 00000000..376fcb97 --- /dev/null +++ b/app/Models/ActionLog/ModelTraits/ActionLog.php @@ -0,0 +1,72 @@ +select('action_log.*', 'action_log_types.*') + ->join('action_log_types', 'action_log_types.id', '=', 'action_log.type_id') + ->orderBy('action_log.created_at', 'DESC'); + + if ($joinUser) { + $actions = $actions->join('users', 'users.id', '=', 'action_log.user_id') + ->select('action_log.*', 'action_log_types.*', 'users.email', 'users.name as user_name'); + } + + return $actions; + } + + /** + * Get last N user actions + * + * @param null $id + * @param int $limit + * + * @return array + */ + public function getUserActions($id = null, $limit = 15) + { + // if user is not specified, use logged one + if (is_null($id)) { + $id = Auth::user()->id; + } + + // load last N actions of selected user + $actions = $this->getLogActionsQuery() + ->limit($limit) + ->where('user_id', $id) + ->get(); + + // translate and return result + $this->translateLogMessages($actions); + + return $actions; + } + + /** + * Method used for translating and filling parameters into value of log. + * + * @param $messages + * + * @return array + */ + public function translateLogMessages(&$messages) + { + // translate name and value of each record + foreach ($messages as $i => $action) { + $messages[$i]->name = trans($action->name); + $messages[$i]->value = trans($action->value, (array)json_decode($action->parameters)); + } + } +} \ No newline at end of file diff --git a/app/Models/Content/Content.php b/app/Models/Content/Content.php index 0d909680..d1806999 100644 --- a/app/Models/Content/Content.php +++ b/app/Models/Content/Content.php @@ -2,17 +2,10 @@ namespace App\Models\Content; -use App\CMS\Enumerations\ContentStatuses; -use App\Http\Requests\Request; -use App\Models\FileManager\Directory; use App\Models\FileManager\File; use App\Models\User; -use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; -use Illuminate\Support\Facades\App; -use Illuminate\Support\Facades\DB; -use Mcamara\LaravelLocalization\Facades\LaravelLocalization; use Modules\Categories\Entities\Category; /** @@ -20,7 +13,7 @@ use Modules\Categories\Entities\Category; */ class Content extends Model { - use SoftDeletes; + use SoftDeletes, ModelTraits\Content; public $timestamps = true; protected $fillable = [ 'user_id', @@ -41,101 +34,9 @@ class Content extends Model 'module_settings', 'status' ]; - protected $guarded = []; - protected $foundSubpages = []; - protected $subpagesInit = false; const STATUS_DRAFT = 'draft'; const STATUS_PROTECTED = 'protected'; const STATUS_PUBLIC = 'public'; - /** - * @var File - */ - private $file; - - public function __construct(array $attributes = []) - { - parent::__construct($attributes); - - $this->file = App::make(File::class); - } - - /** - * Getter for query with setup filter for non-deleted and non-draft pages - */ - public function getPageQuery() - { - return Content::where('status', '!=', Content::STATUS_DRAFT) - ->select('contents.*') - ->with('author') - ->join('modules', 'modules.handler', '=', 'contents.module_handler') - ->where(function ($query) { - $query->where('published_from', '<', Carbon::now()) - ->orWhereNull('published_from'); - }) - ->where(function ($query) { - $query->where('published_to', '>', Carbon::now()) - ->orWhereNull('published_to'); - }) - ->where('language', LaravelLocalization::getCurrentLocale()) - ->where('modules.enabled', true); - } - - /** - * Getter for homepage content page - * @return Content - */ - public function getHomepage() - { - return $this->getPageQuery() - ->where('is_homepage', 1) - ->first(); - } - - /** - * Getter for any page specified by its url. - * - * @param $url - * - * @return Content - */ - public function getByURL($url) - { - return $this->getPageQuery() - ->where('url', $url) - ->first(); - } - - /** - * 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; - } /** * Is current content draft? @@ -177,231 +78,6 @@ class Content extends Model return $this->isPublic() || $this->isProtected(); } - /** - * 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(); - } - - /** - * Getter for overview of all content pages. - * These content pages may be filtered by using some handler - * - * @param bool $handler - * @param bool $status - * @param bool $joinAuthor - * @param bool $joinParent - * - * @return - */ - public function getOverview($handler = false, $status = false, $joinAuthor = false, $joinParent = false) - { - $query = DB::table('contents') - ->select('contents.*', 'modules.name AS module_name', 'modules.id AS module_id') - ->join('modules', 'modules.handler', '=', 'contents.module_handler') - ->whereNull('contents.deleted_at') - ->where('contents.language', LaravelLocalization::getCurrentLocale()) - ->where('modules.enabled', 1) - ->orderBy('created_at', 'DESC'); - - // filter results using handler - if ($handler) { - $query = $query->where('contents.module_handler', $handler); - } - - // join user email and user name to results when needed - if ($joinAuthor) { - $query = $query->join('users', 'users.id', '=', 'contents.user_id') - ->addSelect(DB::raw('COALESCE(users.name, users.email) AS author_name')) - ->addSelect('users.email AS author_email'); - } - - if ($joinParent) { - $query = $query->leftJoin('contents as parent', 'parent.id', '=', 'contents.parent_id') - ->addSelect('parent.title AS parent_title') - ->addSelect('parent.url AS parent_url'); - } - - // add filtering by status - if (in_array($status, ContentStatuses::getSimple())) { - $query = $query->where('contents.status', $status); - } - - return $query; - } - - /** - * 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 - * - * @return int - */ - public function uploadRelatedFiles(Request $request, $revisionId = null) - { - $files = $request->all()['files']; - $changed = 0; - - // check if any file was removed - if ($revisionId) { - $changed += $this->removeRelatedFiles($revisionId, $request); - } - - // allow uploading only on created pages - if (!$this->id || !$files[0]) { - return $changed; - } - - // find or create new directory for files assigned to content - $directory = Directory::firstOrCreate([ - 'name' => '.content_files', - 'hidden' => true - ]); - $request->directoryId = $directory->id; - - foreach ($files as $file) { - if (!$file) { - continue; - } - $uploaded = $this->file->upload($file, $request); - - // add assignement - ContentHasFile::create([ - 'file_id' => $uploaded['id'], - 'content_id' => $this->id - ]); - - if ($revisionId) { - $this->saveHistory($revisionId, 'file', null, ['file' => $uploaded['file']->getClientOriginalName()]); - } - - $changed++; - } - - return $changed; - } - - /** - * Delete files from association - * - * @param $revisionId - * @param $request - * - * @return int - */ - private function removeRelatedFiles($revisionId, $request) - { - $files = array_keys((array)$request->keepAssigned); - - $allFiles = $this->files() - ->whereNotIn('id', $files) - ->get(); - - foreach ($allFiles as $file) { - $this->saveHistory($revisionId, 'file', $file->original_filename, ['file' => null]); - - ContentHasFile::where('content_id', $this->id) - ->where('file_id', $file->id) - ->delete(); - } - - return count($allFiles); - } - /** * Mark relationship with its historical records * @@ -436,35 +112,4 @@ class Content extends Model { return $this->belongsTo(Category::class); } - - /** - * 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->timestamps = false; - $this->viewed++; - $this->save(); - $this->timestamps = true; - } } diff --git a/app/Models/Content/ContentHasFile.php b/app/Models/Content/ContentHasFile.php index 351b80c4..688f35e1 100644 --- a/app/Models/Content/ContentHasFile.php +++ b/app/Models/Content/ContentHasFile.php @@ -6,7 +6,6 @@ use Illuminate\Database\Eloquent\Model; class ContentHasFile extends Model { - public $timestamps = false; public $table = 'contents_has_files'; diff --git a/app/Models/Content/ContentHistory.php b/app/Models/Content/ContentHistory.php index 3e01ef4a..dca25307 100644 --- a/app/Models/Content/ContentHistory.php +++ b/app/Models/Content/ContentHistory.php @@ -2,9 +2,6 @@ namespace App\Models\Content; -use App\CMS\Handlers\Contracts\AppHandler; -use App\CMS\Handlers\Contracts\HistoryHandler; -use App\CMS\Helpers\Differ; use Illuminate\Database\Eloquent\Model; /** @@ -12,6 +9,7 @@ use Illuminate\Database\Eloquent\Model; */ class ContentHistory extends Model { + use ModelTraits\ContentHistory; protected $table = 'content_history'; // this table does not have created_at and updated_at fields public $timestamps = false; @@ -24,77 +22,4 @@ class ContentHistory extends Model 'old_value' ]; protected $guarded = []; - - /** - * Returns history grouped by revisions (edit_batches) - * - * @param Content $content - * - * @return array - */ - public function getStructuredHistoryOf(Content $content) - { - $data = $content->history() - ->select('content_history.*', 'contents.module_handler', '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') - ->get(); - - $info = []; - $history = []; - foreach ($data as $change) { - $info[$change->edit_batch] = [ - 'changed_at' => $change->changed_at, - 'user' => [ - 'id' => $change->user_id, - 'name' => $change->user_name, - 'email' => $change->user_email - ] - ]; - - $change = $this->handleChangeset($change); - - $history[$change->edit_batch][] = $change; - } - - return [ - 'changesets' => $history, - 'info' => $info - ]; - } - - /** - * Getter for history handler of given module - * - * @param $change - * - * @return HistoryHandler - */ - protected function getHistoryHandler($change) - { - /** - * @var $handler AppHandler - */ - - // get handler of given content page - $handler = $change->module_handler; - - return $handler::getHistoryHandler(); - } - - public function handleChangeset($change) - { - $historyHandler = $this->getHistoryHandler($change); - - $change->column_trans = $historyHandler::parseColumnName($change->column); - $change->diff = $historyHandler::parseChangedValue($change); - - return $change; - } - - public function getDiff($change) - { - return Differ::htmlDiff(e($change->old_value), e($change->new_value)); - } } \ No newline at end of file diff --git a/app/Models/Content/ModelTraits/Content.php b/app/Models/Content/ModelTraits/Content.php new file mode 100644 index 00000000..ea75297d --- /dev/null +++ b/app/Models/Content/ModelTraits/Content.php @@ -0,0 +1,360 @@ +file = App::make(File::class); + } + + /** + * Getter for query with setup filter for non-deleted and non-draft pages + */ + public function getPageQuery() + { + return ContentModel::where('status', '!=', ContentModel::STATUS_DRAFT) + ->select('contents.*') + ->with('author') + ->join('modules', 'modules.handler', '=', 'contents.module_handler') + ->where(function ($query) { + $query->where('published_from', '<', Carbon::now()) + ->orWhereNull('published_from'); + }) + ->where(function ($query) { + $query->where('published_to', '>', Carbon::now()) + ->orWhereNull('published_to'); + }) + ->where('language', LaravelLocalization::getCurrentLocale()) + ->where('modules.enabled', true); + } + + /** + * Getter for homepage content page + * @return Content + */ + public function getHomepage() + { + return $this->getPageQuery() + ->where('is_homepage', 1) + ->first(); + } + + /** + * Getter for any page specified by its url. + * + * @param $url + * + * @return Content + */ + public function getByURL($url) + { + return $this->getPageQuery() + ->where('url', $url) + ->first(); + } + + /** + * 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(); + } + + /** + * Getter for overview of all content pages. + * These content pages may be filtered by using some handler + * + * @param bool $handler + * @param bool $status + * @param bool $joinAuthor + * @param bool $joinParent + * + * @return + */ + public function getOverview($handler = false, $status = false, $joinAuthor = false, $joinParent = false) + { + $query = DB::table('contents') + ->select('contents.*', 'modules.name AS module_name', 'modules.id AS module_id') + ->join('modules', 'modules.handler', '=', 'contents.module_handler') + ->whereNull('contents.deleted_at') + ->where('contents.language', LaravelLocalization::getCurrentLocale()) + ->where('modules.enabled', 1) + ->orderBy('created_at', 'DESC'); + + // filter results using handler + if ($handler) { + $query = $query->where('contents.module_handler', $handler); + } + + // join user email and user name to results when needed + if ($joinAuthor) { + $query = $query->join('users', 'users.id', '=', 'contents.user_id') + ->addSelect(DB::raw('COALESCE(users.name, users.email) AS author_name')) + ->addSelect('users.email AS author_email'); + } + + if ($joinParent) { + $query = $query->leftJoin('contents as parent', 'parent.id', '=', 'contents.parent_id') + ->addSelect('parent.title AS parent_title') + ->addSelect('parent.url AS parent_url'); + } + + // add filtering by status + if (in_array($status, ContentStatuses::getSimple())) { + $query = $query->where('contents.status', $status); + } + + return $query; + } + + /** + * 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 + * + * @return int + */ + public function uploadRelatedFiles(Request $request, $revisionId = null) + { + $files = $request->all()['files']; + $changed = 0; + + // check if any file was removed + if ($revisionId) { + $changed += $this->removeRelatedFiles($revisionId, $request); + } + + // allow uploading only on created pages + if (!$this->id || !$files[0]) { + return $changed; + } + + // find or create new directory for files assigned to content + $directory = Directory::firstOrCreate([ + 'name' => '.content_files', + 'hidden' => true + ]); + $request->directoryId = $directory->id; + + foreach ($files as $file) { + if (!$file) { + continue; + } + $uploaded = $this->file->upload($file, $request); + + // add assignement + ContentHasFile::create([ + 'file_id' => $uploaded['id'], + 'content_id' => $this->id + ]); + + if ($revisionId) { + $this->saveHistory($revisionId, 'file', null, ['file' => $uploaded['file']->getClientOriginalName()]); + } + + $changed++; + } + + return $changed; + } + + /** + * Delete files from association + * + * @param $revisionId + * @param $request + * + * @return int + */ + private function removeRelatedFiles($revisionId, $request) + { + $files = array_keys((array)$request->keepAssigned); + + $allFiles = $this->files() + ->whereNotIn('id', $files) + ->get(); + + foreach ($allFiles as $file) { + $this->saveHistory($revisionId, 'file', $file->original_filename, ['file' => null]); + + ContentHasFile::where('content_id', $this->id) + ->where('file_id', $file->id) + ->delete(); + } + + 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->timestamps = false; + $this->viewed++; + $this->save(); + $this->timestamps = true; + } +} \ No newline at end of file diff --git a/app/Models/Content/ModelTraits/ContentHistory.php b/app/Models/Content/ModelTraits/ContentHistory.php new file mode 100644 index 00000000..ee852408 --- /dev/null +++ b/app/Models/Content/ModelTraits/ContentHistory.php @@ -0,0 +1,83 @@ +history() + ->select('content_history.*', 'contents.module_handler', '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') + ->get(); + + $info = []; + $history = []; + foreach ($data as $change) { + $info[$change->edit_batch] = [ + 'changed_at' => $change->changed_at, + 'user' => [ + 'id' => $change->user_id, + 'name' => $change->user_name, + 'email' => $change->user_email + ] + ]; + + $change = $this->handleChangeset($change); + + $history[$change->edit_batch][] = $change; + } + + return [ + 'changesets' => $history, + 'info' => $info + ]; + } + + /** + * Getter for history handler of given module + * + * @param $change + * + * @return HistoryHandler + */ + protected function getHistoryHandler($change) + { + /** + * @var $handler AppHandler + */ + + // get handler of given content page + $handler = $change->module_handler; + + return $handler::getHistoryHandler(); + } + + public function handleChangeset($change) + { + $historyHandler = $this->getHistoryHandler($change); + + $change->column_trans = $historyHandler::parseColumnName($change->column); + $change->diff = $historyHandler::parseChangedValue($change); + + return $change; + } + + public function getDiff($change) + { + return Differ::htmlDiff(e($change->old_value), e($change->new_value)); + } +} \ No newline at end of file diff --git a/app/Models/FileManager/Directory.php b/app/Models/FileManager/Directory.php index b701e19b..ba52b4bc 100644 --- a/app/Models/FileManager/Directory.php +++ b/app/Models/FileManager/Directory.php @@ -17,7 +17,6 @@ class Directory extends Model 'user_id', 'hidden' ]; - protected $guarded = []; /** * Relationship with parent/sub directories diff --git a/app/Models/FileManager/File.php b/app/Models/FileManager/File.php index b93cae9a..3f4f8156 100644 --- a/app/Models/FileManager/File.php +++ b/app/Models/FileManager/File.php @@ -2,23 +2,15 @@ namespace App\Models\FileManager; -use App\Events\UploadFile; -use App\Http\Requests\Request; -use Franzose\ClosureTable\Extensions\Str; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\Auth; -use Illuminate\Support\Facades\Event; -use Illuminate\Support\Facades\File as FileFacade; -use Intervention\Image\Constraint; -use Intervention\Image\Facades\Image; -use Symfony\Component\HttpFoundation\File\File as SymphonyFile; -use Symfony\Component\HttpFoundation\File\UploadedFile; +use Illuminate\Queue\SerializesModels; /** * Class File */ class File extends Model { + use SerializesModels, ModelTraits\File; /** * Hash algorithm used for hashing file */ @@ -32,125 +24,17 @@ class File extends Model 'original_filename', 'description', 'keywords', - 'directory' + 'directory_id', + 'user_id', + 'file_size', + 'mime_type', + 'hash_algorith', + 'name', + 'file_size' ]; - protected $guarded = []; - /** - * Getter for filename of uploaded file. - * - * This filename is used for localy stored file. - * - * @param UploadedFile $file - * - * @return string - */ - public function getFilename(UploadedFile $file) + public function directory() { - return uniqid() . '.' . $file->getClientOriginalExtension(); - } - - /** - * Saves file into FS and creates new record in database - * - * @param UploadedFile $file - * @param Request $request - * - * @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) - { - $destination = config('app.upload_path'); - $filename = $this->getFilename($file); - - // save file into physical location (local FS) - $uploadedFile = $file->move($destination, $filename); - - // is uploaded file an image? - if (Str::startsWith($uploadedFile->getMimeType(), 'image')) { - // yes, create thumbnail - $this->createThumbnail($uploadedFile); - } - - // insert record into database - $id = $this->saveIntoDatabase($uploadedFile, $request, $file->getClientOriginalName()); - - // fire event about new file - Event::fire(new UploadFile($uploadedFile, $id)); - - return [ - 'filename' => $filename, - 'file' => $file, - 'id' => $id - ]; - } - - /** - * Save file into database - * - * 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 $originalFilename - * - * @return mixed - */ - protected function saveIntoDatabase(SymphonyFile $file, Request $request, $originalFilename) - { - // get path and hash of uploaded file - $path = config('app.upload_path') . DIRECTORY_SEPARATOR . $file->getFilename(); - $hash = hash_file(self::HASH_ALGORITHM, $path); - - // define mandatory fields - $newFile = new File(); - $newFile->user_id = Auth::user()->id; - $newFile->filename = $file->getFilename(); - $newFile->original_filename = $originalFilename; - $newFile->file_hash = $hash; - $newFile->hash_algorithm = self::HASH_ALGORITHM; - $newFile->mime_type = $file->getMimeType(); - $newFile->file_size = $file->getSize(); - - // save optional fields - $optionalFields = ['name', 'description', 'keywords', 'directoryId']; - foreach ($optionalFields as $field) { - if (isset($request->{$field}) && !empty($request->{$field})) { - - $snakeField = snake_case($field); - $newFile->$snakeField = $request->$field; - } - } - - // create new database row - $newFile->save(); - - return $newFile->id; - } - - /** - * Create thumbnail of given image - * - * @param SymphonyFile $file - */ - private function createThumbnail(SymphonyFile $file) - { - // does thumbnail directory exist? - if (!is_dir(config('app.thumbnail_path'))) { - FileFacade::makeDirectory(config('app.thumbnail_path')); - } - - // get image instance - $image = Image::make(config('app.upload_path') . DIRECTORY_SEPARATOR . $file->getFilename()); - - // resize image and keep aspect ration - $image->resize(env('THUMBNAIL_WIDTH', 300), null, function (Constraint $constraint) { - $constraint->aspectRatio(); - $constraint->upsize(); - }); - - // save thumbnail with lower quality - $image->save(config('app.thumbnail_path') . DIRECTORY_SEPARATOR . $file->getFilename(), 75); + return $this->belongsTo(Directory::class, 'directory_id'); } } \ No newline at end of file diff --git a/app/Models/FileManager/ModelTraits/File.php b/app/Models/FileManager/ModelTraits/File.php new file mode 100644 index 00000000..ec2c9641 --- /dev/null +++ b/app/Models/FileManager/ModelTraits/File.php @@ -0,0 +1,128 @@ +getClientOriginalExtension(); + } + + /** + * Saves file into FS and creates new record in database + * + * @param UploadedFile $file + * @param Request $request + * + * @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) + { + $destination = config('app.upload_path'); + $filename = $this->getFilename($file); + + // save file into physical location (local FS) + $uploadedFile = $file->move($destination, $filename); + + // is uploaded file an image? + if (Str::startsWith($uploadedFile->getMimeType(), 'image')) { + // yes, create thumbnail + $this->createThumbnail($uploadedFile); + } + + // insert record into database + $id = $this->saveIntoDatabase($uploadedFile, $request, $file->getClientOriginalName()); + + // fire event about new file + Event::fire(new UploadFile($uploadedFile, $id)); + + return [ + 'filename' => $filename, + 'file' => $file, + 'id' => $id + ]; + } + + /** + * Save file into database + * + * 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 $originalFilename + * + * @return mixed + */ + protected function saveIntoDatabase(SymphonyFile $file, Request $request, $originalFilename) + { + // get path and hash of uploaded file + $path = config('app.upload_path') . DIRECTORY_SEPARATOR . $file->getFilename(); + $hash = hash_file(FileModel::HASH_ALGORITHM, $path); + + // define mandatory fields + $newFile = FileModel::create([ + 'user_id' => Auth::user()->id, + 'filename' => $file->getFilename(), + 'original_filename' => $originalFilename, + 'file_hash' => $hash, + 'hash_algorithm' => FileModel::HASH_ALGORITHM, + 'mime_type' => $file->getMimeType(), + 'file_size' => $file->getSize(), + 'name' => $request->name, + 'description' => $request->description, + 'directory_id' => $request->directoryId, + 'keywords' => $request->keywords + ]); + + return $newFile->id; + } + + /** + * Create thumbnail of given image + * + * @param SymphonyFile $file + */ + private function createThumbnail(SymphonyFile $file) + { + // does thumbnail directory exist? + if (!is_dir(config('app.thumbnail_path'))) { + FileFacade::makeDirectory(config('app.thumbnail_path')); + } + + // get image instance + $image = Image::make(config('app.upload_path') . DIRECTORY_SEPARATOR . $file->getFilename()); + + // resize image and keep aspect ration + $image->resize(env('THUMBNAIL_WIDTH', 300), null, function (Constraint $constraint) { + $constraint->aspectRatio(); + $constraint->upsize(); + }); + + // save thumbnail with lower quality + $image->save(config('app.thumbnail_path') . DIRECTORY_SEPARATOR . $file->getFilename(), 75); + } +} \ No newline at end of file diff --git a/app/Models/Language.php b/app/Models/Language.php index 2cef168a..151ae1e9 100644 --- a/app/Models/Language.php +++ b/app/Models/Language.php @@ -14,5 +14,4 @@ class Language extends Model 'script', 'native' ]; - protected $guarded = []; } \ No newline at end of file diff --git a/app/Models/ModelTraits/Module.php b/app/Models/ModelTraits/Module.php new file mode 100644 index 00000000..938f3b73 --- /dev/null +++ b/app/Models/ModelTraits/Module.php @@ -0,0 +1,108 @@ +has_submodules = true; + $parentModule->save(); + } + + // insert module into database + $module = Module::create([ + 'name' => $name, + 'description' => $description, + 'handler' => $handler, + 'manages_content' => $managesContent, + 'support_categories' => $supportCategories, + 'alias' => $alias, + 'module_settings' => json_encode($settings), + 'parent_id' => $parentModuleId ? $parentModuleId : null, + 'enabled' => 1, + 'is_template' => $isTemplate + ]); + + // install something module-specific + if ($handler) { + call_user_func([$handler, 'install']); + } + + return $module; + } + + /** + * Delete module from database and uninstall its dependencies + * + * @throws \ErrorException + */ + public function uninstall() + { + // check if user does not want to install module in runtime + if (!App::runningInConsole()) { + throw new \ErrorException('Modules can be uninstalled only via Artisan!'); + } + + // delete everything in /resources/views/visitor + if ($this->is_template) { + $this->deleteDirectory(resource_path('views/visitor')); + $this->deleteDirectory(resource_path('views/modules')); + $this->deleteDirectory(public_path('assets')); + + // delete all template paths + TemplatePath::getQuery()->delete(); + } + + if ($this->handler && is_callable([$this->handler, 'uninstall'])) { + call_user_func([$this->handler, 'uninstall'], $this); + } + + $this->delete(); + } + + /** + * Delete directory when uninstalling module. + * + * @param $directory + * + * @throws \ErrorException + */ + private function deleteDirectory($directory) + { + if (!is_dir($directory)) + return; + + $success = \File::deleteDirectory($directory, true); + + if (!$success) { + throw new \ErrorException('Cannot delete ' . $directory); + } + } +} \ No newline at end of file diff --git a/app/Models/ModelTraits/Settings.php b/app/Models/ModelTraits/Settings.php new file mode 100644 index 00000000..841c6125 --- /dev/null +++ b/app/Models/ModelTraits/Settings.php @@ -0,0 +1,86 @@ +where('language', LaravelLocalization::getCurrentLocale()) + ->orWhere('language', null) + ->orderBy('language', 'ASC'); + } + + /** + * Load all settings + * + * @return \stdClass + */ + public function getAll() + { + $settings = $this->getSettingsQuery() + ->get(); + + return $this->returnPairs($settings); + } + + /** + * Get all settings with language info + * + * @return \stdClass + */ + public function getAllWithLanguage() + { + $settings = $this->getSettingsQuery() + ->get(); + + $data = new \stdClass(); + foreach ($settings as $conf) { + $data->{$conf->key} = [ + 'val' => $conf->value, + 'lang' => $conf->language + ]; + } + + return $data; + } + + /** + * Load only config for views + * + * @return \stdClass + */ + public function getForView() + { + $settings = $this->getSettingsQuery() + ->where('load_into_views', 1) + ->get(); + + return $this->returnPairs($settings); + } + + /** + * From pair create object key => value + * + * @param $settings + * + * @return \stdClass + */ + private function returnPairs($settings) + { + $data = new \stdClass(); + foreach ($settings as $conf) { + $data->{$conf->key} = $conf->value; + } + + return $data; + } +} \ No newline at end of file diff --git a/app/Models/Module.php b/app/Models/Module.php index d90c9b62..f6940aad 100644 --- a/app/Models/Module.php +++ b/app/Models/Module.php @@ -2,15 +2,14 @@ namespace App\Models; -use App\CMS\Handlers\Contracts\TemplateHandler; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\App; /** * Class Module */ class Module extends Model { + use ModelTraits\Module; public $timestamps = false; protected $fillable = [ 'handler', @@ -24,105 +23,4 @@ class Module extends Model 'manages_content', 'is_template' ]; - protected $guarded = []; - - /** - * Create new module in database - * - * @param $name - * @param $alias - * @param string $description - * @param null $handler - * @param $parentModuleId - * @param array $settings - * - * @return Module - * @throws \ErrorException - */ - public static function install($name, $alias, $description, $handler, $parentModuleId, $settings) - { - // check if user does not want to install module in runtime - if (!App::runningInConsole()) { - throw new \ErrorException('Modules can be installed only via Artisan!'); - } - - $managesContent = $handler ? in_array('App\CMS\Handlers\Contracts\AppHandler', class_implements($handler)) : false; - $isTemplate = $handler ? in_array(TemplateHandler::class, class_implements($handler)) : false; - $supportCategories = $managesContent ? call_user_func([$handler, 'supportCategories']) : false; - - if ($parentModuleId) { - $parentModule = Module::findOrFail($parentModuleId); - $parentModule->has_submodules = true; - $parentModule->save(); - } - - // insert module into database - $module = Module::create([ - 'name' => $name, - 'description' => $description, - 'handler' => $handler, - 'manages_content' => $managesContent, - 'support_categories' => $supportCategories, - 'alias' => $alias, - 'module_settings' => json_encode($settings), - 'parent_id' => $parentModuleId ? $parentModuleId : null, - 'enabled' => 1, - 'is_template' => $isTemplate - ]); - - // install something module-specific - if ($handler) { - call_user_func([$handler, 'install']); - } - - return $module; - } - - /** - * Delete module from database and uninstall its dependencies - * - * @throws \ErrorException - */ - public function uninstall() - { - // check if user does not want to install module in runtime - if (!App::runningInConsole()) { - throw new \ErrorException('Modules can be uninstalled only via Artisan!'); - } - - // delete everything in /resources/views/visitor - if ($this->is_template) { - $this->deleteDirectory(resource_path('views/visitor')); - $this->deleteDirectory(resource_path('views/modules')); - $this->deleteDirectory(public_path('assets')); - - // delete all template paths - TemplatePath::getQuery()->delete(); - } - - if ($this->handler && is_callable([$this->handler, 'uninstall'])) { - call_user_func([$this->handler, 'uninstall'], $this); - } - - $this->delete(); - } - - /** - * Delete directory when uninstalling module. - * - * @param $directory - * - * @throws \ErrorException - */ - private function deleteDirectory($directory) - { - if (!is_dir($directory)) - return; - - $success = \File::deleteDirectory($directory, true); - - if (!$success) { - throw new \ErrorException('Cannot delete ' . $directory); - } - } } \ No newline at end of file diff --git a/app/Models/Settings.php b/app/Models/Settings.php index 83691ee8..5ab99456 100644 --- a/app/Models/Settings.php +++ b/app/Models/Settings.php @@ -7,85 +7,9 @@ use Mcamara\LaravelLocalization\Facades\LaravelLocalization; class Settings extends Model { + use ModelTraits\Settings; + protected $table = 'settings'; public $timestamps = false; protected $fillable = ['key', 'value', 'language']; - - /** - * Prepares common query for selecting settings - * - * @return mixed - */ - protected function getSettingsQuery() - { - return Settings::select(['key', 'value', 'language']) - ->where('language', LaravelLocalization::getCurrentLocale()) - ->orWhere('language', null) - ->orderBy('language', 'ASC'); - } - - /** - * Load all settings - * - * @return \stdClass - */ - public function getAll() - { - $settings = $this->getSettingsQuery() - ->get(); - - return $this->returnPairs($settings); - } - - /** - * Get all settings with language info - * - * @return \stdClass - */ - public function getAllWithLanguage() - { - $settings = $this->getSettingsQuery() - ->get(); - - $data = new \stdClass(); - foreach ($settings as $conf) { - $data->{$conf->key} = [ - 'val' => $conf->value, - 'lang' => $conf->language - ]; - } - - return $data; - } - - /** - * Load only config for views - * - * @return \stdClass - */ - public function getForView() - { - $settings = $this->getSettingsQuery() - ->where('load_into_views', 1) - ->get(); - - return $this->returnPairs($settings); - } - - /** - * From pair create object key => value - * - * @param $settings - * - * @return \stdClass - */ - private function returnPairs($settings) - { - $data = new \stdClass(); - foreach ($settings as $conf) { - $data->{$conf->key} = $conf->value; - } - - return $data; - } } diff --git a/app/Models/Templates/ModelTraits/Template.php b/app/Models/Templates/ModelTraits/Template.php new file mode 100644 index 00000000..769bb01a --- /dev/null +++ b/app/Models/Templates/ModelTraits/Template.php @@ -0,0 +1,78 @@ +pathModel) { + $this->pathModel = TemplatePath::where('id', $this->path) + ->first(); + } + + return $this->pathModel; + } + + /** + * Getter for absolute path to template + * + * @param null $mode + * + * @return string + */ + public function getPathToTemplate($mode = null) + { + $templateName = $this->template_name; + $path = $this->getPath(); + + // delete namespace if given + if (strpos($this->template_name, '::')) { + list(, $templateName) = explode('::', $templateName); + } + + // get template name, do not care about directories (they are already contained in path) + $parts = explode('.', $templateName); + $templateName = last($parts); + + // just a shortcut for this unbelievable long constant name... + $_ = DIRECTORY_SEPARATOR; + + // path parts + $absolutePath = base_path($path->path); + $templatePath = str_replace('.', $_, $templateName); + $file = $templatePath . TemplateModel::TEMPLATE_SUFFIX; + + // compose two versions of path - original and with "custom" directory + $original = $absolutePath . $_ . $file; + $edited = $absolutePath . $_ . TemplateModel::EDITED_TEMPLATES_DIRECTORY . $_ . $file; + + // decide which path will be returned + switch ($mode) { + case TemplateModel::CUSTOM_EDIT_DIRECTORY: + return $edited; + break; + + case TemplateModel::ORIGINAL_DIRECTORY: + return $original; + break; + + default: + if (file_exists($absolutePath . $_ . TemplateModel::EDITED_TEMPLATES_DIRECTORY . $_ . $file)) { + return $edited; + } + + return $original; + break; + } + } +} \ No newline at end of file diff --git a/app/Models/Templates/Template.php b/app/Models/Templates/Template.php index 81370bbf..ed43dd63 100644 --- a/app/Models/Templates/Template.php +++ b/app/Models/Templates/Template.php @@ -1,14 +1,12 @@ pathModel) { - - $this->pathModel = TemplatePath::where('id', $this->path) - ->first(); - } - - return $this->pathModel; - } - - /** - * Getter for absolute path to template - * - * @param null $mode - * - * @return string - */ - public function getPathToTemplate($mode = null) - { - $templateName = $this->template_name; - $path = $this->getPath(); - - // delete namespace if given - if (strpos($this->template_name, '::')) { - list(, $templateName) = explode('::', $templateName); - } - - // get template name, do not care about directories (they are already contained in path) - $parts = explode('.', $templateName); - $templateName = last($parts); - - // just a shortcut for this unbelievable long constant name... - $_ = DIRECTORY_SEPARATOR; - - // path parts - $absolutePath = base_path($path->path); - $templatePath = str_replace('.', $_, $templateName); - $file = $templatePath . self::TEMPLATE_SUFFIX; - - // compose two versions of path - original and with "custom" directory - $original = $absolutePath . $_ . $file; - $edited = $absolutePath . $_ . self::EDITED_TEMPLATES_DIRECTORY . $_ . $file; - - // decide which path will be returned - switch ($mode) { - case self::CUSTOM_EDIT_DIRECTORY: - return $edited; - break; - - case self::ORIGINAL_DIRECTORY: - return $original; - break; - - default: - if (file_exists($absolutePath . $_ . self::EDITED_TEMPLATES_DIRECTORY . $_ . $file)) { - return $edited; - } - - return $original; - break; - } - } } \ No newline at end of file diff --git a/app/Models/Templates/TemplatePath.php b/app/Models/Templates/TemplatePath.php index 68337c6a..2fec2de6 100644 --- a/app/Models/Templates/TemplatePath.php +++ b/app/Models/Templates/TemplatePath.php @@ -1,6 +1,6 @@ hasMany('App\Models\Template', 'path'); + return $this->hasMany(Template::class, 'path'); } /** @@ -30,6 +34,6 @@ class TemplatePath extends Model */ public function subdirectories() { - return $this->hasMany('App\Models\TemplatePath', 'parent_id'); + return $this->hasMany(TemplatePath::class, 'parent_id'); } } \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php index 127b4bd3..9af1a4c3 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -22,7 +22,6 @@ class User extends Model implements AuthenticableInterface 'password', 'name', ]; - protected $guarded = []; /** * The attributes excluded from the model's JSON form. * @@ -38,18 +37,4 @@ class User extends Model implements AuthenticableInterface const ROLE_VISITOR = 'visitor'; const ROLE_EDITOR = 'editor'; const ROLE_ADMIN = 'admin'; - - /** - * Getter for Gravatar URL - * - * This method returns full path (url) to user's Gravatar. It accepts optional parameter for setting size. - * - * @param int $size size of rendered gravatar - * - * @return string - */ - public function gravatar($size = 50) - { - return Gravatar::img($this->email, $size); - } } diff --git a/app/Models/Widgets/ModelTraits/Widget.php b/app/Models/Widgets/ModelTraits/Widget.php new file mode 100644 index 00000000..82f1c263 --- /dev/null +++ b/app/Models/Widgets/ModelTraits/Widget.php @@ -0,0 +1,41 @@ +handler, 'save'], $request); + + // create new widget + $widget = WidgetModel::create([ + 'widget_type_handler' => $widgetType->handler, + 'language' => LaravelLocalization::getCurrentLocale(), + 'user_id' => \Auth::user()->id, + 'name' => $request->name, + 'container_class' => $request->containerClass, + 'container_id' => empty($request->containerId) ? null : $request->containerId, + 'description' => $request->description, + 'settings' => json_encode($settings), + ]); + + // fire event with newly created widget + \Event::fire(new CreateNewWidget($widget)); + + return $widget; + } +} \ No newline at end of file diff --git a/app/Models/Widgets/ModelTraits/WidgetArea.php b/app/Models/Widgets/ModelTraits/WidgetArea.php new file mode 100644 index 00000000..f457fb35 --- /dev/null +++ b/app/Models/Widgets/ModelTraits/WidgetArea.php @@ -0,0 +1,24 @@ +join('widget_in_widget_area', 'widget_in_widget_area.widget_id', '=', 'widgets.id') + ->join('widget_areas', 'widget_in_widget_area.widget_area_id', '=', 'widget_areas.id') + ->where('language', LaravelLocalization::getCurrentLocale()) + ->orderBy('widget_in_widget_area.position'); + if (!$uniqueCode) { + $widgets = $widgets->where('widget_areas.viewed', '>=', setting('preloadFrequentedWidgetAreasTreshold', 10)); + } else { + $widgets = $widgets->where('code', $uniqueCode); + } + + return $widgets; + } +} \ No newline at end of file diff --git a/app/Models/Widgets/ModelTraits/WidgetInWidgetArea.php b/app/Models/Widgets/ModelTraits/WidgetInWidgetArea.php new file mode 100644 index 00000000..96c608bb --- /dev/null +++ b/app/Models/Widgets/ModelTraits/WidgetInWidgetArea.php @@ -0,0 +1,20 @@ +get(); + + $ids = []; + foreach ($models as $model) { + $ids[] = $model->widget_id; + } + + return $ids; + } +} \ No newline at end of file diff --git a/app/Models/Widgets/Widget.php b/app/Models/Widgets/Widget.php index 93569e26..fdb27d56 100644 --- a/app/Models/Widgets/Widget.php +++ b/app/Models/Widgets/Widget.php @@ -22,45 +22,4 @@ class Widget extends Model 'viewed', 'deletable' ]; - protected $guarded = []; - - /** - * Create new widget of given type - * - * @param WidgetType $widgetType - * @param $data - * - * @return Widget - */ - public function createNew(WidgetType $widgetType, $data) - { - // convert array or whatever into object - if (!is_object($data)) { - $data = (object)$data; - } - - // create new widget - $widget = new Widget(); - $widget->widget_type_handler = $widgetType->handler; - $widget->language = LaravelLocalization::getCurrentLocale(); - $widget->user_id = \Auth::user()->id; - $widget->name = $data->name; - $widget->container_class = $data->containerClass; - $widget->container_id = empty($data->containerId) ? null : $data->containerId; - - // save description if available - if (isset($data->description)) { - $widget->description = $data->description; - } - - $widget = call_user_func([$widgetType->handler, 'save'], $widget, $data); - - // save into database - $widget->save(); - - // fire event with newly created widget - Event::fire(new \App\Events\CreateNewWidget($widget)); - - return $widget; - } } \ No newline at end of file diff --git a/app/Models/Widgets/WidgetArea.php b/app/Models/Widgets/WidgetArea.php index b7e2aadc..2e32cb5b 100644 --- a/app/Models/Widgets/WidgetArea.php +++ b/app/Models/Widgets/WidgetArea.php @@ -3,13 +3,14 @@ namespace App\Models\Widgets; use Illuminate\Database\Eloquent\Model; -use Mcamara\LaravelLocalization\Facades\LaravelLocalization; /** * Class WidgetArea */ class WidgetArea extends Model { + use ModelTraits\WidgetArea; + public $timestamps = false; protected $fillable = [ 'name', @@ -17,21 +18,4 @@ class WidgetArea extends Model 'description', 'deletable' ]; - protected $guarded = []; - - public function getWidgets($uniqueCode = false) - { - $widgets = Widget::select('widgets.*', 'widgets.widget_type_handler', 'widget_areas.code as widget_area_code', 'widgets.name as widget_name', 'widgets.settings') - ->join('widget_in_widget_area', 'widget_in_widget_area.widget_id', '=', 'widgets.id') - ->join('widget_areas', 'widget_in_widget_area.widget_area_id', '=', 'widget_areas.id') - ->where('language', LaravelLocalization::getCurrentLocale()) - ->orderBy('widget_in_widget_area.position'); - if (!$uniqueCode) { - $widgets = $widgets->where('widget_areas.viewed', '>=', setting('preloadFrequentedWidgetAreasTreshold', 10)); - } else { - $widgets = $widgets->where('code', $uniqueCode); - } - - return $widgets; - } } \ No newline at end of file diff --git a/app/Models/Widgets/WidgetInWidgetArea.php b/app/Models/Widgets/WidgetInWidgetArea.php index 4ad03ebd..58574c38 100644 --- a/app/Models/Widgets/WidgetInWidgetArea.php +++ b/app/Models/Widgets/WidgetInWidgetArea.php @@ -9,6 +9,8 @@ use Illuminate\Database\Eloquent\Model; */ class WidgetInWidgetArea extends Model { + use ModelTraits\WidgetInWidgetArea; + protected $table = 'widget_in_widget_area'; public $timestamps = false; protected $fillable = [ @@ -16,18 +18,4 @@ class WidgetInWidgetArea extends Model 'widget_area_id', 'position' ]; - protected $guarded = []; - - public static function getWidgetIdsFromArea($widgetAreaId) - { - $models = WidgetInWidgetArea::where('widget_area_id', $widgetAreaId) - ->get(); - - $ids = []; - foreach ($models as $model) { - $ids[] = $model->widget_id; - } - - return $ids; - } } \ No newline at end of file diff --git a/app/Models/Widgets/WidgetType.php b/app/Models/Widgets/WidgetType.php index 066832af..370d5f61 100644 --- a/app/Models/Widgets/WidgetType.php +++ b/app/Models/Widgets/WidgetType.php @@ -9,7 +9,6 @@ use Illuminate\Database\Eloquent\Model; */ class WidgetType extends Model { - public $timestamps = false; protected $fillable = [ @@ -19,8 +18,4 @@ class WidgetType extends Model 'module_id', 'description' ]; - - protected $guarded = []; - - } \ No newline at end of file diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index f566a0a0..69855239 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -11,7 +11,7 @@ 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\Template; +use App\Models\Templates\Template; use App\CMS\Widgets\HtmlCode\HtmlCode; use App\CMS\Widgets\Menu\Menu; use App\CMS\Widgets\OrbitSlider\OrbitSlider; diff --git a/app/Providers/TemplateServiceProvider.php b/app/Providers/TemplateServiceProvider.php index d090626c..10fbdd71 100644 --- a/app/Providers/TemplateServiceProvider.php +++ b/app/Providers/TemplateServiceProvider.php @@ -4,7 +4,7 @@ namespace App\Providers; use App\CMS\Handlers\Registrators\TemplateRegistrator; use App\CMS\Helpers\CurrentTemplate; -use App\Models\Template; +use App\Models\Templates\Template; use Illuminate\Support\Facades\App; use Illuminate\Support\ServiceProvider; diff --git a/templates/Base/OnePage/Widgets/OnePageMenu/OnePageMenu.php b/templates/Base/OnePage/Widgets/OnePageMenu/OnePageMenu.php index 7b229d25..28f2e46f 100644 --- a/templates/Base/OnePage/Widgets/OnePageMenu/OnePageMenu.php +++ b/templates/Base/OnePage/Widgets/OnePageMenu/OnePageMenu.php @@ -3,8 +3,7 @@ namespace Templates\Base\OnePage\Widgets\OnePageMenu; use App\CMS\Contracts\Widgets\PublicWidget; use App\CMS\Contracts\Widgets\WidgetRenderer; -use App\Models\Widgets\Widget; -use stdClass; +use App\Http\Requests\Request; class OnePageMenu implements PublicWidget { @@ -39,15 +38,12 @@ class OnePageMenu implements PublicWidget } /** - * @param Widget $widget - * @param stdClass $data + * @param Request $data * * @return mixed */ - public static function save(Widget $widget, stdClass $data) + public static function save(Request $data) { - $widget->settings = json_encode([]); - - return $widget; + return []; } }