/** * Main search method * @return string * @throws \Ffcms\Core\Exception\NativeException * @throws NotFoundException * @throws \Ffcms\Core\Exception\SyntaxException */ public function actionIndex() { // get search query value from GET headers $query = (string) $this->request->query->get('query', null); // strip html tags $query = App::$Security->strip_tags(trim($query)); // get configs $configs = $this->getConfigs(); // check search query length if (Str::likeEmpty($query) || Str::length($query) < (int) $configs['minLength']) { throw new NotFoundException(__('Search query is too short!')); } // prevent sh@t query's with big length if (Str::length($query) > static::QUERY_MAX_LENGTH) { throw new NotFoundException(__('Search query is too long!')); } // initialize search controller model $model = new EntitySearchMain($query, $configs); // try to search by default apps $model->make(); // register search event to allow extend it model results App::$Event->run(static::EVENT_SEARCH_RUNNED, ['model' => $model]); // render output view with search result return $this->view->render('index', ['model' => $model, 'query' => $query]); }
/** * 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()]); }
/** * Normalize local disk-based path. Ex: ../../dir/./dir/file.txt * @param string $path * @return string */ public static function diskPath($path) { // its full-based path? Lets return real path if (Str::startsWith(root, $path)) { // fix path collisions if is not exist if (file_exists($path)) { return realpath($path); } else { return $path; } } // else - sounds like relative path $path = Str::replace('\\', '/', $path); $splitPath = explode('/', $path); $outputPath = []; foreach ($splitPath as $index => $part) { if ($part === '.' || Str::length(trim($part)) < 1) { continue; } if ($part === '..') { // level-up (: array_pop($outputPath); continue; } $outputPath[] = trim($part); } return implode(DIRECTORY_SEPARATOR, $outputPath); }
/** * Check comment add conditions. On bad conditions will be throw'd exception. * @throws JsonException * @return boolean */ public function check() { // check if user is auth'd or guest name is defined if (!App::$User->isAuth() && ((int) $this->_configs['guestAdd'] !== 1 || Str::length($this->guestName) < 2)) { throw new JsonException(__('Guest name is not defined')); } // check if pathway is empty if (Str::likeEmpty($this->pathway)) { throw new JsonException(__('Wrong target pathway')); } // check if message length is correct if (Str::length($this->message) < (int) $this->_configs['minLength'] || Str::length($this->message) > (int) $this->_configs['maxLength']) { throw new JsonException(__('Message length is incorrect. Current: %cur%, min - %min%, max - %max%', ['cur' => Str::length($this->message), 'min' => $this->_configs['minLength'], 'max' => $this->_configs['maxLength']])); } // guest moderation if (!App::$User->isAuth() && (bool) $this->_configs['guestModerate']) { $captcha = App::$Request->request->get('captcha'); if (!App::$Captcha->validate($captcha)) { throw new JsonException(__('Captcha is incorrect! Click on image to refresh and try again')); } } // check delay between 2 comments from 1 user or 1 ip $query = CommentPost::where('user_id', '=', $this->_userId)->orWhere('ip', '=', $this->ip)->orderBy('created_at', 'DESC')->first(); // check if latest post time for this user is founded if ($query !== null) { $postTime = Date::convertToTimestamp($query->created_at); $delay = $postTime + $this->_configs['delay'] - time(); if ($delay > 0) { throw new JsonException(__('Spam protection: please, wait %sec% seconds', ['sec' => $delay])); } } return true; }
/** * Validate input data from captcha * @param string|null $data * @return bool * @throws SyntaxException */ public static function validate($data = null) { $captchaValue = App::$Session->get('captcha'); // unset session value to prevent duplication. Security fix. App::$Session->remove('captcha'); // check if session has value if ($captchaValue === null || Str::length($captchaValue) < 1) { return false; } return $data === $captchaValue; }
/** * 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(); }
/** * Get internalization based on called controller * @param string $text * @param array $params * @return string */ public function translate($text, array $params = []) { $index = null; $namespace = 'Apps\\Controller\\' . env_name . '\\'; foreach (@debug_backtrace() as $caller) { if (isset($caller['class']) && Str::startsWith($namespace, $caller['class'])) { $index = Str::sub((string) $caller['class'], Str::length($namespace)); } } return $this->get($index, $text, $params); }
/** * Print json response for search query based on standard model * @return string * @throws JsonException */ public function actionIndex() { $this->setJsonHeader(); // get search query as string from request $query = $this->request->query->get('query', null); if (Str::likeEmpty($query) || Str::length($query) < 2) { throw new JsonException('Short query'); } // initialize basic search model $model = new EntitySearchMain($query, ['itemPerApp' => 3]); $model->make(); // build response by relevance as array $response = $model->getRelevanceSortedResult(); return json_encode(['status' => 1, 'count' => count($response), 'data' => $response]); }
/** * Try user auth after form validate * @return bool */ public function tryAuth() { $password = App::$Security->password_hash($this->password); $search = App::$User->where('password', '=', $password)->where(function ($query) { $query->where('login', '=', $this->login)->orWhere('email', '=', $this->login); }); if ($search->count() === 1) { $object = $search->first(); // check if accounts is approved if ($object->approve_token !== '0' && Str::length($object->approve_token) > 0) { return false; } return $this->openSession($object); } return false; }
/** * Browse files from ckeditor * @param string $type * @throws NativeException * @throws \Ffcms\Core\Exception\SyntaxException */ public function actionBrowse($type) { $files = null; $relative = null; // check if request type is defined if ($this->allowedExt[$type] === null || !Obj::isArray($this->allowedExt[$type])) { throw new NativeException('Hack attempt'); } // list files in directory $files = File::listFiles('/upload/' . $type, $this->allowedExt[$type]); // absolute path to relative URI foreach ($files as $file) { $newName = Str::sub($file, Str::length(root) + 1); $relative[] = trim(Str::replace(DIRECTORY_SEPARATOR, '/', $newName), '/'); } // generate response return App::$View->render('editor/browse', ['callbackName' => App::$Security->strip_tags(App::$Request->query->get('CKEditor')), 'callbackId' => (int) App::$Request->query->get('CKEditorFuncNum'), 'files' => $relative, 'type' => $type], __DIR__); }
/** * After validation generate new pwd, recovery token and send email * @throws SyntaxException * @throws \Ffcms\Core\Exception\NativeException */ public function make() { $user = App::$User->getIdentityViaEmail($this->email); if ($user === null) { throw new SyntaxException('Email not found'); } if ($user->approve_token !== '0' && Str::length($user->approve_token) > 0) { throw new SyntaxException('You must approve your account'); } $rows = UserRecovery::where('user_id', '=', $user->getId())->orderBy('id', 'DESC')->first(); if ($rows !== null && $rows !== false) { // prevent spam of recovery messages if (Date::convertToTimestamp($rows->created_at) > time() - self::DELAY) { return; } } // generate pwd, token and pwdCrypt $newPwd = Str::randomLatinNumeric(mt_rand(8, 16)); $pwdCrypt = App::$Security->password_hash($newPwd); $token = Str::randomLatinNumeric(mt_rand(64, 128)); // write new data to recovery table $rObject = new UserRecovery(); $rObject->user_id = $user->id; $rObject->password = $pwdCrypt; $rObject->token = $token; $rObject->save(); // write logs data $log = new UserLog(); $log->user_id = $user->id; $log->type = 'RECOVERY'; $log->message = __('Password recovery is initialized from: %ip%', ['ip' => App::$Request->getClientIp()]); $log->save(); // generate mail template $mailTemplate = App::$View->render('user/mail/recovery', ['login' => $user->login, 'email' => $this->email, 'password' => $newPwd, 'token' => $token, 'id' => $rObject->id]); $sender = App::$Properties->get('adminEmail'); // format SWIFTMailer format $mailMessage = \Swift_Message::newInstance(App::$Translate->get('Profile', 'Account recovery on %site%', ['site' => App::$Request->getHost()]))->setFrom([$sender])->setTo([$this->email])->setBody($mailTemplate, 'text/html'); // send message App::$Mailer->send($mailMessage); }
/** * Check if comment answer conditions is ok. Will throw exception if not. * @return bool * @throws JsonException */ public function check() { // check if user is auth'd or guest name is defined if (!App::$User->isAuth() && ((int) $this->_configs['guestAdd'] !== 1 || Str::length($this->guestName) < 2)) { throw new JsonException(__('Guest name is not defined')); } // guest moderation if (!App::$User->isAuth() && (bool) $this->_configs['guestModerate']) { $captcha = App::$Request->request->get('captcha'); if (!App::$Captcha->validate($captcha)) { throw new JsonException(__('Captcha is incorrect! Click on image to refresh and try again')); } } // check if replayTo is defined if ($this->replayTo < 1) { throw new JsonException(__('Comment post thread is not founded')); } // check if message length is correct if (Str::length($this->message) < (int) $this->_configs['minLength'] || Str::length($this->message) > (int) $this->_configs['maxLength']) { throw new JsonException(__('Message length is incorrect. Current: %cur%, min - %min%, max - %max%', ['cur' => Str::length($this->message), 'min' => $this->_configs['minLength'], 'max' => $this->_configs['maxLength']])); } $count = CommentPost::where('id', '=', $this->replayTo)->count(); if ($count !== 1) { throw new JsonException(__('Comment post thread is not founded')); } // check to prevent spam $query = CommentAnswer::where('user_id', '=', $this->_userId)->orWhere('ip', '=', $this->ip)->orderBy('created_at', 'DESC')->first(); // something is founded :D if ($query !== null) { $answerTime = Date::convertToTimestamp($query->created_at); $delay = $answerTime + $this->_configs['delay'] - time(); if ($delay > 0) { // sounds like config time is not passed now throw new JsonException(__('Spam protection: please, wait %sec% seconds', ['sec' => $delay])); } } return true; }
/** * Update user information in database based on current obj attributes passed from input data */ public function save() { foreach ($this->getAllProperties() as $property => $value) { if ($property === 'password' || $property === 'newpassword') { // update password only if new is set and length >= 3 if ($this->newpassword !== null && Str::length($this->newpassword) >= 3) { $this->_user->password = App::$Security->password_hash($this->newpassword); } } elseif ($property === 'approve_token') { if ($value == "1") { $this->_user->approve_token = '0'; } else { if ($this->_approve_tmp === '0') { $this->_approve_tmp = Str::randomLatinNumeric(mt_rand(32, 128)); } $this->_user->approve_token = $this->_approve_tmp; } } else { $this->_user->{$property} = $value; } } $this->_user->save(); }
/** * Add user in database * @return string * @throws NativeException */ public function actionAdduser() { echo "Login:"******"Email:"; $email = Console::$Input->read(); if (!Str::isEmail($email)) { throw new NativeException('Email is bad'); } echo "Password:"******"RoleId (1 = onlyread, 2 = user, 3 = moderator, 4 = admin):"; $role = (int) Console::$Input->read(); if (!Arr::in($role, [1, 2, 3, 4])) { $role = 2; } if (User::isMailExist($email) || User::isLoginExist($login)) { throw new NativeException('User with this email or login is always exist'); } $salt = Console::$Properties->get('passwordSalt'); $user = new User(); $user->login = $login; $user->email = $email; $user->password = Security::password_hash($pass, $salt); $user->role_id = $role; $user->save(); $profile = new Profile(); $profile->user_id = $user->id; $profile->save(); return 'User was successful added to database!'; }
/** * Check if user with $login is exist * @param string $login * @return bool */ public static function isLoginExist($login) { if (!Obj::isString($login) || Str::length($login) < 1) { return false; } return self::where('login', '=', $login)->count() > 0; }
/** * Prepare model attributes from passed objects * @throws ForbiddenException */ public function before() { $this->id = $this->_content->id; $this->title = $this->_content->getLocaled('title'); $this->text = $this->_content->getLocaled('text'); // check if title and text are exists if (Str::length($this->title) < 1 || Str::length($this->text) < 1) { throw new ForbiddenException(); } // get meta data $this->metaTitle = $this->_content->getLocaled('meta_title'); if (Str::likeEmpty($this->metaTitle)) { $this->metaTitle = $this->title; } $this->metaDescription = $this->_content->getLocaled('meta_description'); $tmpKeywords = $this->_content->getLocaled('meta_keywords'); $this->metaKeywords = explode(',', $tmpKeywords); // set content date, category data $this->createDate = Date::humanize($this->_content->created_at); $this->catName = $this->_category->getLocaled('title'); $this->catPath = $this->_category->path; // set user data if (App::$User->isExist($this->_content->author_id)) { $this->authorId = $this->_content->author_id; $profile = App::$User->identity($this->authorId)->getProfile(); $this->authorName = $profile->getNickname(); } $this->source = $this->_content->source; $this->views = $this->_content->views + 1; // check for dependence, add '' for general cat, ex: general/depend1/depend2/.../depend-n $catNestingArray = Arr::merge([0 => ''], explode('/', $this->catPath)); if ($catNestingArray > 1) { // latest element its a current nesting level, lets cleanup it array_pop($catNestingArray); $catNestingPath = null; foreach ($catNestingArray as $cPath) { $catNestingPath .= $cPath; // try to find category by path in db $record = ContentCategory::getByPath($catNestingPath); if ($record !== null && $record->count() > 0) { // if founded - add to nesting data $this->catNesting[] = ['name' => $record->getLocaled('title'), 'path' => $record->path]; } if (!Str::likeEmpty($catNestingPath)) { $catNestingPath .= '/'; } } } // build array of category nesting level $this->catNesting[] = ['name' => $this->catName, 'path' => $this->catPath]; // get gallery images and poster data $galleryPath = '/upload/gallery/' . $this->_content->id; // check if gallery folder is exist if (Directory::exist($galleryPath)) { $originImages = File::listFiles($galleryPath . '/orig/', ['.jpg', '.png', '.gif', '.jpeg', '.bmp', '.webp'], true); // generate poster data if (Arr::in($this->_content->poster, $originImages)) { // original poster $posterName = $this->_content->poster; $this->posterFull = $galleryPath . '/orig/' . $posterName; if (!File::exist($this->posterFull)) { $this->posterFull = null; } // thumb poster $posterSplit = explode('.', $posterName); array_pop($posterSplit); $posterCleanName = implode('.', $posterSplit); $this->posterThumb = $galleryPath . '/thumb/' . $posterCleanName . '.jpg'; if (!File::exist($this->posterThumb)) { $this->posterThumb = null; } } // generate full gallery foreach ($originImages as $image) { $imageSplit = explode('.', $image); array_pop($imageSplit); $imageClearName = implode('.', $imageSplit); // skip image used in poster if (Str::startsWith($imageClearName, $this->_content->poster)) { continue; } $thumbPath = $galleryPath . '/thumb/' . $imageClearName . '.jpg'; if (File::exist($thumbPath)) { $this->galleryItems[$thumbPath] = $galleryPath . '/orig/' . $image; } } } // set rating data $this->rating = $this->_content->rating; $ignoredRate = App::$Session->get('content.rate.ignore'); $this->canRate = true; if (Obj::isArray($ignoredRate) && Arr::in((string) $this->id, $ignoredRate)) { $this->canRate = false; } if (!App::$User->isAuth()) { $this->canRate = false; } elseif ($this->authorId === App::$User->identity()->getId()) { $this->canRate = false; } // update views count $this->_content->views += 1; $this->_content->save(); }
echo __('Rating'); ?> </a></li> <li><a href="<?php echo $model->category['sort']['views']; ?> "><?php echo __('Popularity'); ?> </a></li> </ul> </div> </div> </h1> <?php if (Str::length($model->category['description']) > 0) { ?> <p><?php echo $model->category['description']; ?> </p> <?php } ?> <hr /> <?php } if ($model->getContentCount() < 1) { ?> <p class="alert alert-warning"><?php echo __('This category is empty!');
/** * Build pathway from array $to. Example: ['controller/action', 'id', 'add', ['get' => 'value'], '#anchor'] * @param array $to * @param bool $encode * @return string|null */ public static function buildPathway(array $to = null, $encode = true) { // if empty passed - let show main page if ($to === null) { return null; } $response = Str::lowerCase(trim($to[0], '/')); // controller/action list($controller, $action) = explode('/', $response); $routing = App::$Properties->getAll('Routing'); // sounds like dynamic callback if (Str::startsWith('@', $controller)) { $controller = trim($controller, '@'); // search callback in properties if (isset($routing['Callback'][env_name]) && Arr::in($controller, $routing['Callback'][env_name])) { $pathInject = array_search($controller, $routing['Callback'][env_name]); // if path is founded - lets set source if ($pathInject !== false) { $controller = Str::lowerCase($pathInject); } } // if controller still looks like path injection - define last entity like controller name if (Str::contains('\\', $controller)) { $controller = Str::lastIn($controller, '\\', true); } $response = $controller . '/' . $action; } // check if controller and action is defined if (Str::likeEmpty($controller) || Str::likeEmpty($action)) { return null; } // id is defined? if (isset($to[1]) && !Str::likeEmpty($to[1])) { $response .= '/' . self::safeUri($to[1], $encode); } // add param is defined? if (isset($to[2]) && !Str::likeEmpty($to[2])) { $response .= '/' . self::safeUri($to[2], $encode); } // try to find static alias if (isset($routing['Alias'][env_name]) && Arr::in('/' . $response, $routing['Alias'][env_name])) { $pathAlias = array_search('/' . $response, $routing['Alias'][env_name]); if ($pathAlias !== false) { $response = Str::lowerCase(trim($pathAlias, '/')); } } // parse get attributes if (isset($to[3]) && Obj::isArray($to[3]) && count($to[3]) > 0) { // check if anchor bindig is exist $anchor = false; if (isset($to[3]['#']) && Obj::isString($to[3]['#']) && Str::startsWith('#', $to[3]['#'])) { $anchor = $to[3]['#']; unset($to[3]['#']); } $queryString = http_build_query($to[3]); if (Str::length($queryString) > 0) { $response .= '?' . http_build_query($to[3]); } if ($anchor !== false) { $response .= $anchor; } } // parse anchor link part #item-related-id-1 if (isset($to[4]) && Obj::isString($to[4]) && Str::startsWith('#', $to[4])) { $response .= $to[4]; } return $response; }
/** * List latest by created_at content items contains tag name * @param string $tagName * @return string * @throws NotFoundException * @throws \Ffcms\Core\Exception\SyntaxException * @throws \Ffcms\Core\Exception\NativeException */ public function actionTag($tagName) { // remove spaces and other shits $tagName = App::$Security->strip_tags(trim($tagName)); // check if tag is not empty if (Str::likeEmpty($tagName) || Str::length($tagName) < 2) { throw new NotFoundException(__('Tag is empty or is too short!')); } // get equal rows order by creation date $records = ContentEntity::where('meta_keywords', 'like', '%' . $tagName . '%')->orderBy('created_at', 'DESC')->take(self::TAG_PER_PAGE); // check if result is not empty if ($records->count() < 1) { throw new NotFoundException(__('Nothing founded')); } // define tag list event App::$Event->run(static::EVENT_TAG_LIST, ['records' => $records]); // render response return $this->view->render('tag', ['records' => $records->get(), 'tag' => $tagName]); }
/** * Save changes in database */ public function save() { $this->_content->title = $this->title; $this->_content->text = $this->text; $this->_content->path = $this->path; $this->_content->category_id = $this->categoryId; $this->_content->author_id = $this->authorId; $this->_content->display = $this->display; $this->_content->meta_title = $this->metaTitle; $this->_content->meta_keywords = $this->metaKeywords; $this->_content->meta_description = $this->metaDescription; $this->_content->source = $this->source; // check if rating is changed if ((int) $this->addRating !== 0) { $this->_content->rating += (int) $this->addRating; } // check if special comment hash is exist if ($this->_new || Str::length($this->_content->comment_hash) < 32) { $this->_content->comment_hash = $this->generateCommentHash(); } // check if date is updated if (!Str::likeEmpty($this->createdAt) && !Str::startsWith('0000', Date::convertToDatetime($this->createdAt, Date::FORMAT_SQL_TIMESTAMP))) { $this->_content->created_at = Date::convertToDatetime($this->createdAt, Date::FORMAT_SQL_TIMESTAMP); } // save poster data $posterPath = '/upload/gallery/' . $this->galleryFreeId . '/orig/' . $this->poster; if (File::exist($posterPath)) { $this->_content->poster = $this->poster; } // get temporary gallery id $tmpGalleryId = $this->galleryFreeId; // save row $this->_content->save(); // update tags data in special table (relation: content->content_tags = oneToMany) ContentTag::where('content_id', '=', $this->_content->id)->delete(); $insertData = []; foreach ($this->metaKeywords as $lang => $keys) { // split keywords to tag array $tags = explode(',', $keys); foreach ($tags as $tag) { // cleanup tag from white spaces $tag = trim($tag); // prepare data to insert if (Str::length($tag) > 0) { $insertData[] = ['content_id' => $this->_content->id, 'lang' => $lang, 'tag' => $tag]; } } } // insert tags ContentTag::insert($insertData); // move files if ($tmpGalleryId !== $this->_content->id) { Directory::rename('/upload/gallery/' . $tmpGalleryId, $this->_content->id); } }
<?php use Ffcms\Core\Helper\Type\Obj; use Ffcms\Core\Helper\Type\Str; $code = \App::$Properties->get('gaTrackId'); if (!Obj::isString($code) || Str::length($code) < 3) { return null; } ?> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', '<?php echo $code; ?> ', 'auto'); ga('send', 'pageview'); </script>
/** * Filter ['object', 'required'] * @param $object * @return bool */ public static function required($object) { if (Obj::isArray($object)) { return count($object) > 0; } return Str::length($object) > 0; }
/** * Validate pathway * @param string $path * @return bool * @throws SyntaxException */ public function pathIsFree($path) { $owner = ContentCategory::getById($this->dependId); if ($owner === null || $owner === false) { throw new SyntaxException(); } // build path with owner category $this->_pathNested = $owner->path; if (Str::length($this->_pathNested) > 0) { $path = $this->_pathNested . '/' . $path; } // make select for check $query = ContentCategory::where('path', '=', $path); if ($this->_new !== true) { // exclude current category from checking path's $query->where('id', '!=', $this->_record->id); } return $query->count() === 0; }
/** * Display nav listing block * @param array $elements */ public static function display($elements) { // check if elements isn't empty and contains rows if (!Obj::isArray($elements) || count($elements['items']) < 1) { return null; } // prepare tab order if ($elements['tabAnchor'] === null) { $elements['tabAnchor'] = Str::randomLatin(mt_rand(6, 12)); } // set global element properties $blockProperty = []; if ($elements['blockProperty'] !== null) { if (Obj::isArray($elements['blockProperty'])) { $blockProperty = $elements['blockProperty']; } unset($elements['blockProperty']); } // check if items have defined active order $activeDefined = Arr::in(true, Arr::ploke('active', $elements['items'])); // prepare tab content $tabContent = null; $tabIdx = 1; // initialize dom model $dom = new Dom(); // prepare items to drow listing $items = []; foreach ($elements['items'] as $item) { // its just a link, drow it as is if ($item['type'] === 'link') { $items[] = $item; } elseif ($item['type'] === 'dropdown') { // build bootstrap dropdown properties $item['dropdown'] = ['class' => 'dropdown-toggle', 'data-toggle' => 'dropdown', 'href' => '#']; $item['property']['class'] = Str::concat(' ', 'dropdown', $item['property']['class']); $items[] = $item; } elseif ($item['type'] === 'tab') { $activeObject = false; $item['type'] = 'link'; // fix for global Listing builder $item['link'] = '#' . $elements['tabAnchor'] . $tabIdx; $item['property']['role'] = 'presentation'; // check if active definition is exist in elements options if ($activeDefined) { if ($item['active'] === true) { $activeObject = true; } } elseif ($tabIdx === 1) { // if not exist set first as active $activeObject = true; } // mark active tab if ($activeObject === true) { $item['property']['class'] .= (Str::length($item['property']['class']) > 0 ? ' ' : null) . 'active'; } // tab special properties for bootstrap $item['linkProperty']['aria-controls'] = $elements['tabAnchor'] . $tabIdx; $item['linkProperty']['role'] = 'tab'; $item['linkProperty']['data-toggle'] = 'tab'; $itemContent = $item['content']; unset($item['content']); $items[] = $item; // draw tab content $tabContent .= $dom->div(function () use($item, $itemContent) { if ($item['html'] === true) { if ($item['!secure'] === true) { return $itemContent; } else { return self::safe($itemContent, true); } } else { return self::nohtml($itemContent); } }, ['role' => 'tabpanel', 'class' => 'tab-pane fade' . ($activeObject === true ? ' in active' : null), 'id' => $elements['tabAnchor'] . $tabIdx]); $tabIdx++; } } // check if global class "nav" isset if ($elements['property']['class'] !== null) { if (!Str::contains('nav ', $elements['property']['class'])) { $elements['property']['class'] = 'nav ' . $elements['property']['class']; } } else { $elements['property']['class'] = 'nav'; } // render final output return $dom->div(function () use($elements, $items, $tabContent, $dom) { // drow listing $listing = Listing::display(['type' => 'ul', 'property' => $elements['property'], 'activeOrder' => $elements['activeOrder'], 'items' => $items]); // drow tabs if isset if ($tabContent !== null) { $tabContent = $dom->div(function () use($tabContent) { return $tabContent; }, ['class' => 'tab-content']); } return $listing . $tabContent; }, $blockProperty); }
<?php if ($properties['rating']) { echo \App::$View->render('content/_rate', ['id' => $model->id, 'rating' => $model->rating, 'canRate' => $model->canRate]); } ?> <?php echo \App::$View->render('content/_rateJs'); ?> </div> <div class="pull-right"> <?php if ($properties['tags']) { ?> <div id="content-tags"> <?php if (Obj::isArray($model->metaKeywords) && count($model->metaKeywords) > 0 && Str::length($model->metaKeywords[0]) > 0) { echo '<i class="fa fa-tags hidden-xs"></i> '; foreach ($model->metaKeywords as $tag) { echo Url::link(['content/tag', $tag], $tag, ['class' => 'label label-default']) . " "; } } ?> </div> <?php } ?> </div> </div> </div> <?php if (!Str::likeEmpty($model->source)) {
/** * Get base path from current environment without basePath of subdirectories * @return string */ public function getInterfaceSlug() { $path = $this->getBasePath(); $subDir = App::$Properties->get('basePath'); if ($subDir !== '/') { $offset = (int) Str::length($subDir); $path = Str::sub($path, --$offset); } return $path; }
public function createObject($name, $type) { $singleName = false; if (!Str::contains('/', $name)) { if ($type === 'ActiveRecord') { $singleName = true; } else { $this->message = 'Command dosn\'t contains valid name. Example: Front/SomeForm, Admin/SomePkg/SomeInput'; return false; } } $objectDirPath = null; $objectNamespace = null; $objectName = null; $objectTemplate = null; if ($singleName) { $objectDirPath = root . '/Apps/' . $type . '/'; $objectNamespace = 'Apps\\' . $type; $objectName = ucfirst($name); } else { $split = explode('/', $name); $workground = ucfirst(strtolower(array_shift($split))); $objectName = ucfirst(array_pop($split)); $subName = false; if (count($split) > 0) { // some sub-namespace / folder path foreach ($split as $part) { if (Str::length($part) > 0) { $subName[] = ucfirst(strtolower($part)); } } } if ($type === 'Widget') { $objectDirPath = root . '/Widgets/' . $workground; $objectNamespace = 'Widgets\\' . $workground; } else { $objectDirPath = root . '/Apps/' . $type . '/' . $workground; $objectNamespace = 'Apps\\' . $type . '\\' . $workground; } if (false !== $subName) { $objectDirPath .= '/' . implode('/', $subName); $objectNamespace .= '\\' . implode('\\', $subName); } // try to find workground-based controller if (File::exist('/Private/Carcase/' . $workground . '/' . $type . '.tphp')) { $objectTemplate = File::read('/Private/Carcase/' . $workground . '/' . $type . '.tphp'); } } if (!Directory::exist($objectDirPath) && !Directory::create($objectDirPath)) { $this->message = 'Directory could not be created: ' . $objectDirPath; return false; } if ($objectTemplate === null) { $objectTemplate = File::read('/Private/Carcase/' . $type . '.tphp'); if (false === $objectTemplate) { $this->message = 'Php template file is not founded: /Private/Carcase/' . $type . '.tphp'; return false; } } $objectContent = Str::replace(['%namespace%', '%name%'], [$objectNamespace, $objectName], $objectTemplate); $objectFullPath = $objectDirPath . '/' . $objectName . '.php'; if (File::exist($objectFullPath)) { $this->message = $type . ' is always exist: ' . $objectFullPath; return false; } File::write($objectFullPath, $objectContent); $this->message = $type . ' template was created: [' . $objectName . '] in path: ' . Str::replace(root, '', $objectDirPath); return true; }
/** * Approve user profile via $email and $token params * @param string $email * @param string $token * @throws ForbiddenException */ public function actionApprove($email, $token) { // sounds like a not valid token if (App::$User->isAuth() || Str::length($token) < 32 || !Str::isEmail($email)) { throw new ForbiddenException(); } // lets find token&email $find = App::$User->where('approve_token', '=', $token)->where('email', '=', $email); // not found? exit if ($find->count() !== 1) { throw new ForbiddenException(); } // get row and update approve information $user = $find->first(); $user->approve_token = '0'; $user->save(); // open session and redirect to main $loginModel = new FormLogin(); $loginModel->openSession($user); $this->response->redirect('/'); // session is opened, refresh page }
/** * Try to find exist viewer full path * @param string $path * @param string|null $source * @return null|string * @throws NativeException */ private function findViewer($path, $source = null) { $tmpPath = null; // sounds like a relative path for current view theme if (Str::contains('/', $path)) { // lets try to get full path for current theme $tmpPath = $path; if (!Str::startsWith($this->themePath, $path)) { $tmpPath = Normalize::diskPath($this->themePath . '/' . $path . '.php'); } } else { // sounds like a object-depended view call from controller or etc // get stack trace of callbacks $calledLog = debug_backtrace(); $calledController = null; // lets try to find controller in backtrace foreach ($calledLog as $caller) { if (isset($caller['class']) && Str::startsWith('Apps\\Controller\\', $caller['class'])) { $calledController = (string) $caller['class']; } } // depended controller is not founded? Let finish if ($calledController === null) { throw new NativeException('View render is failed: callback controller not founded! Call with relative path: ' . $path); } // get controller name $controllerName = Str::sub($calledController, Str::length('Apps\\Controller\\' . env_name . '\\')); $controllerName = Str::lowerCase($controllerName); // get full path $tmpPath = $this->themePath . DIRECTORY_SEPARATOR . $controllerName . DIRECTORY_SEPARATOR . $path . '.php'; } // check if builded view full path is exist if (File::exist($tmpPath)) { return $tmpPath; } // hmm, not founded. Lets try to find in caller directory (for widgets, apps packages and other) if ($source !== null) { $tmpPath = Normalize::diskPath($source . DIRECTORY_SEPARATOR . $path . '.php'); if (File::exist($tmpPath)) { // add notify for native views if (App::$Debug !== null) { App::$Debug->addMessage('Render native viewer: ' . Str::replace(root, null, $tmpPath), 'info'); } return $tmpPath; } } if (App::$Debug !== null) { App::$Debug->addMessage('Viewer not founded on rendering: ' . $path, 'warning'); } return null; }
/** * Alias constructor. Build alias properties for system data to provide fast-access from apps and other places. */ public function __construct() { // make alias for view pathway $this->currentViewPath = App::$View->themePath; // make alias for baseUrl, script url and domain $this->baseDomain = App::$Request->getHttpHost(); if (Str::likeEmpty($this->baseDomain)) { $this->baseDomain = App::$Properties->get('baseDomain'); } // build script url $this->scriptUrl = App::$Request->getScheme() . '://' . $this->baseDomain; if (App::$Properties->get('basePath') !== '/') { $this->scriptUrl .= rtrim(App::$Properties->get('basePath'), '/'); } // build base url (with current used interface path slug) $this->baseUrl = $this->scriptUrl; if (App::$Request->getInterfaceSlug() !== null) { $this->baseUrl .= App::$Request->getInterfaceSlug(); } $this->baseUrlNoLang = $this->baseUrl; if (App::$Request->languageInPath() && App::$Request->getLanguage() !== null) { $this->baseUrl .= '/' . App::$Request->getLanguage(); } // add cron initiation from user if enabled if ((bool) App::$Properties->get('userCron') && env_name === 'Front') { $this->addPlainCode('js', 'if(Math.random() > 0.8) { $.get("' . $this->scriptUrl . '/cron.php?rand=" + Math.random()); }'); } // build vendor libs alias $this->vendorNamedLibrary['js']['jquery'] = $this->scriptUrl . '/vendor/bower/jquery/dist/jquery.min.js'; $this->vendorNamedLibrary['css']['bootstrap'] = $this->scriptUrl . '/vendor/bower/bootstrap/dist/css/bootstrap.min.css'; $this->vendorNamedLibrary['js']['bootstrap'] = $this->scriptUrl . '/vendor/bower/bootstrap/dist/js/bootstrap.min.js'; $this->vendorNamedLibrary['css']['fa'] = $this->scriptUrl . '/vendor/bower/components-font-awesome/css/font-awesome.min.css'; $this->vendorNamedLibrary['js']['jquery-ui'] = $this->scriptUrl . '/vendor/bower/jquery-ui/jquery-ui.min.js'; $this->vendorNamedLibrary['css']['jquery-ui'] = $this->scriptUrl . '/vendor/bower/jquery-ui/themes/base/jquery-ui.min.css'; $themeAll = App::$Properties->get('theme'); if (!isset($themeAll[env_name]) || Str::length($themeAll[env_name]) < 1) { $themeAll[env_name] = 'default'; } $this->currentViewUrl = $this->scriptUrl . '/Apps/View/' . env_name . '/' . $themeAll[env_name]; }