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_DELETED) ->where('status', '!=', Content::STATUS_DRAFT); } /** * Getter for homepage content page * @return Content */ public function getHomepage() { return $this->getPageQuery() ->where('language', LaravelLocalization::getCurrentLocale()) ->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) ->where('language', LaravelLocalization::getCurrentLocale()) ->first(); } /** * Get list of all subpages * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function subpages() { if (!$this->subpagesInit) { $this->subpages = $this->getPageQuery() ->where('parent_id', $this->id) ->where('language', LaravelLocalization::getCurrentLocale()) ->get(); // convert JSON settings into stdClass foreach ($this->subpages as $subpage) { $subpage->module_settings = json_decode($subpage->module_settings); } $this->subpagesInit = true; } return $this->subpages; } /** * Is current content draft? * * @return bool */ public function isDraft() { return $this->status == self::STATUS_DRAFT; } /** * Is current content visible for all visitors? * * @return bool */ public function isPublic() { return $this->status == self::STATUS_PUBLIC; } /** * Is current content visible only for logged users? * * @return bool */ public function isProtected() { return $this->status == self::STATUS_PROTECTED; } /** * Is current content visible for logged user OR for everyone? * * @return bool */ public function isVisible() { 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('language', LaravelLocalization::getCurrentLocale()) ->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 * * @return */ public function getOverview($handler = false, $status = false, $joinAuthor = false, $joinParent = false) { $query = DB::table('contents') ->select('contents.*', 'modules.name AS module_name') ->where('contents.status', '<>', self::STATUS_DELETED) ->where('contents.language', LaravelLocalization::getCurrentLocale()) ->join('modules', 'modules.handler', '=', 'contents.module_handler') ->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')) { $file = $this->file->upload($request->file('titlePhoto'), $request); $this->title_photo = $file['filename']; } } /** * 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 * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function history() { return $this->hasMany('App\Models\ContentHistory'); } /** * Mark relationship with users table * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function author() { return $this->belongsTo('App\Models\User', 'user_id'); } /** * Related files to content page * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function files() { return $this->belongsToMany(File::class, 'contents_has_files'); } public function category() { 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); } }