FEATURE: move bussiness logic out of models
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace App\CMS\Contracts\Widgets;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Widgets\Widget;
|
||||
|
||||
interface PublicWidget
|
||||
@@ -27,10 +28,11 @@ interface PublicWidget
|
||||
public static function getPresenter();
|
||||
|
||||
/**
|
||||
* @param Widget $widget
|
||||
* @param \stdClass $data
|
||||
* Get widget settings for saving into database
|
||||
*
|
||||
* @return mixed
|
||||
* @param Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function save(Widget $widget, \stdClass $data);
|
||||
public static function save(Request $request);
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace App\CMS\Enumerations;
|
||||
|
||||
use App\Models\TemplatePath;
|
||||
use App\Models\Templates\TemplatePath;
|
||||
|
||||
class TemplatePaths extends BaseEnumeration
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace App\CMS\Enumerations;
|
||||
|
||||
use App\Models\TemplatePath;
|
||||
use App\Models\Templates\TemplatePath;
|
||||
|
||||
class TemplatePathsHumanReadable extends BaseEnumeration
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace App\CMS\Enumerations;
|
||||
|
||||
use App\Models\TemplatePath;
|
||||
use App\Models\Templates\TemplatePath;
|
||||
|
||||
class TemplatePathsHumanReadableRootOnly extends BaseEnumeration
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace App\CMS\Enumerations;
|
||||
|
||||
use App\Models\Template;
|
||||
use App\Models\Templates\Template;
|
||||
|
||||
class Templates extends BaseEnumeration
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@ namespace App\CMS\Handlers\Registrators;
|
||||
|
||||
use App\CMS\Enumerations\TemplatePaths;
|
||||
use App\CMS\Enumerations\Templates;
|
||||
use App\Models\Template;
|
||||
use App\Models\TemplatePath;
|
||||
use App\Models\Templates\Template;
|
||||
use App\Models\Templates\TemplatePath;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Process\Exception\InvalidArgumentException;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
namespace App\CMS\Widgets\HtmlCode;
|
||||
|
||||
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\Widgets\Widget;
|
||||
|
||||
class HtmlCode implements PublicWidget
|
||||
@@ -39,25 +39,17 @@ class HtmlCode implements PublicWidget
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Widget $widget
|
||||
* @param \stdClass $data
|
||||
* @param Request $data
|
||||
*
|
||||
* @return Widget
|
||||
* @return array
|
||||
* @throws MissingParameterException
|
||||
*/
|
||||
public static function save(Widget $widget, \stdClass $data)
|
||||
public static function save(Request $data)
|
||||
{
|
||||
if (!isset($data->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];
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace App\Models\ActionLog\ModelTraits;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
trait ActionLog
|
||||
{
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ContentHasFile extends Model
|
||||
{
|
||||
|
||||
public $timestamps = false;
|
||||
public $table = 'contents_has_files';
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
namespace App\Models\Content\ModelTraits;
|
||||
|
||||
use App\CMS\Enumerations\ContentStatuses;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\FileManager\Directory;
|
||||
use App\Models\FileManager\File;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
|
||||
use App\Models\Content\Content as ContentModel;
|
||||
|
||||
trait Content {
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
private $file;
|
||||
|
||||
protected $foundSubpages = [];
|
||||
protected $subpagesInit = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
namespace App\Models\Content\ModelTraits;
|
||||
|
||||
use App\CMS\Handlers\Contracts\AppHandler;
|
||||
use App\CMS\Handlers\Contracts\HistoryHandler;
|
||||
use App\CMS\Helpers\Differ;
|
||||
use App\Models\Content\Content;
|
||||
|
||||
trait ContentHistory
|
||||
{
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ class Directory extends Model
|
||||
'user_id',
|
||||
'hidden'
|
||||
];
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* Relationship with parent/sub directories
|
||||
|
||||
+11
-127
@@ -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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
trait File
|
||||
{
|
||||
/**
|
||||
* Getter for filename of uploaded file.
|
||||
*
|
||||
* This filename is used for localy stored file.
|
||||
*
|
||||
* @param UploadedFile $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFilename(UploadedFile $file)
|
||||
{
|
||||
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(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);
|
||||
}
|
||||
}
|
||||
@@ -14,5 +14,4 @@ class Language extends Model
|
||||
'script',
|
||||
'native'
|
||||
];
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
namespace App\Models\ModelTraits;
|
||||
|
||||
use App\CMS\Handlers\Contracts\TemplateHandler;
|
||||
use App\Models\Templates\TemplatePath;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
trait Module {
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
namespace App\Models\ModelTraits;
|
||||
|
||||
use App\Models\Settings as SettingsModel;
|
||||
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
|
||||
|
||||
trait Settings
|
||||
{
|
||||
/**
|
||||
* Prepares common query for selecting settings
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getSettingsQuery()
|
||||
{
|
||||
return SettingsModel::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 <key, value> 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;
|
||||
}
|
||||
}
|
||||
+1
-103
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-78
@@ -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 <key, value> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Templates\ModelTraits;
|
||||
|
||||
use App\Models\Templates\TemplatePath;
|
||||
use App\Models\Templates\Template as TemplateModel;
|
||||
|
||||
trait Template {
|
||||
protected $pathModel = null;
|
||||
|
||||
/**
|
||||
* In one path may be many templates
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
if (!$this->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
namespace App\Models\Templates;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Class CustomFieldType
|
||||
*/
|
||||
class Template extends Model
|
||||
{
|
||||
use ModelTraits\Template;
|
||||
public $timestamps = true;
|
||||
protected $fillable = [
|
||||
'template_name',
|
||||
@@ -18,82 +16,10 @@ class Template extends Model
|
||||
'description',
|
||||
'editable'
|
||||
];
|
||||
protected $guarded = [];
|
||||
protected $pathModel = null;
|
||||
const EDITED_TEMPLATES_DIRECTORY = 'custom';
|
||||
const ASSETS_DIRECTORY = 'assets';
|
||||
const MODULES_DIRECTORY = 'modules';
|
||||
|
||||
const TEMPLATE_SUFFIX = '.blade.php';
|
||||
const CUSTOM_EDIT_DIRECTORY = 1;
|
||||
const ORIGINAL_DIRECTORY = 2;
|
||||
|
||||
/**
|
||||
* In one path may be many templates
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
if (!$this->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
namespace App\Models\Templates;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
@@ -10,8 +10,12 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class TemplatePath extends Model
|
||||
{
|
||||
public $timestamps = true;
|
||||
protected $fillable = ['name', 'path', 'parent_id', 'namespace'];
|
||||
protected $guarded = [];
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'path',
|
||||
'parent_id',
|
||||
'namespace'
|
||||
];
|
||||
|
||||
/**
|
||||
* In one path may be many templates
|
||||
@@ -20,7 +24,7 @@ class TemplatePath extends Model
|
||||
*/
|
||||
public function templates()
|
||||
{
|
||||
return $this->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');
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
namespace App\Models\Widgets\ModelTraits;
|
||||
|
||||
use App\Events\CreateNewWidget;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Widgets\Widget as WidgetModel;
|
||||
use App\Models\Widgets\WidgetType;
|
||||
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
|
||||
|
||||
trait Widget
|
||||
{
|
||||
/**
|
||||
* Create new widget of given type
|
||||
*
|
||||
* @param WidgetType $widgetType
|
||||
* @param Request $request
|
||||
*
|
||||
* @return WidgetModel
|
||||
*/
|
||||
public function createNew(WidgetType $widgetType, Request $request)
|
||||
{
|
||||
$settings = call_user_func([$widgetType->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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace App\Models\Widgets\ModelTraits;
|
||||
|
||||
use App\Models\Widgets\Widget;
|
||||
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
|
||||
|
||||
trait WidgetArea
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace App\Models\Widgets\ModelTraits;
|
||||
|
||||
use App\Models\Widgets\WidgetInWidgetArea as WidgetInWidgetAreaModel;
|
||||
|
||||
trait WidgetInWidgetArea
|
||||
{
|
||||
public static function getWidgetIdsFromArea($widgetAreaId)
|
||||
{
|
||||
$models = WidgetInWidgetAreaModel::where('widget_area_id', $widgetAreaId)
|
||||
->get();
|
||||
|
||||
$ids = [];
|
||||
foreach ($models as $model) {
|
||||
$ids[] = $model->widget_id;
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 = [];
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user