📜 ⬆️ ⬇️

Working with static pages in Yii

In this article I want to consider writing basic functionality for working with static pages. The task seems rather trivial, but if we need nesting of pages, it must be admitted that it becomes more complicated. In this article I want to offer a simple solution for such a task, which, I think, can cover most of the requirements for static pages put forward by small websites.

And, actually, there are not so many requirements:


Since the described requirements are imposed on the functionality necessary for most of the created sites, it makes sense to arrange it as a module, and in the future just copy the latter from project to project.

Our entire system will revolve around a simple array, called its map of paths . Each element of the array characterizes a separate page. The primary keys (further ID) of the pages in the database are used as array indices, and the paths to the corresponding pages are used as values.
')
Thus, the task is to write code that should:


So let's get started. Let's start by creating a table for storing pages. The SQL query for this is as follows:

CREATE TABLE IF NOT EXISTS `pages` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `root` int(10) unsigned NOT NULL, `lft` int(10) unsigned NOT NULL, `rgt` int(10) unsigned NOT NULL, `level` int(10) unsigned NOT NULL, `parent_id` int(10) unsigned NOT NULL, `slug` varchar(127) NOT NULL, `layout` varchar(15) DEFAULT NULL, `is_published` tinyint(1) unsigned NOT NULL DEFAULT '0', `page_title` varchar(255) NOT NULL, `content` text NOT NULL, `meta_title` varchar(255) NOT NULL, `meta_description` varchar(255) NOT NULL, `meta_keywords` varchar(255) NOT NULL, PRIMARY KEY (`id`), KEY `root` (`root`), KEY `lft` (`lft`), KEY `rgt` (`rgt`), KEY `level` (`level`) ); 

As can be seen from the request, the method of storing “nested sets” trees is used to build the hierarchical structure; therefore, when adding the administrative part of the module, it will make sense to use the Nested Set Behavior extension.

Next, using Gii, we generate the module framework (let's call it pages), as well as the model for working with the newly created table (we will call it Page).

Let's correct the code of the created module. Add the $ cacheId attribute to store the identifier for the cached path map.

During module initialization, a check should be made to see if there is a path map in the cache, and if it is absent there, a map that is up to date should be generated. To do this, we add the function init ().

We also add three methods: generating, updating and returning a map of paths. Total, the module code takes the following form:

 class PagesModule extends CWebModule { /** * @var string ,       */ public $cacheId = 'pagesPathsMap'; public function init() { if (Yii::app()->cache->get($this->cacheId) === false) $this->updatePathsMap(); $this->setImport(array( 'pages.models.*', 'pages.components.*', )); } /** *     . * @return mixed */ public function getPathsMap() { $pathsMap = Yii::app()->cache->get($this->cacheId); return $pathsMap === false ? $this->generatePathsMap() : $pathsMap; } /** *         . * @return void */ public function updatePathsMap() { Yii::app()->cache->set($this->cacheId, $this->generatePathsMap()); } /** *   . * @return array ID  =>    */ public function generatePathsMap() { $nodes = Yii::app()->db->createCommand() ->select('id, level, slug') ->from('pages') ->order('root, lft') ->queryAll(); $pathsMap = array(); $depths = array(); foreach ($nodes as $node) { if ($node['level'] > 1) $path = $depths[$node['level'] - 1]; else $path = ''; $path .= $node['slug']; $depths[$node['level']] = $path . '/'; $pathsMap[$node['id']] = $path; } return $pathsMap; } } 

We have finished with this module class; don't forget to let the application know about it by adding the module identifier to the modules property of the configuration array.

Now create the PagesUrlRule rule class inherited from CBaseUrlRule. It is enough to declare only two methods: to create and to parse the URL. The code for creating the URL looks like this:

 public function createUrl($manager, $route, $params, $ampersand) { $pathsMap = Yii::app()->getModule('pages')->getPathsMap(); if ($route === 'pages/default/view' && isset($params['id'], $pathsMap[$params['id']])) return $pathsMap[$params['id']] . $manager->urlSuffix; else return false; } 

The method checks the existence of the page in the map of paths, and when it finds it returns the path to it (do not forget about the URL suffix! - I like the addresses to end with a slash).

Method code to parse the URL (here, on the contrary, the page ID is searched along the path to it)

 public function parseUrl($manager, $request, $pathInfo, $rawPathInfo) { $pathsMap = Yii::app()->getModule('pages')->getPathsMap(); $id = array_search($pathInfo, $pathsMap); if ($id === false) return false; $_GET['id'] = $id; return 'pages/default/view'; } 

Do not forget to add an entry with reference to the rule class in the configuration array. Well, since we are returning here a link to the default controller, it is useful to provide its code.

 class DefaultController extends Controller { public function actionView($id) { $page = $this->loadModel($id); $this->render('view', array( 'page' => $page, )); } public function loadModel($id) { $model = Page::model()->published()->findByPk($id); if ($model === null) throw new CHttpException(404, '   .'); return $model; } } 

Actually, everything. The functionality for parsing, creating a URL, and displaying pages to a visitor is ready. And the implementation of the page management functionality (it is quite standard), if you wish, you can look at the finished project, which can be downloaded from here .

UPD1. Fixed work with the cache, added indexes to the table, updated link to the file with the finished project.

Source: https://habr.com/ru/post/155927/


All Articles