# Tutorial 2 - Extending a basic site ## Overview In the [first tutorial](1-building-a-basic-site) we learned how to create a basic site using SilverStripe. This tutorial builds on what you have learned in [the first tutorial](1-building-a-basic-site), so it is recommended that you complete it first. In this tutorial you will explore extending SilverStripe by creating your own page types. In doing this you will get a good overview of how SilverStripe works. ## What are we working towards? Throughout this tutorial we are going to work on adding two new sections to the site we built in the first tutorial. The first is a news section, with a recent news listing on the homepage and an RSS feed. The second is a staff section, which demonstrates more complex database structures by associating an image with each staff member. ![](_images/news-with-rss-small.jpg)![](_images/einstein-small.jpg) ## The SilverStripe data model A large part of designing complex SilverStripe sites is the creation of your own page types. Before we progress any further, it is important to understand what a page type is, and how the SilverStripe data model works. SilverStripe is based on the **"Model-View-Controller"** design pattern. This means that SilverStripe attempts to separate data, logic and presentation as much as possible. Every page has three separate parts which are combined to give you the final page. Lets look at each one individually: ### Model All content on your site is stored in a database. There is a table in the database corresponding for every class that is a child of the `[api:DataObject]` class. Every object of that class corresponds to a row in that table - this is your "data object", the **"model"** of Model-View-Controller. A page type has a data object that represents all the data for your page - rather than inheriting directly from data object it inherits from `[api:SiteTree]`. We generally create a "Page" data object, and subclass this for the rest of the page types. This allows us to define behavior that is consistent across all pages in our site. ### View The **"view"** is the presentation of your site. As we have already seen, the templates SilverStripe uses to render a page is dependent on the page type. Using both your templates and css, you are able to have full control over the presentation of your site. ### Controller A page type also has a **"controller"**. A controller contains all the code used to manipulate your data before it is rendered. For example, suppose you were making an auction site, and you only wanted to display the auctions closing in the next ten minutes. You would implement this in the controller. The controller for a page should inherit from `[api:ContentController]`. Just as we create a "Page" data object and subclass it for the rest of the site, we also create a "Page_Controller" that is subclassed. Creating a new page type simply requires creating these three things. You can then have full control over presentation, the database, which fields can be edited in the CMS, and can use code to make our pages do much more clever things. A more in-depth introduction of Model-View-Controller can be found [here](http://www.slash7.com/articles/2005/02/22/mvc-the-most-vexing-conundrum). ![](_images/pagetype-inheritance.jpg) ## Creating the news section page types Let's make our news section. We'll need two new page types for this. The first one is obvious: we need an *ArticlePage* page type. The second is a little less obvious: we need an *ArticleHolder* page type that contains our articles. We'll start with the *ArticlePage* page type. First we create the model, a class called "ArticlePage". We put the *ArticlePage* class into a file called "ArticlePage.php" inside *mysite/code*. We also put the controller, *ArticlePage_Controller*, in here. Any other classes that are related to *ArticlePage* – for example, the class *ArticlePage_AnythingElse* - will also go into "ArticlePage.php". **mysite/code/ArticlePage.php** :::php Here we've created our data object/controller pair, but we haven't actually extended them at all. Don't worry about the *$db* and *$has_one* arrays just yet, we'll explain them soon, as well as other ways in which you can extend your page types. SilverStripe will use the template for the *Page* page type as explained in the first tutorial, so we don't need to specifically create the view for this page type. Let's create the *ArticleHolder* page type. **mysite/code/ArticleHolder.php** :::php Here we have done something interesting: the *$allowed_children* field. This is one of a number of static fields we can define to change the properties of a page type. The *$allowed_children* field is an array of page types that are allowed to be children of the page in the site tree. As we only want news articles in the news section, we only want *ArticlePage* pages for children. We can enforce this in the CMS by setting the *$allowed_children* field. We will be introducing other fields like this as we progress; there is a full list in the documentation for `[api:SiteTree]`. Now that we have created our page types, we need to let SilverStripe rebuild the database. If we rebuild the database by going to [http://localhost/dev/build?flush=1](http://localhost/dev/build?flush=1), SilverStripe will detect that there are two new page types and add them to the list of page types in the database. > It is SilverStripe convention to suffix general page types with "Page", and page types that hold other page types with > "Holder". This is to ensure that we don't have URLs with the same name as a page type; if we named our *ArticleHolder* > page type "News", it would conflict with the page name also called "News". ## Adding date and author fields Now that we have an *ArticlePage* page type, let's make it a little more useful. Remember the *$db* array? We can use this array to add extra fields to the database. It would be nice to know when each article was posted, and who posted it. Change the *$db* array in the *ArticlePage* class so it looks like this: :::php 'Date', 'Author' => 'Text' ); // ..... } Every entry in the array is a key-value pair. The key is the name of the field, and the value is the type. We have a `[api:Date]` for a complete list of different data types. > Note: The names chosen for the fields you add must not already be used. Be careful using field names such as Title, > Content etc. as these may already be defined in the page types your new page is extending from. If we rebuild the database, we will see that now the *ArticlePage* table is created. Even though we had an *ArticlePage* page type before, the table was not created because we had no fields that were unique to the article page type. We now have the extra fields in the database, but still no way of changing them. To add these fields to the CMS we have to override the *getCMSFields()* method, which is called by the CMS when it creates the form to edit a page. Add the method to the *ArticlePage* class. :::php addFieldToTab('Root.Content', new DateField('Date'), 'Content'); $fields->addFieldToTab('Root.Content', new TextField('Author'), 'Content'); return $fields; } } // ... Let's walk through this method. :::php $fields = parent::getCMSFields(); Firstly, we get the fields from the parent class; we want to add fields, not replace them. The *$fields* variable returned is a `[api:FieldList]` object. :::php $fields->addFieldToTab('Root.Content', new DateField('Date'), 'Content'); $fields->addFieldToTab('Root.Content', new TextField('Author'), 'Content'); We can then add our new fields with *addFieldToTab*. The first argument is the tab on which we want to add the field to: "Root.Content" is the tab which the content editor is on. The second argument is the field to add; this is not a database field, but a `[api:FormField]` documentation for more details. :::php return $fields; Finally, we return the fields to the CMS. If we flush the cache (by adding ?flush=1 at the end of the URL), we will be able to edit the fields in the CMS. Now that we have created our page types, let's add some content. Go into the CMS and create an *ArticleHolder* page named "News", and create some *ArticlePage*s inside it. ![](_images/news-cms.jpg) ## Modifing the date field **Please note:** As of version 2.4, the DateField type no longer automatically adds a javascript datepicker. Your date field will look just like a text field. This makes it confusing and doesn't give the user much help when adding a date. To make the date field a bit more user friendly, you can add a dropdown calendar, set the date format and add better title. :::php addFieldToTab('Root.Content', $dateField = new DateField('Date','Article Date (for example: 20/12/2010)'), 'Content'); $dateField->setConfig('showcalendar', true); $dateField->setConfig('dateformat', 'dd/MM/YYYY'); $fields->addFieldToTab('Root.Content', new TextField('Author','Author Name'), 'Content'); return $fields; } Let's walk through these changes. :::php $fields->addFieldToTab('Root.Content', $dateField = new DateField('Date','Article Date (for example: 20/12/2010)'), 'Content'); *$dateField* is added only to the DateField in order to change the configuration. :::php $dateField->setConfig('showCalendar', true); Set *showCalendar* to true to have a calendar appear underneath the Date field when you click on the field. :::php $dateField->setConfig('dateformat', 'dd/MM/YYYY'); *dateFormat* allows you to specify how you wish the date to be entered and displayed in the CMS field. :::php $fields->addFieldToTab('Root.Content', new TextField('Author','Author Name'), 'Content'); By default the first argument *'Date'* or *'Author'* is shown as the title, however this might not be that helpful so to change the title, add the new title as the second argument. See the `[api:DateField]` documentation for more details. ## Creating the templates We can already look at the content of news pages on our site, because the article holder page and the article pages inherit their templates from Page. But we're not getting the author and date fields displayed in either case. So let's create a template for each of our new page types. We'll put these in *themes/tutorial/templates/Layout* so we only have to define the page specific parts: SilverStripe will use *themes/tutorial/templates/Page.ss* for the basic page layout. First, the template for displaying a single article: **themes/tutorial/templates/Layout/ArticlePage.ss** :::ss <% if Menu(2) %>
$Content.FirstSentence