= sfDynamicCMS plugin = == Overview == This plugin allows you to add a Dynamic Content Management System (CMS) to your Symfony project with the following features: - Manage different versions of a website (different applications or cultures, usually : frontend but cms can be used in a backend) - For each version : create and manage a tree structure for navigations ; breadcrumb navigation - Associate page to navigation element and edit page information (title & meta) and content - Manage navigation url and routing parameters for navigation element (generate routing rules in route.yml) - Edit access credential of navigation element - Manage administrator and editor credentials for admin module - Manage page templates (global or specific to version) and template slots - Manage page content with structured dynamic content (slots) - i18n ready (the interface is translated) ; french translation included - usable in any kind of module (by extending it or not) - User management can be controlled through [wiki:sfGuardPlugin] The aim is to give a backend admin to navigation and content management for all kind of Symfony Project. Then plugin usage is more complex that sfSimpleCMS but permits to be used in any kind of project. This CMS is not l10n, you can't have different version for a page. But you can maintain different version for a whole website. Then website can be different according to culture. This CMS has been experimented in a backend cms usage : navigation into the backend and backend help pages content are managed with the sfDynamicCMS module. This CMS is currently used by all websites (~10) developped by Author : mainly e-commerce and corporate websites. In fact, sfDynamicCMS plugin might be like a mini Content Management Framework (?) == Screenshots == [[Image(sfDynamicCMS_1.gif, 20%)]] [[Image(sfDynamicCMS_2.gif, 20%)]] [[Image(sfDynamicCMS_3.gif, 20%)]] [[Image(sfDynamicCMS_4.gif, 20%)]] == Requirements == You should have good basic Symfony knowledge, because the plugin is designed to be very extensible, it might be not easy to grips with. The prerequisites for using the `sfDynamicCMS` plugin are: - The page tree strucure use the [http://trac.symfony-project.com/trac/wiki/sfPropelActAsNestedSetBehaviorPlugin sfPropelActAsNestedSetBehaviorPlugin]. The plugin must be installed and behaviors enabled in your `propel.ini`. It is advised to have the following plugins : - Rich text editing uses tinyMCE. You must install tinyMCE if you want a wysiwyg interface for text editing. - [wiki:sfGuardPlugin] to manage permission - [wiki:sfThumbnailPlugin] to easily get image at a good size == Installation == - To install the plugin for a symfony project, the usual process is to use the symfony command line: {{{ $ php symfony plugin-install http://plugins.symfony-project.com/sfDynamicCMSPlugin }}} Alternatively, if you don't have PEAR installed, you can download the latest package attached to this plugin's wiki page and extract it under your project's `plugins/` directory. You will also have to copy the contents of the `myproject/plugins/sfDynamicCMSPlugin/web/` directory into a `myproject/web/sfDynamicCMSPlugin/` directory. - Rebuild the model, generate the SQL code for the new tables and insert it into your database: {{{ $ php symfony propel-build-all }}} - Enable the new `sfDynamicCMS` modules in your application (usually frontend), via the `settings.yml` file. {{{ // in myproject/apps/frontend/config/settings.yml all: .settings: enabled_modules: [default, sfDynamicCMS] }}} - Enable the new `sfDynamicCMSAdmin` modules in your application (usually backend), via the `settings.yml` file. {{{ // in myproject/apps/backend/config/settings.yml all: .settings: enabled_modules: [default, sfDynamicCMSAdmin] }}} - Clear Symfony default routes in routing.yml of your application managed by sfDynamicCMS (frontend usualy). It is possible to add your specific routes but don't have routes which use module variable (:module). - Give write permission to routing.yml (-rw-rw-rw- / 666) of your application managed by sfDynamicCMS (frontend usualy). - Clear the cache to enable the autoloading to find the new classes: {{{ $ php symfony cc }}} == sfDynamicCMSAdmin Configuration == sfDynamicCMSAdmin configuration require mainly to describe slots. The aim is to have a syntax which look like "Admin generator" generator.yml files for slots description. Usually configuration is also used to describe global templates which are used by all version. It is possible in admin to define templates that are used only in a specific version. === `app.yml` === {{{ sfDynamicCMS: dev_credentials: superadmin templates: intro: name: "Intro page" slots: [] home: name: "Homepage" slots: [text] page1: name: "Page model 1" slots: [text, image, doc_file] page2: name: "Page model 2" slots: [column1, date, products_ads] contact: name: "Contact" slots: [text_contact, email] slots: text: name: "Text" type: Text params : size=100x10 column1: name: "Text - 1st column" type: Text help: Don't use "CTRL+V" keystroke but "paste" icons. params: rich=true tinymce_options=height:500,width:300 date: name: "Publication date" type: Date products_ads: name: "Products" type: Double_list params: related_class=Products retrieve_method=doSelectPublished image: name: "Image" type: Image params: include_link=page include_remove=true upload_dir: page help: Download a JPEG file doc_file: name: "Documentation" type: File params: include_link=doc_pdf include_remove=true upload_dir: doc_pdf help: "Download a pdf file" email: name: "E-mail address" type: Input params: size=40 }}} - `dev_credentials`: Credential to access developper features (version and routing management). If you use sfGuard and are superadmin, you don't need to define it. - localizations: [fr, en] : Use to have different culture version : first element is the default culture == sfDynamicCMS Configuration == === `app.yml` === {{{ sfDynamicCMS: title: "My Website rules da world" default_module: page default_action: sfDynamicCMS routes_register: true localizations: [fr, en] }}} recommanded : - `title` : default title or title prefix/sufix - `default_module` module called by default while routing (usually : `default`, `my_cms_module` ) - `default_action` action called by default while routing (usually : `index` or `my_cms_action` ) facultative : - `routes_register` : Use the plugin's routes (true by default) - `localizations` : Use to have different culture version : first element is the default culture (take care to have the same for sfDynamicCMS & sfDynamicCMSAdmin) == Usage of sfDynamicCMSAdmin : Manage version, navigation and content == Start using the plugin by browsing to the admin module's default page: {{{ http://myproject/backend_dev.php/sfDynamicCMSAdmin }}} Admin is divided in 2 sections : - version management - navigation and content management If the plugin is used for the first time (when there is no version), it is needed to start by creating a version. Then : - Create a version (usualy default culture and frontend application) - Define page templates : as global (in app.yml) or as defined for this version only (in page template section) - Create root navigation element (or homepage) - Create navigation elements, create pages, define template used by pages, ... - Manage rooting parameters of navigation elements - Manage pages linked to navigation elements - Manage content of pages - Create a new version and manage his templates, pages and content - ... Next : If you want to use all the power of sfDynamicCMS you should extend one or many modules with sfDynamicCMS. == Usage of sfDynamicCMS : Extend your module to get navigation information and content == You can extend any module without modify how it work. - It is possible to extend a module dedicated to be used as CMS module (for classical pages). - It is also possible to extend a module which contain business logic like product catalog, news, ecommerce module - Without extending module, it is also possible to use all sfDynamicCMS features by coding your own methods It permit : - to get current navigation element information to know where are the visitor in the website - to get current page template and define it automaticaly - to get current page information (title, meta tags, template) and fill it automaticaly - to get page content (slots) === Action === First extends the actions.php : - actions should inherit from BasesfDynamicCMSActions {{{ require_once(sfConfig::get('sf_plugins_dir'). '/sfDynamicCMSPlugin/modules/sfDynamicCMS/lib/BasesfDynamicCMSActions.class.php'); class defaultActions extends BasesfDynamicCMSActions { ... }}} It is recommanded (but optionnal) to add the SfDynamicCMS features to all module actions by adding this 2 lines in preExecute method. You can also add this 2 lines only in actions which need SfDynamicCMS features. {{{ // Always retrieve navigation information and page content public function preExecute() { $this->executeSfDynamicCMS(); } // OR // public function executeNews() { $this->executeSfDynamicCMS(); // ... my article action code (business logic) ... // $this->news=NewsPeer::getLastNewsPublished(); } }}} - first line concern navigation : it just return the current element in navigation tree (if sfDynamicCMS is able to find it). - second line concern page, template and content : it return the current page linked to the navigation element Moreother, this feature automaticaly define page title, page meta-tags and page template. === Template files === Usually, the template file used is named with the name of the template and the suffix "Success" like `my_templateSuccess.php`. But if a template file named with the name of action and the suffix "Success" exist like `indexSuccess.php`, it will overide this. It permits to use page content (structured with a generic template slots) with a specific template defined for a specific action. Then be carefull, `indexSuccess.php` will overide your template file if you use index action which is usualy the default action (this may change for a future version). Templates are not included in sfDynamicCMS, you have to create it. Example, add in your template 'articleSuccess.php' : {{{ <?php use_helper('sfDynamicCMS'); include_component('default','submenu'); if($current_page->getSlotValue('image')) echo image_tag('/uploads/page/'.$current_page->getImage('image')); echo $current_page->getRichText('text'); if($page_oeuvre->getSlotValue('author')) echo '<p>'.link_to($current_page->getSlotValue('author'),$current_page->getSlotValue('link')).'</p>'; $next_node=$current_node->retrieveNextSibling(); if (next_node) echo '<p'>.link_to_with_path('next article',$next_node->getFirstInternalUri()).</p>; ?> }}} Be carefull, as you see in example, you need to use link_to_with_path (or button_to_with_path or url_for_with_path) for sfDynamicCMS generated links. === Component === Component are usually used for menu : main menu, sub menu or multiple levels menu Example of usage in Component actions : `components.class.php` : {{{ public function executeMenu() { //get first level navigation elements (main menu) : $this->elements=SfDynamicCmsNodePeer::getRootNode()->getChildren(); //get current first level navigation element (to highlight it in main menu): $this->current_element= sfDynamicCMS::getInstance()->getCurrentNode(1); } public function executeSumenu() { //get current first level navigation element (main menu opened) $parent_element = sfDynamicCMS::getInstance()->getCurrentNode(1); //get second level navigation elements (sub menu) if($parent_element) $this->sub_elements=$axe->getChildren(); //second way, you can just get the name of the current second level navigation element (to highlight it in sub menu) $this->current_submenuname= sfDynamicCMSTools::getCurrentUrl(2); } }}} Example of usage in Component template : `_menu.php` : {{{ <?php use_helper('sfDynamicCMS'); ?> <div id="menu"><ul><?php foreach ($elements as $element) { if ($element->isPublished()) { if (isset($current_element) && $current_element->getUrl()==$element->getUrl()) $class='menu-highlight'; $id='menu-'.$element->getUrl(); echo "<li>".link_to_with_path('<span>'.$element->getTitle().'</span>',$element->getFirstInternalUri(),array('class' => $class, 'id' => $id, 'title' => $element->getMenuName()))."</li>\n"; } } ?></ul></div> }}} Be carefull, as you see in example, you need at this time to use rawurldecode for sfDynamicCMS generated links. == sfDynamicCMS ROUTING == sfDynamicCMS permits 3 ways to define a route : - Default routing : route managed automaticaly by sfDynamicCMS - Custom routing : route managed by sfDynamicCMS, same routing parameters that routing.yml can be defined - Traditionnal routing : routing rules defined in routing.yml of the application The aim is to have a tree managed navigation which permit to have cms page, absolute url or any kind of module or action for a given node. === Custom routing === By using Custom routing, sfDynamicCMSAdmin module generate rules in routing.yml (without erasing your own rules). sfDynamicCMS will recognize this kind of rules. This way is usefull to merge your business logic with cms features offered by sfDynamicCMS. === Default routing === By using Default way, there is nothing to define, route is managed automaticaly but not permit to have use a specific module or action. Default routing doesn't appear in routing.yml, this rules are executed after custom and traditionnal routing rules. === Traditionnal routing === Traditionnal rules can defined in routing.yml before or after the sfDynamicCMS rules (which are automaticaly updated). Be carefull because sfDynamicCMS might not be able to find where are located this rules in sfDynamicCMS navigation tree. == Dev information == Please note that this plugin is in perpetual development. If you want to help and improve it, please contact Sylvain Papet (my firstname @ com-ocean.com). Business logic : - "version" = nav (navigation tree) => SfDynamicCmsNav class & sf_dynamic_cms_nav table - "navigation element" = node (navigation node) => SfDynamicCmsNode class & sf_dynamic_cms_node table - "Page" = page => SfDynamicCmsPage class & sf_dynamic_cms_page table - "Content" = slot => SfDynamicCmsSlot class & sf_dynamic_cms_slot table The plugin has 2 main goals : - manage navigation and version - manage pages and content The aim is to have independance between these 2 logics sfDynamicCMS class : - sfDynamicCMS : represent current version: the sfDynamicCMS navigation. Use in your module to perform navigation management. - sfDynamicCMSTools : static functions to use in extended module and static function used by sfDynamicCMSAdmin - model classes : for nav, node, page & slot - slotType classes : used in sfDynamicCMSAdmin & model (works look-like sfSimpleCms slots) A lot of things can be refactored and improved. == TODO == === Global === * sylvio : publish plugin on Symfony svn & link Wiki page to README * sylvio : pages management section in version management * sylvio : enhancement : backend interface === CMS Features === * sylvio : check and enhance title parameter usage * sylvio : add new slot types * sylvio : add new helper functions === Routing & Navigation === * sylvio : check nodes which has same url while creating or updating and display warning * sylvio : review node url function * sylvio : review/refactor localization routing management * sylvio : ability to have custom tags for a node (e.g. menu_id, menu_image) or a version (title, ...) === Doc === * sylvio : API * sylvio : Routing (relative url & tree routing, localization / multi-culture) * sylvio : Sandbox == Changelog == === 2008-10-04 | 0.2.1 Alpha === * sylvio : fix usage of sfDynamicCMSAdmin button "before" bug * sylvio : fix route bug : order of custom route rules generated in routing.yml * sylvio : add Select and CheckBox slot types * sylvio : ability to have absolute url like : "http://www.symfony-project.org" * sylvio : ability to have empty url to have url generated with node menu name * sylvio : default sfDynamicCMS action is now sfDynamicCMS (instead of index) * sylvio : remove getThumbnail method (unusefull - use directly sfThumbnail helper) === 2008-26-03 | 0.2.0 Alpha === * sylvio : downgrade to Alpha (Beta was not correct in precedent version) * sylvio : '''BC (Break compatibility)''' in sf_dynamic_node table : "name" field renamed "url" field and "url" field renamed "absolute_url" field, then use getUrl() instead of getName() in template {{{ ALTER TABLE `sf_dynamic_cms_node` CHANGE `url` `absolute_url` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ALTER TABLE `sf_dynamic_cms_node` CHANGE `name` `url` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL }}} * sylvio : refactor routing : parameters field disapear (parameters are defined in url like in routing.yml rules) * sylvio : refactor slots & add "Date", "Double_list", "Custom" slots * sylvio : sfDynamicCMSAdmin module is now extensible (in order to permit to add custom slot templates) === 2008-25-03 | 0.1.2 Beta === * sylvio : Fix an important bug appearing in 0.1.1 (credential bug during installation) * sylvio : make i18n ready "page templates section" & some i18n correction * sylvio : add "Date" slot type === 2008-17-03 | 0.1.1 Beta === * sylvio : allow flexible model extension by adding an additional level of class inheritance (http://trac.symfony-project.com/wiki/HowToExtendPropelPluginModel) * sylvio : add helper to generate link, url & button (in order to correct '/' conversion) * sylvio : check write permission to routing.yml files * sylvio : add method to check access credentials in sfDynamicCMS module * sylvio : add generic action named 'sfDynamicCMS' to sfDynamicCMS module * sylvio : security fix (access to 'index' action from sfDynamicCMSAdmin module) * sylvio : use of sfThumbnailHelper (in PluginsfDynamicCmsPage) === 2008-14-03 | 0.1.0 Beta === * sylvio: initial release