public static function widget(array $params = null) { self::$class = get_called_class(); // check if class exist if (!class_exists(self::$class)) { return 'Error: Widget is not founded: ' . self::$class; } // init class and pass properties $object = new self::$class(); if (Obj::isArray($params) && count($params) > 0) { foreach ($params as $property => $value) { if (property_exists($object, $property)) { $object->{$property} = $value; } } } // prepare output $out = null; try { $object->init(); $out = $object->display(); } catch (\Exception $e) { throw $e; } return $out; }
/** * Run cron task. Attention - this method is too 'fat' to run from any app's * @return array|null */ public function run() { // check if cron instances is defined if (!isset($this->configs['instances']) || !Obj::isArray($this->configs['instances'])) { return null; } // get timestamp $time = time(); $log = []; // each every one instance foreach ($this->configs['instances'] as $callback => $delay) { if ((int) $this->configs['log'][$callback] + $delay <= $time) { // prepare cron initializing list($class, $method) = explode('::', $callback); if (class_exists($class) && method_exists($class, $method)) { // make static callback forward_static_call([$class, $method]); $log[] = $callback; } // update log information $this->configs['log'][$callback] = $time + $delay; } } // write updated configs App::$Properties->writeConfig('Cron', $this->configs); return $log; }
/** * Build <select {$properties} >[<options>]</select> response * {@inheritDoc} * @see \Ffcms\Core\Helper\HTML\Form\iField::make() */ public function make() { // get options from properties $options = $this->properties['options']; unset($this->properties['options']); if (!Obj::isIterable($options)) { throw new SyntaxException('Select field ' . self::nohtml($this->name) . ' have no iterable options'); } // value is not used there unset($this->properties['value']); // options is defined as key->value array? $optionsKey = $this->properties['optionsKey'] === true; unset($this->properties['optionsKey']); $buildOpt = null; foreach ($options as $optIdx => $opt) { $optionProperty = []; if ($optionsKey === true) { // options with value => text $optionProperty['value'] = $optIdx; if ($optIdx == $this->value) { $optionProperty['selected'] = null; // def boolean attribute html5 } } else { // only value option if ($opt == $this->value) { $optionProperty['selected'] = null; // def boolean attribute html5 } } $buildOpt .= self::buildContainerTag('option', $optionProperty, $opt); } // return compiled DOM return self::buildContainerTag('select', $this->properties, $buildOpt, true); }
/** * Get sitemap index files info as array * @return array */ public function getInfo() { if (!Obj::isArray($this->info)) { return []; } return $this->info; }
/** * Make snippet from text or html-text content. * @param string $text * @param int $length * @return string */ public static function snippet($text, $length = 150) { // check if valid string is passed if (!Obj::isString($text)) { return null; } $breakerPos = mb_strpos($text, self::WYSIWYG_BREAK_HTML, null, 'UTF-8'); // offset is founded, try to split preview from full text if ($breakerPos !== false) { $text = Str::sub($text, 0, $breakerPos); } else { // page breaker is not founded, lets get a fun ;D // find first paragraph ending $breakerPos = mb_strpos($text, '</p>', null, 'UTF-8'); // no paragraph's ? lets try to get <br[\/|*]> if ($breakerPos === false) { $breakerPos = mb_strpos($text, '<br', null, 'UTF-8'); } else { // add length('</p>') $breakerPos += 4; } // cut text from position caret before </p> (+4 symbols to save item as valid) if ($breakerPos !== false) { $text = Str::sub($text, 0, $breakerPos); } } // if breaker position is still undefined - lets make 'text cut' for defined length and remove all html tags if ($breakerPos === false) { $text = strip_tags($text); $text = self::cut($text, 0, $length); } return $text; }
/** * Make function of current field type. Return compiled html response * @return string * @throws \Ffcms\Core\Exception\NativeException * @throws \Ffcms\Core\Exception\SyntaxException */ public function make() { // get options from properties $options = $this->properties['options']; if (!Obj::isIterable($options)) { throw new SyntaxException('Radio field ' . self::nohtml($this->name) . ' have no iterable options'); } unset($this->properties['options'], $this->properties['value']); // options is defined as key->value array? $optionsKey = $this->properties['optionsKey'] === true; unset($this->properties['optionsKey']); $build = null; // build output dom html foreach ($options as $idx => $value) { $property = $this->properties; if ($optionsKey === true) { // radio button as [value => text_description] - values is a key $property['value'] = $idx; if ($idx == $this->value) { $property['checked'] = null; // def boolean attribute html5 } } else { // radio button only with [value] data $property['value'] = $value; if ($value == $this->value) { $property['checked'] = null; // def boolean attribute html5 } } // get template and concat avg response $build .= App::$View->render('native/form/radio_list', ['tag' => self::buildSingleTag('input', $property), 'text' => $value]); } return $build; }
/** * Scan available permissions and write to cfg file * @return string */ public function actionBuildperms() { // default permissions $permissions = ['global/write', 'global/modify', 'global/file', 'global/all']; // admin controllers $AdminAppControllers = '/Apps/Controller/Admin/'; // scan directory $scan = File::listFiles($AdminAppControllers, ['.php']); foreach ($scan as $file) { $className = Str::firstIn(Str::lastIn($file, DIRECTORY_SEPARATOR, true), '.'); // read as plain text $byte = File::read($file); preg_match_all('/public function action(\\w*?)\\(/', $byte, $matches); // matches[0] contains all methods ;) if (Obj::isArray($matches[1]) && count($matches[1]) > 0) { foreach ($matches[1] as $perm) { $permissions[] = 'Admin/' . $className . '/' . $perm; } } } // prepare save string $stringSave = "<?php \n\nreturn " . var_export($permissions, true) . ';'; File::write('/Private/Config/Permissions.php', $stringSave); return 'Permissions configuration is successful updated! Founded permissions: ' . count($permissions); }
/** * Decode string $data and get value by key * @param $data * @param string $key * @return string|array|null */ public static function getDecoded($data, $key) { if (!Obj::isArray($data)) { $data = self::decode($data); } return $data === false ? null : $data[$key]; }
/** * Read feedback message and answers and work with add answer model * @param int $id * @param string $hash * @return string * @throws \Ffcms\Core\Exception\NativeException * @throws ForbiddenException * @throws \Ffcms\Core\Exception\SyntaxException */ public function actionRead($id, $hash) { if (!Obj::isLikeInt($id) || Str::length($hash) < 16 || Str::length($hash) > 64) { throw new ForbiddenException(__('The feedback request is not founded')); } // get feedback post record from database $recordPost = FeedbackPost::where('id', '=', $id)->where('hash', '=', $hash)->first(); if ($recordPost === null) { throw new ForbiddenException(__('The feedback request is not founded')); } $userId = App::$User->isAuth() ? App::$User->identity()->getId() : 0; $model = null; // check if feedback post is not closed for answers if ((int) $recordPost->closed === 0) { // init new answer add model $model = new FormAnswerAdd($recordPost, $userId); // if answer is sender lets try to make it model if ($model->send() && $model->validate()) { $model->make(); App::$Session->getFlashBag()->add('success', __('Your answer was added')); $model->clearProperties(); } } // render output view return $this->view->render('read', ['model' => $model, 'post' => $recordPost, 'answers' => $recordPost->getAnswers()->get()]); }
/** * Build <input type="checkbox" checked {$properties} /> response * {@inheritDoc} * @see \Ffcms\Core\Helper\HTML\Form\iField::make() * @throws \Ffcms\Core\Exception\NativeException * @throws \Ffcms\Core\Exception\SyntaxException */ public function make() { // check if options is defined $options = $this->properties['options']; if (!Obj::isIterable($options)) { throw new SyntaxException('Options for field ' . self::nohtml($this->name) . ' is not iterable'); } unset($this->properties['options']); // set field type $this->properties['type'] = 'checkbox'; // set this field as array html dom object $this->properties['name'] .= '[]'; unset($this->properties['value'], $this->properties['id']); $build = null; foreach ($options as $opt) { // check if this is active element if (Obj::isArray($this->value) && Arr::in($opt, $this->value)) { $this->properties['checked'] = null; } else { unset($this->properties['checked']); // remove checked if it setted before } $this->properties['value'] = $opt; // apply structured checkboxes style for each item $build .= App::$View->render('native/form/multi_checkboxes_list', ['item' => self::buildSingleTag('input', $this->properties) . self::nohtml($opt)]); } return $build; }
/** * Upload files from ckeditor * @param string $type * @return string * @throws NativeException * @throws \Ffcms\Core\Exception\SyntaxException */ public function actionUpload($type) { /** @var $loadFile \Symfony\Component\HttpFoundation\File\UploadedFile */ $loadFile = App::$Request->files->get('upload'); if ($loadFile === null || $loadFile->getError() !== 0) { return $this->errorResponse(__('File upload failed')); } // get file extension $fileExt = '.' . $loadFile->guessExtension(); // check if this request type is allowed if ($this->allowedExt[$type] === null || !Obj::isArray($this->allowedExt[$type])) { throw new NativeException('Hack attempt'); } // check if this file extension is allowed to upload if (!Arr::in($fileExt, $this->allowedExt[$type])) { return $this->errorResponse(__('This file type is not allowed to upload')); } $date = Date::convertToDatetime(time(), 'd-m-Y'); // create file hash based on name-size $fileNewName = App::$Security->simpleHash($loadFile->getFilename() . $loadFile->getSize()) . $fileExt; $savePath = Normalize::diskFullPath('/upload/' . $type . '/' . $date); // save file from tmp to regular $loadFile->move($savePath, $fileNewName); // generate URI of uploaded file $url = '/upload/' . $type . '/' . $date . '/' . $fileNewName; return App::$View->render('editor/load_success', ['callbackId' => (int) App::$Request->query->get('CKEditorFuncNum'), 'url' => $url], __DIR__); }
/** * Delete user row from database * @param int $id * @return string * @throws \Ffcms\Core\Exception\SyntaxException * @throws \Ffcms\Core\Exception\NativeException * @throws NotFoundException */ public function actionDelete($id = null) { // check if id is passed or get data from GET as array ids if ($id === 0 || (int) $id < 1) { $ids = $this->request->query->get('selected'); if (Obj::isArray($ids) && Arr::onlyNumericValues($ids)) { $id = $ids; } else { throw new NotFoundException('Bad conditions'); } } else { $id = [$id]; } // initialize delete model $model = new FormUserDelete($id); // check if users is found if ($model->users === null) { throw new NotFoundException(__('Users are not found')); } // check if delete is submited if ($model->send() && $model->validate()) { $model->delete(); App::$Session->getFlashBag()->add('success', __('Users and them data are successful removed')); $this->response->redirect('user/index'); } // set view response return $this->view->render('user_delete', ['model' => $model]); }
public function makeTag($name, $value = null, $properties = null) { // check if properties is passed well if ($properties !== null && !Obj::isArray($properties)) { throw new SyntaxException('Property must be passed as array or null! Field: ' . $name); } // add properties to autovalidation by js (properties passed by ref) $this->validatorProperties($name, $properties); // prepare properties name and id to autobuild $this->globalProperties($name, $value, $properties); // initialize build model depend of current type switch ($this->type) { case static::TYPE_TEXT: // for <input type="text"> $builder = new TextField($properties, $name); return $builder->make(); case static::TYPE_CHECKBOX: $builder = new CheckboxField($properties, $name, $value); return $builder->make(); case static::TYPE_PASSWORD: $builder = new PasswordField($properties, $name); return $builder->make(); case static::TYPE_EMAIL: $builder = new EmailField($properties, $name); return $builder->make(); case static::TYPE_SELECT: $builder = new SelectField($properties, $name, $value); return $builder->make(); case static::TYPE_TEXTAREA: $builder = new TextareaField($properties, $name, $value); return $builder->make(); case static::TYPE_MULTI_CHECKBOXES: $builder = new MultiCheckboxField($properties, $name, $value); return $builder->make(); case static::TYPE_CAPTCHA: $builder = new CaptchaField($properties, $name); return $builder->make(); case static::TYPE_FILE: $builder = new FileField($properties, $name); return $builder->make(); case static::TYPE_HIDDEN: $builder = new HiddenField($properties, $name, $value); return $builder->make(); case static::TYPE_DIV_FAKE: $builder = new DivFakeField($properties, $name, $value); return $builder->make(); case static::TYPE_MULTISELECT: $builder = new MultiSelectField($properties, $name, $value); return $builder->make(); case static::TYPE_RADIO: $builder = new RadioField($properties, $name, $value); return $builder->make(); } // if field is unknown type add notification in debugbar if (App::$Debug !== null) { App::$Debug->addMessage('Field with name [' . App::$Security->strip_tags($name) . '] have unknown type [' . $this->type . ']', 'error'); } return 'No data: ' . App::$Security->strip_tags($name); }
/** * Get all permissions as array * @return array * @throws SyntaxException */ public function getAllPermissions() { $p = App::$Properties->getAll('permissions'); if ($p === false || !Obj::isArray($p)) { throw new SyntaxException('User permissions settings is not founded: /Private/Config/Permissions.php'); } return $p; }
/** * Set global variable from key=>value array (key = varname) * @param array $array */ public function setGlobalArray(array $array) { if (!Obj::isArray($array)) { return; } foreach ($array as $var => $value) { $this->globalVars[$var] = Obj::isString($value) ? App::$Security->strip_tags($value) : $value; } }
/** * Prepare conditions to build content list * @throws NotFoundException */ public function before() { // check length of passed terms if (!Obj::isString($this->_terms) || Str::length($this->_terms) < self::MIN_QUERY_LENGTH) { throw new NotFoundException(__('Search terms is too short')); } // lets make active record building $this->_records = ContentEntity::whereNotIn('id', $this->_skip)->search($this->_terms)->take(self::MAX_ITEMS)->get(); $this->buildContent(); parent::before(); }
/** * Special function for locale stored attributes under serialization. * @param string $attribute * @return array|null|string */ public function getLocaled($attribute) { // if always decoded if (Obj::isArray($this->{$attribute})) { return $this->{$attribute}[App::$Request->getLanguage()]; } if (!Obj::isString($attribute) || Str::likeEmpty($this->{$attribute})) { return null; } return Serialize::getDecodeLocale($this->{$attribute}); }
/** * Add message into debug bar * @param string $m * @param string $type * @throws \DebugBar\DebugBarException */ public function addMessage($m, $type = 'info') { if (!Obj::isString($m) || !Obj::isString($type)) { return; } $m = App::$Security->secureHtml($m); $mCollector = $this->bar->getCollector('messages'); if (method_exists($mCollector, $type)) { $this->bar->getCollector('messages')->{$type}($m); } }
/** * Set property values from configurations */ public function before() { $properties = App::$Properties->getAll(); if ($properties === false || !Obj::isArray($properties)) { return; } // set default values foreach (App::$Properties->getAll() as $key => $value) { if (property_exists($this, $key)) { $this->{$key} = $value; } } }
/** * Try to convert string to date time format * @param string|int $rawDate * @param string $format * @return string|bool */ public static function convertToDatetime($rawDate, $format = 'd.m.Y') { if (Obj::isLikeInt($rawDate)) { // convert timestamp to date format $rawDate = date($format, $rawDate); } try { $object = new \DateTime($rawDate); return $object->format($format); } catch (\Exception $e) { return false; } }
/** * Build xml output and save it into sitemap folder * @param string $uniqueName * @return bool * @throws \Ffcms\Core\Exception\NativeException * @throws \Ffcms\Core\Exception\SyntaxException */ public function save($uniqueName) { // check if data exists if ($this->data === null || !Obj::isArray($this->data)) { return false; } // list data each every language, render xml output and write into file foreach ($this->data as $lang => $items) { $xml = App::$View->render('native/sitemap_urlset', ['items' => $items]); File::write(EntityIndexList::INDEX_PATH . '/' . $uniqueName . '.' . $lang . '.xml', $xml); } return true; }
/** * Set default configurations if not defined * {@inheritDoc} * @see \Ffcms\Core\Arch\Widget::init() */ public function init() { $cfg = $this->getConfigs(); // check cache is defined if ($this->cache === null || !Obj::isLikeInt($this->cache)) { $this->cache = (int) $cfg['cache']; } // check tag count is defined if ($this->count === null || !Obj::isLikeInt($this->count)) { $this->count = (int) $cfg['count']; } $this->_lang = App::$Request->getLanguage(); $this->_cacheName = 'widget.contenttag.' . $this->createStringClassSnapshotHash(); }
/** * Build console controllers. * php console.php Controller/Action index */ public static function run() { global $argv; $output = null; if (!Obj::isArray($argv) || Str::likeEmpty($argv[1])) { $output = 'Console command is unknown! Type "console main/help" to get help guide'; } else { $controller_action = $argv[1]; $arrInput = explode('/', $controller_action); $controller = ucfirst(strtolower($arrInput[0])); $action = ucfirst(strtolower($arrInput[1])); if ($action == null) { $action = 'Index'; } // set action and id $action = 'action' . $action; $id = null; if (isset($argv[2])) { $id = $argv[2]; } try { $controller_path = '/Apps/Controller/' . env_name . '/' . $controller . '.php'; if (file_exists(root . $controller_path) && is_readable(root . $controller_path)) { include_once root . $controller_path; $cname = 'Apps\\Controller\\' . env_name . '\\' . $controller; if (class_exists($cname)) { $load = new $cname(); if (method_exists($cname, $action)) { if ($id !== null) { $output = @$load->{$action}($id); } else { $output = @$load->{$action}(); } } else { throw new NativeException('Method ' . $action . '() not founded in ' . $cname . ' in file {root}' . $controller_path); } unset($load); } else { throw new NativeException('Namespace\\Class - ' . $cname . ' not founded in {root}' . $controller_path); } } else { throw new NativeException('Controller not founded: {root}' . $controller_path); } } catch (NativeException $e) { $e->display($e->getMessage()); } } return self::$Output->write($output); }
/** * Get current application configs as array * @return array */ public function getConfigs() { if ($this->configs !== null) { return $this->configs; } $configs = (array) $this->application->configs; foreach ($configs as $cfg => $value) { if (Obj::isLikeInt($value)) { $configs[$cfg] = (int) $value; // convert string 1 "1" to int 1 1 } } $this->configs = $configs; return $this->configs; }
/** * Add ckeditor library's to lazyload * @return null */ public function display() { App::$Alias->setCustomLibrary('js', $this->baseUrl . '/ckeditor.js'); App::$Alias->setCustomLibrary('js', $this->baseUrl . '/adapters/jquery.js'); $jsInitializeCode = "\$('.{$this->targetClass}').ckeditor({"; $jsInitializeCode .= "language: '{$this->language}', customConfig: '{$this->config}.js', "; if ($this->jsConfig !== null && Obj::isArray($this->jsConfig)) { foreach ($this->jsConfig as $obj => $value) { $jsInitializeCode .= $obj . ": '" . $value . "', "; } } $jsInitializeCode .= "});"; App::$Alias->addPlainCode('js', $jsInitializeCode); return null; }
/** * Get single row by defined type and sys_name with query caching * @param string $type * @param string|array $sys_name * @return mixed|null * @throws SyntaxException */ public static function getItem($type, $sys_name) { foreach (self::all() as $object) { if ($object->type === $type) { //&& $object->sys_name === $sys_name) { if (Obj::isArray($sys_name) && Arr::in($object->sys_name, $sys_name)) { // many different app name - maybe alias or something else return $object; } elseif (Obj::isString($sys_name) && $object->sys_name === $sys_name) { return $object; } } } return null; }
/** * Get user nickname by user id with predefined value on empty or not exist profile * @param $userId * @param string $onEmpty * @return string */ public static function parseUserNick($userId = null, $onEmpty = 'guest') { // try to get user id as integer if (Obj::isLikeInt($userId)) { $userId = (int) $userId; } else { // user id is empty, lets return default value return \App::$Security->strip_tags($onEmpty); } // try to find user active record as object $identity = App::$User->identity($userId); if ($identity === null || $identity === false) { return \App::$Security->strip_tags($onEmpty); } // return user nickname from profile return $identity->getProfile()->getNickname(); }
/** * Prepare widget. Set default configs if not defined on initialization * {@inheritDoc} * @see \Ffcms\Core\Arch\Widget::init() */ public function init() { $cfg = $this->getConfigs(); // check if categories is empty if ($this->categories === null) { $this->categories = $cfg['categories']; } // check cache is defined if ($this->cache === null || !Obj::isLikeInt($this->cache)) { $this->cache = (int) $cfg['cache']; } // check item count is defined if ($this->count === null || !Obj::isLikeInt($this->count)) { $this->count = (int) $cfg['count']; } $this->_cacheName = 'widget.newcontent.' . $this->createStringClassSnapshotHash(); }
/** * Display language switcher as html or get builded result as array * @return array|null|string */ public function display() { // prevent loading on disabled multi-language property if ($this->multiLangEnabled !== true) { return null; } // check if languages is defined and count more then 1 if (!Obj::isArray($this->langs) || count($this->langs) < 2) { return null; } // build output items for listing $items = []; foreach ($this->langs as $lang) { $items[] = ['type' => 'link', 'link' => App::$Alias->baseUrlNoLang . '/' . $lang . App::$Request->getPathInfo(), 'text' => '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="flag flag-' . $lang . '" alt="' . $lang . '"/>', 'html' => true, '!secure' => true]; } if ($this->onlyArrayItems) { return $items; } return Listing::display(['type' => 'ul', 'property' => $this->css, 'items' => $items]); }
/** * Find latest release in github API and get required info */ private function findLatestVersion() { // get remote api with json response $gitJson = File::getFromUrl(static::API_LATEST_RELEASE); if ($gitJson === null || $gitJson === false) { return; } // parse api response to model attributes $git = json_decode($gitJson, true); $this->lastVersion = $git['tag_name']; // get download url to full compiled distributive (uploaded to each release as .zip archive, placed in release.assets) $download = null; if (Obj::isArray($git['assets'])) { foreach ($git['assets'] as $asset) { if ($asset['content_type'] === 'application/zip' && $asset['state'] === 'uploaded') { $download = $asset['browser_download_url']; } } } $this->lastInfo = ['name' => $git['name'], 'created_at' => Date::convertToDatetime($git['published_at'], Date::FORMAT_TO_HOUR), 'download_url' => $download]; }