ENHANCEMENT Added sapphire/docs (migrated from https://github.com/chillu/silverstripe-doc-restructuring)

This commit is contained in:
Ingo Schommer 2011-02-07 19:48:44 +13:00
parent a569567acf
commit 8bd01d62c4
229 changed files with 25915 additions and 0 deletions

2
docs/LICENSE Normal file
View File

@ -0,0 +1,2 @@
Licensed under Creative Commons Attribution 3.0 New Zealand
http://creativecommons.org/licenses/by/3.0/nz/

0
docs/_manifest_exclude Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,46 @@
# 2.0.1 (2007-04-17)
SilverStripe 2.0.1 was released on '''17 April 2007''' and had the following changes:
## Overview
* Improved layout of UserDefinedForm submissions in CMS
* Don't show name field on root folder in Assets section
* Mime types fallback for servers don't have /etc/mime.types
* mb_string module is now an optional dependency
* Added strong_create method to Object, as useCustomClass was not working correctly
## Bugfixes
* Sapphire
* Text->FirstParagraph() now only shows the first paragraph
* Fixed HTMLText->Summary()
* Fixed layout issues on IE7 for TreeDropdownField
* Don't show Akismet errors to user
* Removed overloaded MemberTableField->sourceItems() that was causing problems
* Fixed UserDefinedForm submission emails
* Fixed UserDefinedForm permissions
* If a file extension doesn't have a maximum upload size associated with it, then allow uploads of any size
* Fixed a bug with the TreeMultiselectField that prevented it from displaying the checkboxes
* Made Scheduled tasks concrete so they can be instantiated
* TableField fixes
* Fixed security vunerability in search
* GD::color_web2gd() was using incorrect substr
* Fixed last link css
* Fixed duplicate checkbox fields in UserDefinedForm
* Fixed css in UserDefinedForm
* CMS
* Fixed sizing of tabs in CMS
* Fixed popup for single asset in Files & Images section
* Fixed link to CMS on default homepage
* Fixed permissions table in Security section
* Fixed el no properties error in IE
* Pressing the flash button a second time now hides the dropdown
* Installer
* Fixed MySQL version check
* Merge with existing .htaccess file
* Test that mod_rewrite is working
* Added option to delete installer files after successful install
* Fixed PHP4 parse error so installer loads and shows correct error message
* Apache test passes if apache is used but apache php functions are not available
* SilverStripe needs at least PHP version 5.0.4

155
docs/en/changelogs/2.0.2.md Normal file
View File

@ -0,0 +1,155 @@
# 2.0.2 (2007-07-14)
SilverStripe 2.0.2 was released on '''14 July 2007''' and had the following changes:
## Overview
* BlackCandy is the new default theme
* Added pagination for page comments
* Updated date field in CMS-edited forms to use CalendarDateField
* Added 'open in new window' checkbox to link inserter
* Added dimension fields when inserting images
## Features and Enhancements
* Much more API Documentation
* Modules must now have _config.php files in order to be loaded
* New Classes
* PermissionProvider
* Improved Classes
* CalendarDateField
* Added a calendar icon
* CheckboxSetField
* Prepared for use editing a many-many join in the CMS, popualted with a SQLMap object
* ClassInfo
* Added implementorsOf()
* ContentNegotiator
* Added set_encoding() to choose a character set other than utf-8
* DatabaseAdmin
* Removed populate() as it was a security risk, the initial content is now loaded via requireDefaultRecords()
* DataObject
* Added add_extension() for adding decorators in _config.php
* DataObjectDecorator
* Added extraDBFields() for modifying the decorated data objects, adding extra database fields
* Email
* Added send_all_emails_to()
* Added cc_all_emails_to()
* Added bcc_all_emails_to()
* Replaced sentLiveErrorsTo() with send_errors_to(), for more flexibility
* Form
* Added current_action()
* Added single_field_required()
* FormField
* Added Required(), so that you can put asterisks into a form template if you wish
* GenericDataAdmin
* Updated to use new permission model
* LeftAndMain
* Added second argument to setApplicationName() so that the name in the top corner and the name shown elsewhere can be 2 different strings
* Permission
* Added get_codes()
* Profiler
* Added trace argument to show()
* Added profiling scaffolds
* Added ?profile_trace=1 url variable tool to show a trace on the profiler
* Sorted the output of profiler
* Improvements to profiling information
* TableField
* Added option to aid putting TableFields inside the ComplexTableField popup
* TreeDropdownField
* Added setTreeBaseID(), for showing a sub-tree in your field
* Javascript
* Added event.setStyle to prototype_improvements.js
* Add class text field to image properties dialog in TinyMCE
* Added ?debug_behaviour=1 URL option for debugging behaviour calls with Firebug
## Bugfixes
* CMS
* Forms in newsletter & security section were incorrectly submitting when enter was pressed
* Fixed search in MemberTableField
* Don't show popup when validation fails in Security section
* Fixed bug where scrollbars aren't shown in the CMS
* Let CMSMain be used to manage objects without Sort
* The help button now redirects to http://userhelp.silverstripe.com
* Version displayed in CMS now works correctly
* Fixed CMS action button support when text size increases
* Added message when report is empty
* fixed (overrides) to CSS to avoid larger font-size due to em values
* Fixed tree scrolling and resizing issues
* Fixed sizing issues with CMS right content area
* Fixed bug with image insertion
* Fixed bug where new pages weren't being highlighted in the CMS
* Fixed bug where the last page in the site tree wasn't being highlighted in the CMS
* Fixed reordering of groups in security section
* Improvements to image inserter
* Sapphire
* Reduced warnings when E_NOTICE is enabled
* Fixed validation of date fields in a user defined form
* Fixed multiple security groups being created when logging in with default admin
* Fixed permissions for administrating page comments
* Fixed ContentController::PageComments() method to die if spammers are POSTing form data when comments are disabled
* Fixed permission checking on PHP 5.0.5
* Fixed 'cannot access protected property' error in Security section on PHP 5.0.5
* Fixed javascript validation of forms
* Fixed error when asp_tags = On
* Fixed bug where you have a non-required field with numeric validation
* Added a limit of 20 steps in Breadcrumbs generation
* Changed SiteTree.Title length from 100 to 255
* Fixed random password generator in Member::createNewPassword()
* Fixed BatchProcess to not display an error if no objects could be processed
* Fixed a bug where a user is redirected incorrectly after logging in
* Changed temp-folder selection to not leave temp files lying around, and put silverstripe temp files into a silverstripe-cache folder
* Made guid of PageComments in rss feed unique
* Removed duplicate XML class
* Fixed bugs caused by missing html elements
* Fixed code to remove need for short_open_tag
* Fixed FileSize generation for sizes of just over 1 meg
* only show $messageBlock in FormField::FieldHolder() if $Message is existing
* fixed rightTitle and id in FormField::FieldHolder()
* Fixed ?isDev=1 mode
* Set default of sendWarnings on Debug::send_errors_to
* Fixed formatting of error emails sent from ajax requests
* Removed debug plumbing from the results of Debug::backtrace()
* Simplified return data of htmlEmail, an inconsequential internal optimisation
* Create assets folder if it doesn't exist when uploading a file
* Fixed bug in SiteTree::NestedTitle()
* Don't append /home to the home page URL
* Small fix for windows installations
* Fixed efficiency problems in Versioned::get_latest_version
* Fixed File::sync(), to let it recurse into new directories in a single execution
* Fixed bug with getting form action that was breaking form submission and complextablefield pop-up
* Fixed SQLMap iteration
* Simplified EmailField validation error message
* Fixed some bugs in the debug emailer
* Reduced amount of ajax-refetching that the TreeSelectorFields do
* Fix macron support in reports
* Improved debug message (remove big blocks of redundant data)
* Allow for the disabling of default buttons. Apply this to CMSMain and GenericDataAdmin in the administration, so that we don't default to clicking the *DELETE* button.
* Added default value to first arg of permissionFailure(); it's not actually used!
* Improved handling of EditableFormFields on new UserDefinedForms
* Improved search results message shown on first load
* Made calendar control register a date change when the calendar is used
* Set some good defaults in DataObjectSet::TotalPages() if they have not been set
* Changes to support forum
* Require authenficiation to do a db/build on live sites
* Close directories before trying to remove them
* Fixed a bug where CheckboxSetField wouldn't save if there was a method the same as the field name
* Fix multiple "broken" in class attribute of HTML Content
* Fixed bug with TreeDropdownField when you clicked the expand link 3 or more times, it wouldn't close
* Fixed bug when editing properties of new text fields
* Fixed duplicate of UserDefinedForm objects
* JSParty
* Fixed a bug where you couldn't always edit the bottom of an WYSIWYG editor field
* Ensure that WYSIWYG context menu always appears on the screen
* Javascript performance improvements
* Fix weird bug in behaviour to do with class.applyToChildren
* Improved console.log alternative
* Installer
* Added option of installing either the default template, or the tutorial template
* mod_rewrite check now works with http authentification
* Workaround for 'URL file-access is disabled in the server configuration' using curl for mod_rewrite test
* Better error message if the installer can't detect the web server
* Added an alternative .htaccess configuration
* Less file permissions required by the installer
* Made deleting the installer files more prominent, it now deletes all the installations files, not just php.
* MySQL password is now a hidden field.

171
docs/en/changelogs/2.1.0.md Normal file
View File

@ -0,0 +1,171 @@
# 2.1.0 (2007-10-02)
SilverStripe 2.1.0 was released on '''2 October 2007''' and had the following changes:
## Overview
* Comment administration section, and comment moderation
* Allow CMS users to limit view/edit access to a page
* Show an rss link for page comments on each page
## Upgrading
### Too many redirects
A problem occurs of 'too many redirects' or the page just doesn't load (home page) because of these situations:
* Access tab for home page has 'logged in users only', OR
* NO radio buttons have been set. This happens when upgrading site from old DB.
It's caused by a redirect to Security/login on the home page controller, which is blocked off, so you can't actually
login, so it infinitely loops a redirect. See http://open.silverstripe.com/ticket/1488
## Features and Enhancements
* Theme support
* Widget support
* Better extension API
* Unit testing framework
* More API documentation
* Added support for __ss_environment.php files
* New classes
* BankAccountField
* BBCodeParser
* HasManyComplexTableField
* HasOneComplexTableField
* ManyManyComplexTableField
* NewsletterType
* RestfulService (from mashups module)
* Improved classes
* ComplexTableField
* Validation in popup
* ContentController
* Added project()
* Controller
* Added redirectedTo()
* Convert
* Added raw2htmlatt()
* Added raw2mailto()
* DatabaseAdmin
* Drastically improved database build performance
* DataObject
* Added ID,ID,ID syntax for populating many-many joins
* DataObjectDecorator
* Allow member CMS fields to be added
* DataObjectSet
* Added getRange()
* Date
* Added past_date()
* Director
* Added set_dev_servers()
* Added set_test_servers()
* Added redirected_to()
* Refactored CMS page-URL accessing to use ->AbsoluteLink(), which can be overridden by defining alternateAbsoluteLink()
* Debug
* Optionally hide backtrace-headers in message() and show() (applied in 'showqueries')
* Email
* MimeType-fallback (from /etc/mime.types)
* Improved validation in is_valid_address()
* FieldSet
* Added insertAfter()
* Form
* Automatic filesystem backup of POST-data
* FormField
* Support for right-aligned titles
* Custom CSS-classes by addExtraClass() and removeExtraClass()
* Group
* Added Description field
* HtmlEditorField
* Allow classes other than 'typography' to be set
* Image
* Added PaddedImage()
* ImageField
* Added readonly transformation
* PageCommentInterface
* Added anchors to page comments, and made rss feed link to them
* Permission
* Added $strict flag to check()
* Allow passing of an array of permission codes to get_members_by_permission()
* Added get_groups_by_permission()
* PhoneNumberField
* Improved validation
* Security
* Added basicauthlogin()
* SecurityAdmin
* Added EDIT_PERMISSIONS permission code
* TableField
* Validation and RequiredFields
* TableListField
* Added sorting, highlighting, formatting
* Improved styling
* TreeDropdownField
* Improved styling
* Varchar
* Added RTF()
* ViewableData
* Added `<% if HasPerm(PERM_CODE() %>` for templates
* Javascript
* Implemented showIndicator() and hideIndicator()
* Improved statusMessage() to clear manually instead of fixed interval
* Added hideStatusMessage()
#### Bug Fixes
* CMS
* Fix specific newsletter bug
* Don't show classes user doesn't have permissions to change to in class dropdown
* Fix reading of Live pages in CMSMain
* Fix double page reading after changing the class
* Fix insert flash
* Fix version regex for release candidates
* Fix delete in Files and Images section
* Fixed saving root folder causes error
* Fixed "non-numeric ID" error that occurs when visiting newsletter section for a newsletter that doesn't exist (caused by session sometimes)
* Fixed CMS sort subpages bug
* Sapphire
* Improved spam detection
* Support for running SilverStripe in safe mode and under open_basedir restrictions
* PHP notice fixes
* Use normal authentification rather than basicauth for db/build
* Fix CSS of profiler pop-up
* Changed DropdownField $emptyString syntax from '0' to ''
* Fixed IE6 DOM-parsing bug caused by FormResponse::load_form()
* Triggering previewwrite for 'delete' and 'replace' SQL-actions
* Changed record-insertion in DataObject
* Boolean accepts database-default
* Fixed Permission::get_members_by_permission()
* Added memory_limit to publishall()
* Fix many-many component set relation setting
* The Link for a RedirectorPage points to its target
* Add SQL_ prefix in place it was missing in Email
* Added a check to make sure record exists before calling hasMethod on it in CheckboxSetField
* Fixed bug in DataObject::addStaticVars()
* Check for string 'true' as well as boolean in SiteTree::MetaTags()
* Fix AllNewsletters value not being passed to OptionSetField in SubscribeForm
* Improved the encapsulation of ErrorPage publication
* Fix redirect back after failing login
* Fixed renaming of .tar.gz and .tar.bz2 files
* Fixed validation of DateField, EmailField and NumericField
* Fix livesite bug for visibility handling difference between PHP5.2.0 and PHP5.1.6
* Changed colouring of db/build to be more appropriate for the actual meaning of the messages
* Fixed redirection from /home/ to /./ in IE6
* Use the homepage as a model for the security base-page, so that things like the current subsite are factored in
* Sorted permission codes in Permission::get_codes
* Changes to support gallery module
* Added missing has_many in DataObjectDecorator
* Replace empty strings in SQL queries with NULL
* JSParty
* TinyMCE has been updated to 2.1.1.1
Installer
* New installer look based on BlackCandy
* Use the new theme system
* Add first and last name fields
* Added ability to set servers that will be in dev mode
* When the posix module isn't present, throw a warning instead of dying
* Warn if PHP version is less that 5.2.0 in support of GoPHP5 (http://www.gophp5.org)
* Added favicon to installer and default template
* Optional reporting of version information to SilverStripe
* Installer now runs with short tags disabled
* open_basedir and safe mode fixes

View File

@ -0,0 +1,22 @@
# 2.1.1 (2007-11-02)
SilverStripe 2.1.1 was released on '''2 Nov 2007''' and had the following changes:
## Bug Fixes
* CMS
* BBCode help link now works inside CMS
* Fixed invalid 'cursor: normal' CSS in cms_left.css
* Ensure ComplexTableField CSS is loaded in CMS
* Fixed blank comments showing in Comment Admin
* Ensure behaviour is applied correctly to new fields in a UserDefinedForm
* Fixed fatal error in Newsletter Admin on some servers
* Sapphire
* Fix infinite redirects when upgrading from 2.0.2
* Use the hostname, not the ip address, in dev/test mode tests
* Changed the include of the BBCodeParser so it works on more systems
* Fixed saving of HasOneComplexTableField and HasManyComplexTableField when value is undefined
* Removed extra comma in TableListField.js
* Fixed redirection of login when login fails
* Fixed bug where removing a comment via ajax removed all comments from display
* Fix $_SESSION not saving correctly on some servers

342
docs/en/changelogs/2.2.0.md Normal file
View File

@ -0,0 +1,342 @@
# 2.2.0 (2007-11-28)
SiverStripe 2.2.0 was released on '''28 November 2007''' and had the following changes:
## Upgrading
### Login Form
Check that you have a Layout/Page.ss file for your site, or alternately have a Security_login.ss template.
Your template file needs a $Form variable for it to work. This is where the login form gets included. Without either of
these, the Security/login form will be blank.
### Form Actions HTML/CSS
Check css/js and subclassed templates of Form.ss for changed markup. A global search for "p.Actions" should cover both
js/css changes.
:::ss
// before
<p class="Actions">
// after
<div class="Actions">
See http://open.silverstripe.com/changeset/43562
### Form Security Token
There has been a hidden 'SecurityID' field added to SilverStripe generated forms by default, with the purpose to stop
CRSF attacks. If you wish your form not to be tied to a specific session, and able to be able to be executed by URL
without the SecurityID, you can disable it on your form with
:::php
$form->disableSecurityToken();
The other issue to be aware of is constructing the URL to execute the form manually, as is done in javascript sometimes.
If the security token is enabled, you need to add its value to the URL, eg:
:::js
updateURL += ($('SecurityID') ? '&SecurityID=' + $('SecurityID').value : '');
### Custom Section in CMS
Special attention will need to be given to custom sections on a case-by-case basis.
As we have changed the design of the CMS, the top bar for your custom sections is no longer needed. We've moved the
buttons that it once held down to the bottom.
![](_images/cms22screenie.jpg)
### Classes added to 2.2 that may conflict
Sitemap.php
## Features
* New look for CMS
* Support for authentification by OpenID (auth_openid module included with installer)
* Google Sitemaps support
* Internationalisation support
* German translation
* Dutch translation
* Chinese (simplified) translation
* Spanish translation
* French translation
* Croatian translation
* Polish translation
* Portuguese (Portugal) translation
* Support for multilingual content
* Added a Statistics area showing the following reports
* Page views
* User activity
* Trends
* Operating Systems
* Browsers
* Added an image editor, allowing a user to rotate, crop and resize an image from within the CMS
* Added profile popup in CMS
* Added a 'Sent Status Report' tab to Newsletters with the following reports
* Sending to the following recipients failed
* Sending to the following recipients bounced
* The newsletter has never been sent to following subscribers
* Sending to the following recipients was successful
* Sending to the following recipients did not occur because they are blackListed
* Add 'Send to only people not previously sent to' option for sending newsletters
* Added SWFUpload library as default method of uploading files
* Added photo upload in from the Site Content section
* Added the ability to search the Site Content tree
* Added the ability to publish selected pages
* Added a list of unused assets in the Files & Images section, and the ability to delete unused thumbnails
* Usability improvements
* Move action buttons to bottom right of screen
* Moved insert image/flash/link to pane on right
* Removed right frame headers as the buttons have been moved and they only contain redundant information
* Use a javascript dialog box for confirming unsaved changes instead of the slow loading model one
* Reworked the tabs in the Newsletter section to be less confusing
* Cancel button added to Send Newsletter window
* External logo link opens in a new window
* Left sections in Site Content 'Site Tree', 'History' and 'Reports' now use expandable sections rather than tabs
* Relabeled 'Site Tree' to 'Site Content & Structure', 'History' to 'Page Version History' and 'Reports' to 'Site Reports' in left sections of Site Content
* Relabeled 'Files & Images' left frame to 'Folders'
* Added tooltips to site content tree, showing the page type
* In the 'Page Version History', use a checkbox lable 'Compare mode (click 2 below)' instead of a dropdown
* Renamed 'Save draft' button to 'Save'
* The 'Save' button text changes to 'Saving...', and the 'Publish' button text changes to 'Publishing...' when they are clicked
* Added save indicator to all 'Save' buttons, the 'Save & Publish' button and the 'Unpublish' button while they are being submitted
* Added a go button to the 'Site Reports' dropdown
* Relabeled 'Name' field to 'Folder Name' in Files & Images section
* Renamed the 'Save' button to 'Save folder name' in Files & Images section
* Relabeled 'Send newsletters from' field to 'From email address' in Newsletter section
* Removed the 'Move Files' button from Files & Images section, implemented multi-file drag & drop moving
* Add 'Newsletter Settings' tab to Newsletter type edit form for consistency with other forms
* Make the status message shown after sending a newsletter always include the # of emails sent
* Added delete confirmation for items in Newsletter left tree
* Added delete confirmation for items in Security left tree
* Make 'Add new draft' the default action for 'Create...' in the Newsletter section
* Replace the 'reorganise' button with 'Allowing drag & drog reordering' checkbox
* Delete and Unpublish buttons turn red on hover
* Added the ability to align images 'left on their own'
## Enhancements
* New classes
* Authenticator, allowing multiple authentification methods
* ConfirmPasswordField
* DropdownTimeField
* i18n, for internationalisation
* LanguageDropdownField
* LoginForm, base class for login forms for each authentification method
* MemberAuthenticator, providing username/password authentification
* MemberLoginForm, refactored from old LoginForm form
* PopupDateTimeField
* ToggleField
* OpenIDAuthenticatedRole, which is an extension to Member that adds OpenID authentification columns
* OpenIDAuthenticator, providing OpenID authentification
* OpenIDLoginForm, providing OpenID sign in
* PageView, which saves the details of each page view for statistics
* Statistics, which provides static methods for statistics
* Translatable, for multilingual content
* New third party libraries
* PHP OpenID (http://openidenabled.com/php-openid/)
* Browscap (http://garetjax.info/projects/browscap/)
* Plotr (http://www.solutoire.com/plotr/)
* SWFUpload (http://profandesign.se/swfupload/)
* Improved classes
* CalendarDateField
* Refactored part of Field() into HTMLField() so it can be used in PopupDateTimeField
* ComplexTableField
* Improved pagination in popup
* Better transformation of save-button (replaced indicator with "saving..." label)
* CompositeField
* Added SmallFieldHolder() to properly render fields in a FieldGroup
* Added insertBeforeRecursive()
* Allow empty children
* Added Field()
* Added linebreaks for HTML
* ConfirmedFormAction
* Respect $extraClass
* ContentController
* Save statistics on page views
* Added LangAttributes(), for use in XML header
* Draft/Archived content can only be viewed by users with permission to access the CMS
* Core
* Added _t() for internationalisation
* Check if TEMP_FOLDER is already defined before defining it, allowing the user to set the temporary folder themself
* DataObject
* Added merge()
* Director
* Added extend_site(), which allows modules to register a function that will be run on every page load
* redirectBack() now redirects to the base URL if neither the referrer nor the _REDIRECT_BACK_URL is set
* Added support for translatable URLs
* Added is_cli()
* Added set_status_code() and get_status_code()
* Email
* Define 'EMAIL_BOUNCEHANDLER_KEY' in sapphire/_config.php and require its value to be sent as 'Key' $_GET var in pings to /Email_BounceHandler to prevent fake email bounce pings
* Display an error on duplicate bounce logs instead of a blank screen
* If the contents of the X-SilverStripeMessageID header is sent to /Email_BounceHandler in the 'SilverStripeMessageID' _GET variable, then it will be logged in the Newsletter_SentRecipient table so that the bounce report will show up on the 'Sent Status Report' tab of the Newsletter
* Bounced newsletter recipient emails and blacklisted by default
* FieldSet
* Added insertBeforeRecursive()
* FileSystem
* Added $file_create_mask and $folder_create_mask, which are used whenever creating new files/folders in sapphire
* Form
* All Forms now have a hidden SecurityID field to prevent CSRF attacks
* Added disableSecurityToken() to disable the SecurityID field
* Added securityTokenEnabled()
* Changed `<p class="Actions">` to `<div class="Actions">`
* Renamed PureName() to Name()
* GD
* Added rotate()
* Added rotatePixelByPixel(), allowing rotation where the imagerotate function is unavailable
* Added crop()
* Added getWidth()
* Added getHeight()
* Hierachy
* Versioned now automatically add suffixes, so Hierachy no longer needs to
* HTTP
* Added register_modification_timestamp()
* Added register_etag()
* ImageField
* Improved layout
* Int
* Added support for default value
* ManifestBuilder
* Refactored getClassManifest() for clearer ignore rules
* Ignore i18n language files
* Ignore folders that have a '_manifest_exclude' file
* Member
* Automatically login user if the 'remember login' cookie is set
* Added createNewPassword(), which generates a random password, optionally using a word list
* Added support for password encryption
* Added Locale field to store user preferred language
* Added the ability for Member decorators to augment MemberFormFields()
* MemberLoginForm (refactored from old LoginForm)
* Save the email address in the session to reuse when the login fails
* ModelAsController
* Added support for translatable URLs
* Object
* Added require_developer_login(), which allows you to check if the user has permission to use URL debugging tools
* ?debugmethods=1 now requires developer login
* PageComment
* Added the ability to have BBCode in comments (disabled by default)
* PasswordField
* Always show five stars in performReadonlyTransformation(), so it is impossible to use the information of the password length for brute-force attacks
* Permission
* Added declare_permissions()
* Added get_declared_permissions_list()
* Added traverse_declared_permissions()
* Added Permission_Group class, used to group permissions together for showing on an interface
* Added $admin_implies_all, if this is false then the 'ADMIN' permission doesn't imply all permissions
* Refactored Permission::checkMember(), should be faster now because the non-strict checking is now only executed if the user doesn't has the permission
* Added deny(), giving the ability to define 'deny permissions'
* RecipientImportField
* Added default 'GenericEmail.ss' template
* RestfulService
* Added caching
* RSSFeed
* Added support for conditional GETs
* Security
* Added support for password encryption
* Added set_word_list() and get_word_list(), to set the location of the word list used in Member::generateNewPassword()
* Session
* Added save(), which copies the current controllers session to $_SESSION
* SiteTree
* Changed references to 'stage site' to 'draft site' in TreeTitle()
* Use Translatable interface by default
* Add content language in MetaTags()
* Add delete class to unpublish and rollback buttons
* SSViewer
* Added support for internationalisation in templates, using `<% _t() %>`
* Added $Iteration in templates, which keeps track of the number of iterations in a control block
* TableListField
* Prevent onclick event in td.markingcheckbox from showing the popup
* TabSet
* Remove tabset div to reduce wasted space on tabs
* Added insertBeforeRecursive()
* ToggleCompositeField
* Refactored from TogglePanel
* Added icons and used 'cursor: pointer' to make it obvious that it is clickable
* Versioned
* Added the ability to versionise suffixed tables that have names that are not DataObject descendants
* Added canBeVersioned()
* Added extendWithSuffix()
* Added hasVersionField()
## Bugfixes
* Sapphire
* E_NOTICE fixes
* Fixed incorrect deprecated message in Convert::raw2xml()
* Don't show and error message and quit the script when @ is used to suppress the error
* Changed width of HTMLEditorFields to prevent horizontal scrollbars in IE7
* Added checks in DataObjectSet::First() and DataObjectSet::Last() to prevent errors on an empty $items array
* Fixed incorrect treatment of Member::logout() as a static method in Security::logout()
* Ensure Priority is set in SiteTree::onBeforeWrite(), otherwise an invalid SQL statement will be generated when the page is published
* Only highlight broken links in HTMLEditorFields once, to prevent execution timeouts when there are lots of identical broken links
* Fixed bug "Fatal error: Access to undeclared static property: Controller::$db in ../sapphire/core/Object.php(282) : eval()'d code on line 1"
* Fixed DataObjectDecorators not supporting indexes and defaults
* Fixed ReportField generating invalid HTML
* In Member::setBlacklistedEmail() call this->write() so that the BlacklistedEmail field state will be saved to the Member database table
* Fix Email_BlackList::isBlocked() to check the BlockedEmail field instead of non-existant Email field so that it will actaully return true when an email is blocked
* Fix layout problems with search box in IE by only generating a label tag if TItle is set in FormField::FieldHolder()
* Fixed Permission::check() not p[assing $strict to Permission::checkMember()
* Fixed HTTP::gmt_date()
* Fix validation of Member extensions
* Removed DriversLicense references from LoginForm (project specific clutter)
* Added check for existence of #sitetree in RelationComplexTableField.js
* Fixed VirtualPage creation
* Fixed lighttpd flushing bug
* Fixed CustomRequiredFields
* Fix bugs with ComplexTableField when it is used outside of the CMS
* Fixed error saving when value is undefined in HasOneComplexTableField and HasManyComplexTableField
* Fixed saving error in FileIFrameField
* Added a security fix for Security::check_default_admin()
* Fixed caching in DataObject::getManyManyComponents() to take into account different SQL parameters
* Geop::ip2country() now throws an E_USER_NOTICE instead of an error when it cannot run geoiplookup
* Added if() check around a foreach loop that was causing errors when there were no entries in an RSS feed
* Fix inheritance in ManyManyComplexTableField
* Fixed FormField::setRightTitle() not showing because of a typo
* Create assets folder if doesn't eixts on ErrorPage publish
* Fixed submission of ImageField when no file was selected
* Catch errors in ContentController::deleteinstallfiles()
* Fix generation of group codes on creation of a Group
* Fix title on LabelledLiteralField
* Fix ImageField deleting the Image instead of unlinking it from the page
* Set TimeField value to null when a bad value is passed
* Don't return a span when the Title doesn't exist in DropdownField
* Fix bug where NumericField couldn't have 0 as a default value
* Call Page_Controller->init() when rendering Security/changepassword etc to respect any Requirements called in there
* Fixed an error when a CheckboxSetField is submitted with no checkboxes ticked
* Fixed exporting of TableListField to use commas for CSV files
* ?previewwrite no longer works on live sites
* Fixed incorrect CSS in TableListField.css
* Fixed incorrect namespacing in TableListField::BaseLink()
* If a CreditCardField is completely blank, then it's not invalid. Required-fields should be used to check for values.
* CMS
* E_NOTICE fixes
* New pages are created in the database straight away, which solves a number of issues
* Fixed Email link not working in page history
* Unsaved changes detection now works in Security section member tables
* Fix typo in LeftAndMain::addTreeNodeJS() by renaming 'select' parameter to 'selected' because 'selected' is what is used in the method body
* Delete image thumbnails after deleting an image
* Use 'html>body' instead of just 'html>' so that #sitetree correctly gets assigned width:auto on Mozilla browsers (prevents Folders being selected from 500px away on file drag and drop)
* Display a useful error message if getCMSFields() returns null
* When 'Duplicate this page' is clicked, first silently (without confirmation) save the page, then duplicate it so the new page is identical to the other page
* Fix errors when importing recipients to newsletter mailing list
* Fixed blocking during resize in IE6
* Don't show a 'No template selected' error when sending a test Newsletter if no template has been selected since templates for Emails are optional
* Fixed bug 'for newly created newsletter drafts, content of newsletter sent is not what is shown on screen'
* Don't save new Newsletter drafts as soon as they are created to prevent TinyMCE Javascript errors in IE
* Add if((typeof tinyMCE != 'undefined')) statement around call to tinyMCE.init() to prevent "Error: 'tinyMCE' is undefined" error in IE7 on Newsletter Recipient import
* Don't allow a deleted draft to be edited in the Newsletter section
* Fix a bug where newsletter drafts will be added, but not show up in the left tree (because of a Javascript error), if no selection has been made
* If there are no newsletter types, and 'Add new draft' is chosen, create a newsletter type to prevent errors
* Fix changed icon only showing after Save button is clicked twice
* Fixed VirtualPage creation
* Fix 'Sort subpages' not working correctly
* Use classes instead of the align tag to align images

View File

@ -0,0 +1,33 @@
# 2.2.1 (2007-12-21)
SilverStripe 2.2.1 was released on '''21 December 2007''' and had the following changes:
## Features and Enhancements
* Translations
* Added Italian translation
* Added Russian translation
* Added Slovak translation
* Added Turkish translation
* Added Bulgarian translation
* Added Czech translation
* Added Hungarian translation
* Added Portuguese (Brazil) translation
* Added Swedish translation
* Added Chinese (Taiwan) translation
* Added support for sapphire to Portuguese (Portugal) translation
#### Developer Tools
* Added augmentDefaultRecords(), so DataObjectDecorators can extend requireDefaultRecords
Bug fixes
* Sapphire
* Hardcoded array of encryption algorithims in Security::get_encryption_algorithms(), as a bug in MySQL causes corruption in dumps with enums with commas
* Fixed bug with google sitemap on translated sites
* Removed title from SecurityID fields, as some forms show labels on HiddenFields
* Fixed Object::uninherited() for PHP 5.1.2
* Added empty array to member so that roles can add their own has_one relations
* CMS
* Added SecurityAdmin_rightbottom.ss
* Javascript
* Upgraded TinyMCE to 2.1.3

396
docs/en/changelogs/2.2.2.md Normal file
View File

@ -0,0 +1,396 @@
# 2.2.2 (2008-05-22)
SilverStripe 2.2.2 was released on '''22 May 2008''' and had the following changes:
## Features and Enhancements
* Set svn:externals for new phpinstaller release tags/2.2.2 (changeset 54973)
* Disable / fix flash uploading (changeset 54959)
* Fixed php/code snippets in forum posts (changeset 54619)
* BUGFIX #2504 - Fixed translation interface not working in CMS (changeset 54472)
* Removed references to 'mot' folder in code (changeset 54407)
* #2501 + #2500 - Fixed notice-level errors in editable forms (changeset 54402)
* #2482 - Fixed newsletter unsubscribe (changeset 54215)
* #2447 - Bug in editing comment (changeset 54212)
* Don't mark a test site as being in dev mode if set_test_servers matches (changeset 53373)
* FEATURE: added phpdoc comments to the API calls for customising CMS rebranding (changeset 53216)
* BUGFIX: Ticket #2449 - Fixed unsubscribe function - because it's extending ContentController without a data record, we have to hack this by using null in the parent::__construct() - This however, should be refactored to have a data record (page in the CMS) (changeset 53210)
* MINOR: PHP notice fix - undefined variable (changeset 53204)
* MINOR: Fixed some php notices (changeset 53188)
* BUGFIX: Removed display: none for "nolabel" class - this is custom project code, and shouldn't be in sapphire! (changeset 53175)
* BUGFIX: Ticket #2455 - Check variable exists before accessing Password index (changeset 53160)
* BUGFIX: Removed undefined variable $mem - we include ini_set for memory_limit in main.php instead (changeset 53156)
* _t call for EXPORTCSV problem fixed (changeset 53106)
* DataReport EXPORTCSV field missing (changeset 53105)
* API CHANGE Removed deprecated/incomplete Synchronise class - please do not use for production purposes (changeset 53101)
* Made has_one, has_many, and many_many methods more reliable (changeset 53075)
* Fix drag&drop in assets and security (changeset 53073)
* Make double-redirects a warning rather than an error, since they are usually benign. (changeset 53066)
* Don't redirect from /home to / if you've already called a redirection. (changeset 53066)
* Fixed ContentController where ->dataRecord is empty (changeset 52719)
* Don't strtolower ->action, as it had too many side-effects. (changeset 52452)
* #2387 - Fields specified in DataObjectDecor not saved in some cases (changeset 52448)
* Newsletter import: only send a change notification email if there are changes to be sent (changeset 52434)
* #2378 - Fixed newsletter import (changeset 52432)
* Fixed Authenticators to work with r52400 (changeset 52401)
* #2299 - Fatal error in specific version of PHP (changeset 52400)
* BUGFIX re-initializing tabstrip javascript after ajax-reload in AssetTableField popup (#2309 AssetTableField popup fails after saving) (changeset 52399)
* Fix to ManifestBuilder when running site on windows in a directory containing \r or \t or \n (changeset 52398)
* #2388 - Fixed CMS search. (changeset 52395)
* BUGFIX disable third party browscap by default (#2336) (changeset 52394)
* formatting (changeset 52393)
* Upgraded SWFUpload to improve CMS uploads (changeset 52392)
* Show security id errors on test sites as well as dev (changeset 52391)
* Improved behaviour of contentcontrollerInit when extensions are applied to subclasses of SiteTree (changeset 52350)
* fix comment admin not working correctly (changeset 52309)
* Added LeftAndMain::set_loading_image() for replacing the image shown when the CMS is loading (changeset 52298)
* Fix pagecomment links and feeds (changeset 52296)
* fix links in RSS feeds (changeset 52295)
* don't cache in overridden instance_get(), as the fields are different for subclasses (changeset 52293)
* #2314 - Fixed SQLMap implementation so that Group::map() returns appropriate data, and the group dropdown on the access tab works. (changeset 52224)
* #2362 - Fixed change password form (changeset 52213)
* Add scrollbar to RHS link inserter, so you can see everything (changeset 51973)
* Fix to anchor insertion (changeset 51963)
* fix php notice (changeset 51938)
* Make Object::hasMethod() and Object::__call() case-insensitive, and added tests for it (changeset 51462)
* Test for hasMethod (changeset 51461)
* Fixes to TestRunner for latest PHPUnit/PHP (changeset 51459)
* API CHANGE Allow for tests that don't use the database - don't define a static SapphireTest:: (changeset 51150)
* Fixed typo in r51150 (changeset 51151)
* Fixed HomepageForDomain behaviour when entering multiple domains (changeset 51436)
* API CHANGE Added RestfulService::httpHeader() for setting custom headers on REST requests (changeset 51203)
* API CHANGE Added RestfulService::basicAuth() for setting authentication for REST requests (changeset 51203)
* API CHANGE Added param to RestfulService::connect(), to allow for requesting of multiple URLs from a single RestfulService object. (changeset 51203)
* Updates to usability & IE support of link insertion (changeset 51081)
* #2265 Installer falsely claims modrewrite fails (mamp) (merged from trunk, r50698) (changeset 51070)
* #2282 Undefined index in install.php (merged from trunk, r50698) (changeset 51069)
* #2266 Fresh install of SilverStripe? doesn't let you upload or view images to insert, until you first go into Files and Images area (merged from trunk, r50695) (changeset 51068)
* Cleaned up ChangeLog (changeset 51064)
* updated changelog for 2.2.2 (changeset 51042)
* Added delete from stage button to CMS (changeset 50852)
* Added Translations for Danish (Denmark) - thanks to Jesper and Dennis (changeset 50824)
* Added Translations for Esperanto - thanks to Wojtek, Donald, Evan and Joop (changeset 50824)
* Added Translations for Finnish (Finland) - thanks to Elias, Vesa and Nina (changeset 50824)
* Added Translations for LOLCAT - thanks to Wojtek (changeset 50824)
* Added Translations for Sinhalese (Sri Lanka) - thanks to Nivanka, Himali and Lakshan (changeset 50824)
* Updated several translations in cms/auth_openid/sapphire (changeset 50824)
* Added package names for i18n files (changeset 50824)
* Reverted patch from r47694 which introduced conditional statements in lang-files (changeset 50824)
* Added Translations for Danish (Denmark) - thanks to Jesper and Dennis (changeset 50824)
* Added Translations for Esperanto - thanks to Wojtek, Donald, Evan and Joop (changeset 50824)
* Added Translations for Finnish (Finland) - thanks to Elias, Vesa and Nina (changeset 50824)
* Added Translations for LOLCAT - thanks to Wojtek (changeset 50824)
* Added Translations for Sinhalese (Sri Lanka) - thanks to Nivanka, Himali and Lakshan (changeset 50824)
* Updated several translations in cms/auth_openid/sapphire (changeset 50824)
* Added package names for i18n files (changeset 50824)
* Reverted patch from r47694 which introduced conditional statements in lang-files (changeset 50824)
* Added Translations for Danish (Denmark) - thanks to Jesper and Dennis (changeset 50824)
* Added Translations for Esperanto - thanks to Wojtek, Donald, Evan and Joop (changeset 50824)
* Added Translations for Finnish (Finland) - thanks to Elias, Vesa and Nina (changeset 50824)
* Added Translations for LOLCAT - thanks to Wojtek (changeset 50824)
* Added Translations for Sinhalese (Sri Lanka) - thanks to Nivanka, Himali and Lakshan (changeset 50824)
* Updated several translations in cms/auth_openid/sapphire (changeset 50824)
* Added package names for i18n files (changeset 50824)
* Reverted patch from r47694 which introduced conditional statements in lang-files (changeset 50824)
* #2283 Permissions are a bit broken - what happened to all the CMS permissions? (changeset 50957)
* #2310 MemberTableField Popup breaks after saving (changeset 50954)
* #2310 MemberTableField Popup breaks after saving (changeset 50954)
* BUGFIX fixed csv export in MemberTableField by checking for valid database columns when building SELECT statement (changeset 50952)
* FEATURE added hasDatabaseField() (changeset 50949)
* BUGFIX properly setting $childID in form for newly created items to avoid duplicates after subsequent saving (the form reloaded without the ID connection) (changeset 50947)
* Make RSS feed work with objects that don't support AbsoluteLink, such as the forum (changeset 50921)
* fixing typo in parameter name $validate --> $validator (changeset 50641)
* made $messageType parameter of Validator::validationError optional, and added API docs to explain what (apparently) is going on (changeset 50645)
* fixing bug with in-memory child objects not having their parent ID field updated via the ->add() method (changeset 50815)
* #2302 - Fixed double-escaping of CTF popup page-navigation links (changeset 50903)
* reverted r49775 (accidental removal of "add" feature, its actually not redundant functionality) (changeset 50854)
* fixed xhtml error (forgot closing `<p>`) (changeset 50849)
* updated en_US master entities (changeset 50844)
* updated en_US master entities (changeset 50844)
* updated en_US master entities (changeset 50844)
* fixed PHP notices (changeset 50840)
* fixed PHP notices (changeset 50838)
* formatting, fixed PHP notices (changeset 50836)
* fixed PHP notice (changeset 50829)
* documentation (changeset 50814)
* #2285 - Fixed widget editor (changeset 50812)
* added $searchable_fields in preparation for a more generic search implementation, currently limited to Member.php and MemberTableField.php (mainly to fix bugs caused by r49774 and r47856) (changeset 50805)
* fixed weird indentation formatting in Member.php (changeset 50805)
* Fixed default-setting for link anchor (changeset 50786)
* Added 'anchor' option to link inserter (changeset 50783)
* Fixed svn:externals (changeset 50776)
* Moved externals to used HTTP for 3rd-party friendliness (changeset 50764)
* fixed typo (changeset 50729)
* added database indexes for AuthorID and PublisherID (changeset 50723)
* #2265 Installer falsely claims modrewrite fails (mamp) (changeset 50697)
* #2295 - DataObjectSets cannot be iterated over multiple times concurrently (changeset 50683)
* #2280 - Fixed XML parsing errors in CTF (changeset 50488)
* #2287 - Removed notice-level error when geoip's not installed (changeset 50487)
* Fixed newlines in to-do report (changeset 50361)
* #2277 - Fixed notice-level error on controllers that are direct subclasses of controller (changeset 50352)
* Added support for password and old_password encryption mechanisms if you're using MySQL (changeset 50290)
* Small fix for session bugs on Lightspeed server (changeset 50245)
* A bit of a hack to fix double-escaped URLs in the CMS. (changeset 50214)
* Fixed CMS bottom-navigation after publish, when using the subsites module (or other alternateAbsoluteLink implementors) (changeset 50205)
* Fixed password emailing for edited members (changeset 50200)
* Allow use of on controller extensions (changeset 50180)
* Fixed 4.1-sort-by-group-aggregate query rewriter for sort functions containing columns, eg, ORDER BY if(A,B,C), X (changeset 50179)
* Fixed notice level error (changeset 50047)
* Fixed bug with BasicAuth enabled on an old database, it was preventing you from visiting db/build (changeset 50031)
* Fixed MySQL 4.1 support for situations where we are sorting by a group aggregation function (changeset 49999)
* Fixed notice level error (changeset 49999)
* fixed caching in getManyManyComponents (see r43848) (changeset 49946)
* removed redundant error strings (changeset 49922)
* Added a default exception handler. Any uncaught exceptions thrown from application code are now scooped up by the Debug::fatalHandler (changeset 49906)
* (changeset 49906)
* Still some small problems with displaying stack traces of exceptions because the context array from trigger_error looks quite different from that of Exception::getTrace (changeset 49906)
* (changeset 49906)
* Also fixed a couple of echo/print bugs in Debug::friendlyError. From the looks of the code there may be more bugs to cleanup here. (changeset 49906)
* Fixed Controller::allowed_actions documentation (changeset 49896)
* Added to main CMS controllers (changeset 49895)
* Removed warning in group admin (changeset 49894)
* Improved allowed_actions support for subclassed controllers, such as CMSMain extends LeftAndMain (changeset 49893)
* Removed use of deprecated setExtraClass (changeset 49892)
* Moved _ss_environment.php include to very top (changeset 49891)
* Added deprecation note to BulkLoaderAdmin (changeset 49890)
* added $casting for BaseHref() (changeset 49843)
* fixed sql-injection (changeset 49834)
* Updated AssetAdmin to use TreeTitle() in place of Title for tree generation (changeset 48425)
* > Updated TreeTitle() to allow use of alternateTreeTitle() in decorator (changeset 48425)
* > Updated File to allow the insertion of extra columns by decorator (changeset 48425)
* Updated subject line of warning/error emails (changeset 49732)
* Moved folder admin form to Folder::getCMSFields() to let you more easily manipulate the form with a decorator (changeset 49804)
* Disabled notice level error until more of the core is compliant (changeset 49803)
* Moved CMS page-disabled logic into SiteTree::CMSTreeClasses(), so that it can be more easily customised for specific sites (changeset 48376)
* Added Member->SetPassword, a field that lets you have a write-only password field (changeset 46525)
* Used Member->SetPassword to create a password column on the MemberTableField for SecurityAdmin (changeset 46525)
* Send 'changed password' emails when a user is first created as well as edited (changeset 46525)
* Fixed DataObjectSet::insertFirst() - it now uses a numeric key rather than null (changeset 45750)
* Create Group::canEdit(), which can be used to filter the SecurityAdmin group list (changeset 45748)
* Redirect to legislation section when there are only legislation pages (changeset 45654)
* Allow selection of folder when inserting files / images (changeset 45654)
* Minor bugfixes (changeset 43980)
* Added additional checks so that the email doesn't get sent to new members, or on the test site. (changeset 43384)
* Used Object::create() to create email instances sent by the system. (changeset 43342)
* Added BaseHref() to Member_ChangePasswordEmail so that the email shows the domain name of the current subsite. (changeset 43340)
* Tidied up lost password form. (changeset 43339)
* Added Member::$notify_password_change (changeset 43336)
* Added missing ChangePasswordEmail.ss (changeset 43335)
* Saving the member with a changed password now sends an email to the member. (changeset 43334)
* Updated AssetAdmin to use TreeTitle() in place of Title for tree generation (changeset 48425)
* > Updated TreeTitle() to allow use of alternateTreeTitle() in decorator (changeset 48425)
* > Updated File to allow the insertion of extra columns by decorator (changeset 48425)
* Updated core to allow for subsites restriction of filesystem: Folder::getCMSFields() is now responsible for generating the folder form. (changeset 48401)
* Folder::syncChildren() now exclusively uses DB::query() calls instead of DataObject::get(). (changeset 48401)
* Moved CMS page-disabled logic into SiteTree::CMSTreeClasses(), so that it can be more easily customised for specific sites (changeset 48376)
* Removed redundant Add Member button at the top-right (changeset 46526)
* Added Member->SetPassword, a field that lets you have a write-only password field (changeset 46525)
* Used Member->SetPassword to create a password column on the MemberTableField for SecurityAdmin (changeset 46525)
* Send 'changed password' emails when a user is first created as well as edited (changeset 46525)
* Changed call to ViewableData::castingHelperPair to fix sort not being set by getNewItem (changeset 43365)
* Added LeftAndMainSubsites->augmentNewSiteTreeItem that allows extensions of LeftAndMain to provide the current SubsiteID for the new item. (changeset 43321)
* CMSMain->getNewItem now calls $this->extend('augmentNewSiteTreeItem', $newItem); (changeset 43321)
* Changed DataObject to be a subclass of ViewableData instead of Controller, so that it can't be hacked by visiting Page/write. (changeset 49767)
* reverted accidental delete in r49761 (changeset 49766)
* e-This line, and those below, will be ignored-- (changeset 49766)
* (changeset 49766)
* A svn://svn.silverstripe.com/silverstripe/open/themes/blackcandy/trunk/blackcandy_blog (changeset 49766)
* reverted accidental delete in r49760 (changeset 49765)
* revert accidental commit in r49763 (changeset 49764)
* readding blackcandy (reverted r49761, r49762) (changeset 49763)
* Removed unused blackcandy blog (changeset 49762)
* Removed unused themes (changeset 49761)
* #2200 - Allowed subclasses in ComponentSet::add/remove (changeset 49715)
* #1878: wakeless: Supress disabled errors on live site (changeset 49709)
* Merged r49479 from branches/2.1.1-madebyme (changeset 49658)
* Merged r46528 from branches/2.1.1-madebyme (changeset 49657)
* Bypass debug handler for E_USER_NOTICE as well as E_NOTICE (changeset 49593)
* #2203 - ManifestBuilder regex (changeset 49448)
* fix caching in complex table field (changeset 49447)
* added setFields()/setActions() (changeset 49386)
* formatting (changeset 49386)
* reverted accidental commit (changeset 49352)
* added gwgtn theme files (changeset 49349)
* Added SS_DEFAULT_ADMIN_USERNAME/PASSWORD defines to conf/ConfigureFromEnv.php (changeset 49308)
* #177 - Don't let people create a page name the same as a class name (changeset 49193)
* Disabled unused files list, as it uses way too much memory (changeset 49192)
* #1921 - Make DataObject::write() call the recursive write on components, even when the dataobject itself hasn't changed (changeset 49187)
* #1956 - Show Title in RSSFeed (changeset 49184)
* simon_w: #1954 - Added object caching methods (changeset 49182)
* #1951 - Fix newsletter subscription form (changeset 49181)
* Removed clone behaviour from Form::Fields() (changeset 49180)
* Added SubscribeSubmission template to get subscribeforms to work (changeset 49177)
* Added default SubscribeForm.ss (changeset 49176)
* Fixed ManifestBuilder execution in restrictive openbasedir environments (changeset 49172)
* #1987 - Fixed sitename/?url=sitename bug (changeset 49151)
* #2016 - Added all the types of error pages (changeset 49150)
* #2137 - Changed email encoding from iso-8859-15 to utf-8, in compliance with other parts of SilverStripe and IMC recommendations (changeset 49149)
* fixed i18n::get_owner_module() calls on classes with _s (changeset 49148)
* Improvement to link-insertion logic when selecting text that doesn't have a link (changeset 49147)
* #1881 - Duplicated words in error message text (changeset 49066)
* documentation (changeset 49033)
* documentation (changeset 49032)
* fixed typo in doc comment (changeset 48972)
* fix sql error on comments section (changeset 48970)
* #2088 - Notice level error on compare versions (changeset 48969)
* #2005 - Fixed seamonkey browser recognition (changeset 48968)
* fix upload folder (changeset 48857)
* #2212 / #2201 - Fix notice-level errors in PageView updates (changeset 48941)
* mrickerby: #2201 - fixed PageView's recording of referrers. (changeset 48912)
* For some project we need server run some scheduled task yearly, such as upgrade high school students for GSO. (changeset 48906)
* updating form in ctf-popup after saving (including validation-errors and fields that have may changed on the serverside, e.g. ImageField) (changeset 48874)
* not all cms panel has sitetree, so better check if($('sitetree')) exsit, otherwise IE broken with all genericDataAdmin panel. (changeset 48869)
* adding "delete" class to DeleteImageForm (changeset 48865)
* compressed ImageField layout to fit in CTF-popup (removed "click here to remove" label) (changeset 48855)
* removed iframe-borders for IE (changeset 48855)
* fixed "object not found" error in ie6 (somehow Observable is not applied to sitetree at window-load) (changeset 48847)
* Polishing EducatorAdmin's Students Tab (changeset 48844)
* locking down URLs: image/iframe, image/flush, image/transferlegacycontent (changeset 48835)
* Recover ExportForm for genericDataAdmin Which is needed for CRM CreateCommunication (changeset 48792)
* Add ability to choose which file to upload to in a FileField (changeset 48785)
* Fixed illegal reference to this (changeset 48688)
* Put MenuTitle in the CMS LHS tree instead of Title (changeset 48462)
* (changeset 48451)
* Fix incorrect text boxes being set on an ajax request (changeset 48178)
* Allow many-many complex table fields to be used on the reverse side of the join (belongs many many) (changeset 48082)
* Removed ranking tools from DataObjectSet (changeset 47743)
* implemented equal values (changeset 47459)
* (changeset 47454)
* Added simple to-do list facility to SiteTree (changeset 47172)
* Added title attributes to the SilverStripeNavigator messages (changeset 47156)
* Fix bug when duplicating pages with reorganise enabled (changeset 48507)
* Added paste plain text and paste from word buttons to the HtmlEditorField in the CMS (changeset 47155)
* Added 'duplicate page and children' context-item in addition to 'duplicate just this page' (changeset 48503)
* Fixed context menus in CMS (changeset 48474)
* Fixed 404 on spacer.gif (changeset 47190)
* Fixed bug in todo list reprot (changeset 47174)
* Added simple to-do list facility to SiteTree (changeset 47172)
* Added paste plain text and paste from word buttons to the HtmlEditorField in the CMS (changeset 47157)
* Added paste plain text and paste from word buttons to the HtmlEditorField in the CMS (changeset 47155)
* #2005 - Fixed fatal error due to browscap.ini capitalisation error (changeset 48514)
* Updated windmill tests - sleeps and waits (changeset 48431)
* Added in_array_recursive() to ArrayLib, for recursively checking an array with nested arrays (changeset 48423)
* fix the bug that initialises with preloaded selected items with right hide/show (changeset 48419)
* Added sapphire/conf/ConfigureFromEnv.php for making use of _ss_environment.php (changeset 48359)
* Fixed formatting of code, and added some documentation on what the source for this field should be (changeset 48326)
* (changeset 48313)
* Fix sorting in complextablefield (changeset 48257)
* wakeless: #2144 - More memory-efficient version of admin/publishall (changeset 48242)
* #1736 - Make Security::get_encryption_algorithms() a dynamic function again. (changeset 48227)
* Fixed comment. (changeset 48200)
* Fixed bug: Page class wasn't shown in add-page dropdown (changeset 48176)
* Fixed admin credentials setting from 'make install' and 'make test' (changeset 48175)
* Added the contents of assets/ to svn:ignore (changeset 48175)
* Added Windmill test for editing content (changeset 48173)
* Re-enabled session_regenerate_id() (changeset 48172)
* renamed escapeFlagForField() to escapeTypeForField(), updated documentation (changeset 48168)
* Deprecated use of DBField 'Text' for saving HTML-Content (added check in HTMLEditorField->saveInto()) (changeset 48164)
* Added ViewableData->escapeFlagForField() to determine if the record-field needs escaping (currently only 'xml' supported) (changeset 48164)
* Refactored session_regenerate_id to make it easier to disable in some circumstances. (changeset 48161)
* Temporarily disabled session_regenerate_id so that Windmill can work. (changeset 48161)
* Removed notice level errors for better cli-script operation (changeset 48153)
* Better error for cli-install errors, uses exit(1) to stop make (changeset 48152)
* Added note about Makefile so that people don't think they should use that for normal installation. (changeset 48133)
* Allow calling of installer by running 'make install' from an environment with an _ss_environment.php file. This is important for continuous integration. (changeset 48132)
* formatting (changeset 48113)
* formatting (changeset 48112)
* removed dropDatalessFields() - needs serious refactoring before going into core again (changeset 48110)
* removed dropDatalessFields() - needs serious refactoring before going into core again (changeset 48109)
* renamed $wantDefaultAddRow to $showAddRow (changeset 48105)
* fixed escaping errors in default homepage content (changeset 48104)
* Added Makefile so that you can execute 'make test' in sapphire and it will run tests. (changeset 48100)
* Added support for array in _ss_environment.php for specifying URLs to use for cli-script.php (changeset 48100)
* Improved the Behaviour.addLoader() method to play more nicely with tools such as windmill (changeset 48086)
* fix bug: when no source items found, the table should still show and it should works as adding new records (changeset 48085)
* Fixed the $hide_ancestor static on SiteTree subclasses so that it actually works. (changeset 48056)
* Fixed login test (changeset 48049)
* Added initial windmill test (changeset 48042)
* Fix php notice (changeset 47985)
* FIx php notice (changeset 47982)
* Fix autocompletion in Security Admin (changeset 47956)
* #892 - Error attaching an existing folder to an ImageField (changeset 47948)
* Fix spelling mistake (changeset 47947)
* Remove having clause as it can't be used (changeset 47946)
* simon_w: #2122 - Bug in PageComments class (Security) (changeset 47937)
* #2058 - Installer does not escape passwords in _config files (changeset 47910)
* converted TODO into @todo for better PHPDocumentor support (changeset 47891)
* Fix i18n errors (changeset 47890)
* #2094: Make ContentNegotiator send XHTML to the W3C validator (changeset 47882)
* Fix externals (changeset 47881)
* Fix DataObjectSet constructor breaking with associative arrays (changeset 47880)
* simon_w: #2118 - When removing a value from an enum, set affected rows back to the default (changeset 47877)
* simon_w: #2098: Fixed notice level error (changeset 47876)
* #1874 - generated .htaccess lacks "Rewritebase" (changeset 47875)
* fix wrong warning info: Director -> Debug (changeset 47858)
* rbarreiros: 019 - Lost Locale when translatable string not found (changeset 47857)
* rbarreiros: #1907 - Patch for more i18n strings (changeset 47856)
* #1959 - You can't reorganise pages without creating pages (changeset 47855)
* Don't fail in i18n::include_by_class if the module isn't translatable (changeset 47854)
* Remove debug message (changeset 47847)
* Added $SecurityID for templates (changeset 47846)
* lperera: #1975 - Improvements to RestfulService (changeset 47844)
* #2003: Don't close img and br tags on HTMLText.Summary (changeset 47843)
* Fix syntax error (changeset 47842)
* Error checking in i18n::include_by_class shouldn't complain if mysite/lang doesn't exist - only if a module doesn't have internationalisation options. (changeset 47841)
* Reverted 47595, are it broke $defaults (changeset 47840)
* rbarreiros: #1918 Translate newsletter and other strings (changeset 47839)
* Fix building manifest before database is created (changeset 47838)
* #1352 - Better handling of memory limit (changeset 47836)
* #1212 - Show the saved value of EditableEmailField.SendCopy (changeset 47832)
* #1352 - Better handling of memory limit (changeset 47831)
* Allow insertion of `<img>` tags that refer to external domains (changeset 47827)
* Add alt= to any images that don't have alt tags (changeset 47827)
* Improvements to API docs (changeset 47826)
* documentation (changeset 47815)
* allowing object-parameters in DataObjectSet and ArrayData, added ArrayData::object_to_array() (changeset 47808)
* added is_associative() (changeset 47807)
* added lc_XX locale for LOLCAT (changeset 47813)
* Improved API documentation (changeset 47806)
* Improved API documentation (changeset 47805)
* Moved test control files into sapphire/testing, so that sapphire/tests can be ignored by the documentor. (changeset 47804)
* Use lighter version of browscap.ini (changeset 47802)
* #1088 - attachments cannot be emailed from mac or windows systems (changeset 47800)
* #172 - Reorganise : new page (changeset 47797)
* Fix php notice (changeset 47792)
* API Documentation updates (changeset 47773)
* Added tests for DataObject (changeset 47767)
* Take orderby clause into account when caching in DataObject::get_one() (changeset 47756)
* Fix caching in DataObject::get_one() (changeset 47755)
* Remove HAVING clause from methods where it doesn't make sense to have them (changeset 47754)
* set $template and $itemClass to public (according to parent implementation) (changeset 47748)
* fixed formatting (changeset 47748)
* fixed getParentIdName() call in DetailForm() - paramter-order was wrong (changeset 47747)
* better checking in saveComplexTableField() to avoid PHP-notice (changeset 47747)
* Fix YAML many_many/has_many relationships (changeset 47746)
* YAML comma seperated => lists should work on has_meny relationships as well (changeset 47739)
* Added package tags and docblock info for API documentation (changeset 47733)
* Fixed whitespace (changeset 47733)
* Updated API documentation package tags (changeset 47732)
* Fixed some whitespace (changeset 47732)
* Removed unnecessary file CMSHelp (changeset 47729)
* Removed unnecessary class Staged (changeset 47725)
* Fix stack trace on objects that don't extend the Object class (changeset 47723)
* PDODatabase got the wrong end of the stick - Database::createDatabase() shouldn't need any arguments. Fixed this in the core class and MySQLDatabase, but PDODatabse still needs fixing. (changeset 47698)
* Fixed TestRunner (changeset 47699)
* Added paste plain text and paste from word buttons to the HtmlEditorField in the CMS (changeset 47155)
* Added paste plain text and paste from word buttons to the HtmlEditorField in the CMS (changeset 47155)
* wakeless: #1976 - DataObject queries the database for child elements when it hasn't been serialized (changeset 47695)
* #1666 - Interface translations don't show in footer (changeset 47694)
* Fix title and description in RSS feeds (changeset 47688)
* Update copyright to 2008 (changeset 47657)
* update copyright to 2008 (changeset 47654)
* Update copyright to 2008 (changeset 47653)
* Added release date (changeset 47430)
* Updated Changelog (changeset 47262)
* Updated ChangeLog (changeset 46870)
* add function fieldByName (changeset 47479)
* made breadcrumbs-delimiter configurable (changeset 47634)
* Reversed isset() change which was causing some side effects (changeset 47602)
* Fixed PHP notice undefined index - $messageSet['alreadyLoggedIn'] (changeset 47600)
* Fixed ID undefined PHP notice error (changeset 47595)
* removed DetailForm() (was just needed to set custom class which is now in $popupClass), updated saveComplexTableField() to reflect parent class code (changeset 47593)
* added $popupClass to avoid duplication, getting basedataclass for existing children in DetailForm() (in case we're dealing with different subclasses) (changeset 47592)
* more solid ID-detection in php() (changeset 47591)
* additional checks before foreach() loop (changeset 47589)
* fixed PHP notice in implementorsOf (changeset 47588)
* #2069 Locale file /lang/en_US.php should exist (Windows) (changeset 47587)

View File

@ -0,0 +1,36 @@
* BUGFIX: Don't allow calling of magically added methods via URL unless explicitly listed in allowed_actions (changeset 64988)
* BUGFIX: Fixed HTTP/1.0 support (changeset 64722)
* Fix typo (changeset 64643)
* Fix accept button in CommentAdmin not working (changeset 64640)
* Fix CMS export (changeset 64639)
* MINOR: PHP notice fixes (changeset 64638)
* MINOR: fix php notice (changeset 64637)
* Allow default value to be set on CountryDropdownField (changeset 64636)
* Add ability to disable 'None' option and to choose the title field in TypeDropdown (changeset 64635)
* BUGFIX: Allow disabling of updateCMSFields() on SiteTree so subclasses that want decorators to have access to (changeset 64634)
* their added fields can call it themselves. (changeset 64634)
* MINOR: Fix PHP notices (changeset 64625)
* Show '(Choose)' text on TreeDropdownField when a non-existent object is selected, as can happen when related data is removed (changeset 64355)
* When calling Folder::findOrMake(), set the Title as well as the Name of new folders (changeset 64354)
* Allow updating of File detail CMS fields by defining updateCMSFields in a decorator (changeset 64353)
* Add macron about native name of maori (changeset 64130)
* Added ->itemWriteMethod parameter, to adjust the way that CTFs write (for instance, to save and publish instead of just save) (changeset 64128)
* BUGFIX: Form::sessionMessage() didn't set type (changeset 63966)
* Fixed sorting in TableListField and subclasses (changeset 63524)
* Removed hard-coded limits in ConfirmedPasswordField. This should be configured in a member password validator (changeset 63405)
* BUGFIX: Fixed tree.js to work with TreeMultiselectField (changeset 63343)
* ENHANCEMENT: Use get variable rather than session for Security::permissionFailure()'s BackURL, as it's more reliable (changeset 63030)
* BUGFIX Set ID of lostpassword page to -1 so we don't get top level pages (changeset 62107)
* as its children (changeset 62107)
* BUGFIX Revert r61631 for Translatable but kept SiteTree changes instact from that revision since they are still useful (changeset 61815)
* API CHANGE: Decorators on SiteTree can now define updateCMSActions (changeset 61625)
* API CHANGE: Decorators on SiteTree can now define updateCMSActions (changeset 61624)
* BUGFIX: Don't show publish button when editing translatable page, as it is broken (changeset 61624)
* BUGFIX: search is now html valid! (changeset 60980)
* merged from trunk (changeset 60651)
* BUGFIX: Fix typedropdown not working when there are no records of that (changeset 60240)
* dataobject. (changeset 60240)
* commented out line 121 that put line breaks (changeset 60194)
* add missing semicolon (changeset 60026)
* Fix null title value on tiny mce inserted images (changeset 60025)
* Overwriting Date.php to output US Date format (changeset 59710)

View File

@ -0,0 +1,43 @@
# 2.2.4 (2009-03-20)
## Features and Enhancements
* ![rev:65263] Default permission failure message set can be changed
* ![rev:73365] Text->FirstParagraph?() now works for `<div>` containers in HTML, as you may not always have paragraph tags.
* ![rev:73272] Added Director::is_relative_url() and Director::is_site_url()
* ![rev:69634] After a javascript validation error from a form submission, focus on the first errored field
## Bugfixes
* ![rev:73367] Allow translation of front-end content into all languages, not just common ones (Merged from r64943)
* ![rev:73347] Removed canEdit() call that doesn't exist in SecurityAdmin::savemember()
* ![rev:73319] Added missing action 'DeleteImageForm' to Image::$allowed_actions
* ![rev:73305] Added missing action 'EditImageForm' to Image::$allowed_actions
* ![rev:73302] Fixed too strict permission checking on Image::$allowed_actions. Replaced broken * permission check with explicit method names
* ![rev:73298] Fixed array to string conversion caused by patch committed in r73272
* ![rev:73295] Validating $_FILES in Image::loadUploadedImage() (Original patch was applied to Upload->validate() in trunk - r73254)
* ![rev:73294] Validating $_FILES in Folder::addUploadToFolder() (Original patch was applied to Upload->validate() in trunk - r73254)
* ![rev:73292] Fixed undefined variable $backURL that should've been $_REQUEST['BackURL']
* ![rev:73282] Using $allowed_actions in ImageEditor (Merged from r73248)
* ![rev:73280] Using $allowed_actions in Image_Uploader (Merged from r73255)
* ![rev:73279] Validating $_FILES in File::loadUploaded (Original patch was applied to Upload->validate() in trunk - r73254)
* ![rev:73278] Existence check for Member autologin token (Merged from r73253)
* ![rev:73276] Checking for Director::is_site_url() before redirecting in Controller->redirectBack() and MemberLoginForm (Merged from r73252)
* ![rev:73273] Added isDev() and Permission::check() directives to DatabaseAdmin (Merged from r73251)
* ![rev:73272] Validating $_FILES array in Director::direct()
* ![rev:73271] Using auto-escaped get_by_id() in CommentAdmin and SecurityAdmin (Merged from r73247)
* ![rev:72220] changed target blank to only exist by default for files
* ![rev:69598] Corrected layout of Security/lostpassword and Secuirty/changepassword pages to not show a glitchy main menu, ie, matches Security/login
* ![rev:69138] Fix readonly checkbox fields always setting the field to true
* ![rev:65490] Fixed usability issue with CalendarDateField required field validation. Slightly over-coupled; resolve that in the jQuery validation rewrite.
* ![rev:65258] Fixed ComplexTableField showing export link correctly
* ![rev:65219] Fixed i18n entity problem with TableListField_Item.ss
* ![rev:69594] Corrected changed-password email layout
* ![rev:67482] Merged db/build fix for auto_increment
* ![rev:65473] Preserve BackURL get-variable on failed log-ins
* ![rev:65488] Removed 'Welcome back, FirstName', message that appears if you log-in, out, then in again
* ![rev:66552] Make sure only fields that exist can be autocompleted on MemberTableFields, and never autocomplete on password. (merged from branches/2.3)
* ![rev:69440] forced tinymce to keep iframes in html rather then deleting them
* ![rev:66769] Reverted r66440 - this was causing too many bugs
* ![rev:66479] Fixed error on CommentAdmin
* ![rev:66440] Merged r57599 from branches/roa

2134
docs/en/changelogs/2.3.0.md Normal file
View File

@ -0,0 +1,2134 @@
# 2.3.0 (2009-02-23)
## Upgrading
### Translatable Problems
**Don't use Translatable for multilingual database content. Don't upgrade to 2.3.0 if you're already using
Translatable.**
The [Translatable extension](/topics/translation) is currently marked as
unstable for the initial 2.3 release. **If your site uses more than one language for page content, don't upgrade to this
release.** We're working on bugfixes which will be contained in a minor 2.3.x release soon. Check our [releaseannouncements](http://groups.google.com/group/silverstripe-announce) for updates on Translatable bugfixes.
### BasicAuth disabled on test sites by default
Basic auth isn't enabled by default on test sites. If you need this, put this in your _config.php
if(Director::isTest()) BasicAuth::enable();
### /silverstripe and /cms no longer work as aliases to /admin
Removed certain URL aliases for CMS interface to allow for common page URLs like "silverstripe" or "cms". Please use
/admin as the main URL to access the CMS. See http://open.silverstripe.com/ticket/3267
### SiteTree Access tab now lets you select multiple groups
In order to do this, `SiteTree->ViewersGroup` and `SiteTree->EditorsGroup` have been changed from has_one relations
to many_many relations.
Your group-assignements for "Who can view this page" and "Who can edit this page" should be automatically migrated upon
calling `dev/build`. See [#2847](http://open.silverstripe.com/ticket/2847)
### Newsletter moved into new module
Newsletter functionality has been moved into its own module called **[newsletter](modules/newsletter)**. If you were
previously using this as a feature out of the box with SilverStripe, then you will need to download the userforms module
to continue using it.
If you **don't** require the functionality, it's safe to delete these database tables:
* Newsletter
* NewsletterType
* SubscribeForm
* UnsubscribeRecord
#### auth_openid removed from default installation
The auth_openid module has been removed from default installation. Please install the module separately from
[silverstripe.org](http://silverstripe.org/auth-openid-module/)
### GenericDataAdmin and RelatedDataEditor moved into new module
GenericDataAdmin functionality has been moved into its own module called
**[genericdataadmin](modules/genericdataadmin)**. If you were previously using this as a feature out of the box with
SilverStripe, then you will need to download this module to continue using it.
### User Defined Form moved into new module
User Defined Form has been moved into its own module called **[userforms](modules/userforms)**. If you were previously
using this as a feature out of the box with SilverStripe, then you will need to download the userforms module to
continue using it.
//Important note: If you **do** have an existing page of User Defined Form type in your CMS site tree, it's best to
install the module first as shown above. If you run dev/build?flush=1 without installing userforms, you'll lose the User
Defined Form page type until you install it then run dev/build?flush=1.//
If you **don't** require the User Defined Form functionality, it's safe to delete these database tables:
* EditableCheckbox
* EditableCheckboxOption
* EditableDropdownOption
* EditableEmailField
* EditableFileField
* EditableFormField
* EditableMemberListField
* EditableRadioOption
* EditableTextField
* SubmittedFileField
* SubmittedForm
* SubmittedFormField
* UserDefinedForm
* UserDefinedForm_Live
* UserDefinedForm_versions
### PostBackup
PostBackup has been moved into a module. See [postbackup
module](http://open.silverstripe.com/browser/modules/postbackup/trunk).
### /db/build/?flush=1 is now called /dev/build
Flushing the manifest with `?flush=1` doesn't need to be explicitly added.
### Core API Changes
* Removed ViewableData->setVal(), use ViewableData->setValue() ===
* Removed Director::isLiveMode(), use Director::isLive() ===
* Removed DataObjectSet->append(), use DataObjectSet->push() or DataObjectSet->merge()
* Removed Controller->LinkTo(), use Controller->join_links()
* Removed DataObject->getLastWriteFields(), use DataObject->getChangedFields()
* Removed Convert::raw2attr(), use Convert::raw2att()
* Removed Member->isAdmin(), use Permission::check('ADMIN')
* Removed Debug::warning(), use user_error("your message", E_USER_WARNING)
* Removed SiteTree->canView_page(), Use instance-specific SiteTree->canView() instead by checking for `$this->ID`.
* Deprecated URL parameter ?buildmanifest=1 (please use ?flush=1)
* i18ntextcollector is executed from a new URL. Use http://mysite.com/dev/task/i18nTextCollectorTask instead of
http://mysite.com/i18ntextcollector
### Director::addRules()
If you have made your own custom director rules with `Director::addRules`, you will need to add a double-slash into
the rule, to separate the part of the URL that specifies "this is how I get to this controller" from the part that
specifies "these are arguments to the controller".
In other words, change this:
:::php
Director::addRules(50, array(
'admin/ImageEditor/$Action' => 'ImageEditor',
));
To this:
:::php
Director::addRules(50, array(
'admin/ImageEditor//$Action' => 'ImageEditor',
));
### Decorators
* Renamed DataObjectDecorator->extraDBFields() to extraStatics() (see
[r65065](http://open.silverstripe.com/changeset/65065))
* DataObjectDecorator->updateCMSFields() is now called from DataObject->getCMSFields(), instead of only SiteTree
instances
* Changed return values for DataObjectDecorator->updateCMSActions() to FieldSet, rather than an array.
### Data Model
* Removed Datetime class, use SSDatetime instead (it was conflicting with PHP 5.2 integrated classes)
* Removed Text->Att(), use Text->ATT_val() instead
### Forms
* Removed NoScriptField, use LiteralField
* Removed EncryptField, use PasswordField
* Removed NamedLabelField, use LabelField
* Removed NoScriptFormAction, use unobtrusive scripting
* Removed FormField->setExtraClass(), use FormField->addExtraClass()
* Removed deprecated ComplexRequiredFields, `RequiredFields` and custom javascript instead
* If you have created your own FormField classes, FormField::performReadonlyTransformation() and
FormField::performDisabledTransformation() must return new form fields, e.g., cloned instances, or unit tests will fail.
### Templates
* '''$Top''' in templates has changed its behaviour; if you call $Top from inside a template that is rendered
separately (eg, a Form template), it will point to the top element of that template execution (in this case, the Form
object) rather than the top element of the outermost template (which would presumably be the page in question). This
was a bug that we have fixed, but some people may rely on it. See http://open.silverstripe.com/ticket/2781
* A `<legend>` element has been added before any `<fieldset>` in all SilverStripe forms. SearchForm.ss and Form.ss are
where it has been added. This now validates the form HTML for W3C compliance. Please verify that your forms visually
look okay after upgrading. Legend can be set by calling ''->setLegend('my legend here')'' on your Form object.
### CMS menu API
We have deprecated the LeftAndMain menu customisation API.
* Don't set any menu-item static variables any more.
* For the most part, you won't need to add anything to _config.php to add CMS menu items; just define the static
variables `$menu_title` and `$url_segment` on your `LeftAndMain` subclasses.
* If you want to add a menu item that's not a subclass of `LeftAndMain` (eg, help or a link to a webstats package),
use `CMSMenu::add_menu_item()`
* To remove a menu item, use `CMSMenu::remove_menu_item()`. It identifies items by classname rather than arbitrary
$code value.
### ContentNegotatior is now disabled by default, mostly
The ContentNegotatior system was a bit of voodoo that confused a lot of people, so we have disabled it by default for
regular templates. It will still enabled by default for templates that include the `<?xml ?>` header, because these
are the only templates that benefit from it significantly.
If you want to enable it for your HTML4 templates, then you can do so by calling `ContentNegotiator::enable()`. Note
also that the DOCTYPE altering, which was a frequent cause of pain, only executes if your original template had the
`<?xml ?>` header.
### Other API Changes
* Removed deprecated File::loadallcontent(), use Upload class
* Image->URL returns relative instead of absolute URL. Use Image->AbsoluteURL instead.
* Moved DataReport and SQLReport into the ecommerce module. If you're using these classes, please download the
[ecommerce module](modules/ecommerce).
### Default mysite/_config.php
The installer includes a default configuration file: *mysite/_config.php*. If you have already have your own
*mysite/_config.php*, you can safely keep your own version and disregard the new file.
### Default validators for Form instances (PHP and JavaScript)
Enforcing usage of a Validator instance in Forms if its not explicitly passed to the Form constructor. By default a new
RequiredField instance is used without any fields marked as required. This was necessary because some FormField
implementations rely on their validate() method, sometimes as a wrongly placed processing hook, but mostly for security
reasons. One example are file extension checks in FileField subclasses.
In most cases this won't have any effect on existing forms, although you might get additional JavaScript dependencies
like Validator.js and behaviour.js. If you want to disable JavaScript validation across forms, add the following to your
_config.php:
:::php
Validator::set_javascript_validation_handler('none');
See http://open.silverstripe.com/changeset/69688
## New Features
* ![rev:71761] Allow combined files to be disabled
* ![rev:70697] CRM Security with two levels: viewable and writeable.
* ![rev:70422] added silverstripe version number to meta generator tag
* ![rev:70142] add permission control for AddForm and EditForm
* ![rev:69687] added Smiliey support to BBCode / forum. Now BBCode supports :) :P :D :( 8-) and :^). Yays for icons. Should move from BBCodeParser to TextParser so its available in tinymce but this will do for the forum
* ![rev:66163] #1531 - Allow moving files in root assets file (hamish)
* ![rev:65904] #1614: Allow use of admin/addpage?ParentID=(ID)&PageType=(Class) url to quick-add pages
* ![rev:65690] #594: Added javascript-on-demand support
* ![rev:65689] #594: Added javascript-on-demand support
* ![rev:65688] #594: Added javascript-on-demand support
* ![rev:65555] #2767 wakeless: Allow popuplation of non-DataObject tables with YamlFixture
* ![rev:65351] merged back patch for image editor. Currently completely broken on trunk this patch does nothing to fix it sadly. I think its a prototype thing
* ![rev:65095] Added CMSMenu and CMSMenuItem and adjusted existing LeftAndMain subclasses to use new notation.See #2872 (thanks to hamish for the patch!)
* ![rev:64881] Making DataObject attributes translatable through i18n class, e.g. $db and all relation statics. Use DataObject->fieldLabels() to access translated attributes.
* ![rev:64877] Added JavaScript unit tests with jQuery QUnit. Can be viewed similiarly to PHPUnit tests through dev/jstests URL. Uses an `<iframe>` to include all tests.
* ![rev:64758] Update to TinyMCE 3.2 - CMS changes
* ![rev:64492] Support for i18n entity namespaces in templates
* ![rev:64480] Added support for 'sake dev/tests/all --showslow' to list slow tests
* ![rev:64473] Added ?debug_memory=1 flag
* ![rev:64461] Show max memory usage on dev/tests/all
* ![rev:64444] Flush template cache before running tests
* ![rev:64417] Added SiteTreeMaintenanceTask
* ![rev:64345] #2956 seaeagle1: Added If-Modified-Since support to HTTP::add_cache_headers() [16:00:18]
* ![rev:64308] Allowing for field-level permissions in DataObject::$api_access - respecting those permissions for reading and writing in RestfulServer (#2918)
* ![rev:64307] Allowing for field-level permissions in DataObject::$api_access - respecting those permissions for reading and writing in RestfulServer (#2918)
* ![rev:64231] #2951 simon_w: Use 301 redirect on Director::forceWWW()
* ![rev:64157] Added FormScaffolder for more flexible scaffolding of FieldSets from DataObject metadata
* ![rev:64103] #2601 - More template handlers
* ![rev:63679] Added HTTP method override support to HTTPRequest and Form (through $_POST['_method'] or $_SERVER['X-HTTP-Method-Override']), incl. unit tests
* ![rev:63659] Frontend CRUD scaffolding with RecordController and CollectionController (not fully functional yet, needs correct Link() methods)
* ![rev:63637] Added coloured output to dev/tests/all
* ![rev:63623] Added DataObject->getFormFields() - uses DataObject->scaffoldFormFields() by default. Added DataObjectDecorator->updateFormFields() for easy customization
* ![rev:63462] Added Email::obfuscate()
* ![rev:62477] Including Firebug Lite when requested by ?debug_firebug=1 for easy debugging in IE/Opera/Safari- otherwise including fake-objects with FirebugX by default to enable usage of console.* commands without javascript errors
* ![rev:62472] Added GoogleSitemap::enable()
* ![rev:62467] Formatting MySQL error messages with newlines through new SQLFormatter class (used in MySQLDatabase)
* ![rev:62458] Allow Use of ?fields=ID,Name,OtherField,RelName get variable on RESTful server queries, to restrict the fields and relations returned int the data set
* ![rev:62396] Added BulkLoader_Result for better inspection of import results, replacing the simple numeric count result format.
* ![rev:62333] TableListField's TRs can now have class=loading added to them to show a loading icon. (Used by ModelAdmin)
* ![rev:62286] Allow customisation of HTTPResponse status text, as well as status code
* ![rev:62284] Files & Images tree now shows filename rather than meta-data title, to make it easier to find the file you're looking for
* ![rev:62211] #1403 - addFieldToTab(), push(), insertBefore(), etc will allow duplicates - the old field is replaced with the new.
* ![rev:61824] #2594 - Allow decoration of getCMSActions() (simon_w)
* ![rev:61605] relate groups with column selections in SearchForm of CRM Admin
* ![rev:61444] xml2array now works with recursion so it will actually work with most xml files. Unit tests to comei
* ![rev:60396] Added configurable Requirements::$write_js_to_body for performance improvements (turned off by default)
* ![rev:60368] Improved debugging view on CLI interface, by having a separate DebugView subclass that takes care of error output for this situation.
* ![rev:60220] Merged in CompositeDBField
## API Change
* ![rev:70697] add Group::canView() so that give group object a different level of security control.
* ![rev:70150] we move the filedata generation part of export() function to a new function generateExportFileData, so that, a child class could reuse the function when overload export function
* ![rev:70057] Decimal->requireField now includes 'not null' constraint, as Sapphire doesn't expect the value to be null. MySQL switches null values to 0.00 on build.
* ![rev:69730] Removed access to broken image editor feature
* ![rev:69688] Enforcing usage of a Validator instance in Forms if its not explicitly passed to the Form constructor. By default a new RequiredField instance is used without any fields marked as required. This was necessary because some FormField implementations rely on their validate() method, sometimes as a wrongly placed processing hook, but mostly for security reasons. One example are file extension checks in FileField subclasses.
* ![rev:69363] Added ModelAdmin_CollectionController::columsnAvailable() and ModelAdmin_CollectionController::columnsSelectedByDefault() that can be overridden to customise the fields available in the column selection control.
* ![rev:69360] Add keyField and titleField arguments to SQLMap
* ![rev:68484] ContentNegotiator is now disabled by default, unless you include the xml header in your template. (merged from r68482)
* ![rev:67426] Added SSViewer::set_source_file_comments() to allow disabling of comments in SSViewer output
* ![rev:67380] Deprecated Email->setFormat()
* ![rev:66894] Move some of the installer into the sapphire directory.
* ![rev:66394]
* ![rev:66392] if a DataObject has getCMSActions, its model admin should be able to add them.
* ![rev:66268] Deprecated Controller::PastVisitor(), it generates a lot of unused cookies
* ![rev:66266] Improve encapsulation of cookies in Director::test()
* ![rev:66264] Revamped CMSMenu system to not instantiate any objects, so that _config.php doesn't get fskd
* ![rev:66175] Moving GoogleSitemap functionality into new "googlesitemaps" module
* ![rev:65744] make CreateForm be able to disable
* ![rev:65742] introduce SearchFilter::getDbFormattedValue() and GreateThanFilter will used this method to make the qurey so that it can apply to a field that input format is different that its db format, such as CalendarDateField.
* ![rev:65669] even when no results found, the HTTPResponse should return a "200" HTTPResponse rather than "404" HTTPResponse, otherwise, the right panel didn't refresh the result table, and the error message shows up.
* ![rev:65581] Deprecated CompositeField->insertBeforeRecursive(), use CompositeField->insertBefore()
* ![rev:65554] tidy up NewsletterAdmin.
* ![rev:65454] Deprecated DataObjectDecorator->augmentInit(), use LeftAndMainDecorator->init()
* ![rev:65453] Deprecated DataObjectDecorator->alternateCanCreate(), use DataObjectDecorator->canCreate()
* ![rev:65452] Removed Folder->userCan*() and File->userCan*()permissions and added more consistent behaviour with Folder->can*() and File->can*()
* ![rev:65451] Don't include NULL returns in decorated methods called through Object->extend(), meaning empty method bodies in decorators won't confuse permission checks through $myObj->extend('canView') etc.
* ![rev:65388] make DataObject::getField() visible to the public
* ![rev:65385] Removed manifest's dependency on database, by removing hastable information [17:47:04]
* ![rev:65229] Use return value of alternateCanPublish()
* ![rev:65150] Changed SiteTree->EditorsGroup has_one relationship to SiteTree->EditorGroups has_many relationship (see #2847)
* ![rev:65095] Removed LeftAndMain::add_menu_item(), LeftAndMain::remove_menu_item(), LeftAndMain::replace_menu_item(), LeftAndMain::clear_menu()
* ![rev:65068] Removed DataObjectSet->consolidate(), use DataObjectSet->toNestedArray()
* ![rev:65066] Removed DataObjectSet->consolidateString()
* ![rev:65065] Renamed DataObjectDecorator->extraDBFields() to extraStatics()
* ![rev:65060] Moved DataObject::get_by_url() to SiteTree::get_by_url()
* ![rev:65059] Marked DataObject->filledOut() deprecated
* ![rev:64958] #2922: RequestHandler:: now inherit
* ![rev:64954] #2857 - Renamed RequestHandlingData to RequestHandler
* ![rev:64953] #2857 - Renamed RequestHandlingData to RequestHandler
* ![rev:64951] #2698 ajshort: URL handler only passes control to subclasses of RequestHandlingData
* ![rev:64807] Added LastChange() method to BulkLoader_Result
* ![rev:64806] Updated CsvBulkLoader to have hasHeaderRow = true by default, even when a columnMap is specified
* ![rev:64805] add updateFieldLabels() to DataObjectDecorator, so as that a dataobject could update fieldLables by its decorator.
* ![rev:64792] A Text db field, by default, should be rendered as a TextareaField in its scaffoldForm
* ![rev:64528] delete GenericDataAdmin, RelatedDataEditor, DropdownField_WithAdd and their related code (js, css, etc) from cms, sapphire, "GenericDataAdmin" name space has also been deleted from lang files. They are all added in the new module "genericdataadmin"
* ![rev:64504] Changed HTMLVarchar->scaffoldFormField() to use HtmlEditorField instead of HtmlOneLineField, which does not work.
* ![rev:64428] Moved CheckboxFieldDisabled class to more common CheckboxField_Disabled notation
* ![rev:64426] Removed NoScriptField, please use LiteralField
* ![rev:64425] Removed EncryptField, use PasswordField
* ![rev:64421] Moved setAllowHTML() to DataLessField
* ![rev:64420] Removed NamedLabelField, use LabelField
* ![rev:64416] Removed SiteTree->makelinksunique() and SiteTree->makelinksuniquequick() - use new SiteTreeMaintenanceTask
* ![rev:64407] Removed NoScriptFormAction, use unobtrusive scripting
* ![rev:64402] Removed deprecated File::loadallcontent(), use Upload class
* ![rev:64401] Removed Filesystem::moverootfilesto()
* ![rev:64399] Removed deprecated ComplexRequiredFields, use RequiredFields and custom javascript instead
* ![rev:64398] Removed SecurityAdmin->listmembers()
* ![rev:64394] Removed deprecated Datetime class, use SSDatetime instead (was conflicting with PHP 5.2 integrated classes)
* ![rev:64384] Removed Email_Template, use Email
* ![rev:64383] Removed ViewableData->setVal(), use ViewableData->setValue()
* ![rev:64381] Removed Debug::mailBuffer()
* ![rev:64380] Removed Director::isLiveMode(), use Director::isLive()
* ![rev:64379] Removed FormField->setExtraClass(), use FormField->addExtraClass()
* ![rev:64378] Removed DataObjectSet->append(), use DataObjectSet->push() or DataObjectSet->merge()
* ![rev:64377] Removed Controller->LinkTo(), use Controller->join_links()
* ![rev:64376] Removed Image->transferlegacycontent()
* ![rev:64375] Removed DataObject->getLastWriteFields(), use DataObject->getChangedFields()
* ![rev:64374] Removed Convert::raw2attr(), use Convert::raw2att()
* ![rev:64373] Removed deprecated RestfulService->connect(), use RestfulService->request()
* ![rev:64372] Removed deprecated CustomValidator class
* ![rev:64371] Removed deprecated EditForm classa
* ![rev:64351] #551: Move code from CMSMain to SiteTree
* ![rev:64350] #551: Move code from CMSMain to SiteTree
* ![rev:64332] Removed deprecated methods related to CanCMS and CanCMSAdmin which are now removed from the Group class in favour of the Permission system
* ![rev:64330] Removed deprecated method isAdmin() on Member - use Permission::check('ADMIN') instead
* ![rev:64327] Removed references to CanCMS and CanCMSAdmin in Group, including references to it in Member. See ticket #2959 for more details.
* ![rev:64157] Added third optional parameter $object to DBField::create() to comply with ForeignKey and PrimaryKey constructors
* ![rev:63997] Deprecated GhostPage
* ![rev:63922] Added support for dot syntax to FieldSet::fieldByName()
* ![rev:63827] Added initial CMS tests to the system. These will execute tests on the data model provided by a user's project code
* ![rev:63764] Deprecated Form->loadNonBlankDataFrom() - it was duplicating loadDataFrom() without allowing for the same options, and it was buggy in its definition of "blank" by doing non-typesafe checks with if($value) $field->setValue($value) which resulted in '0' strings not being loaded
* ![rev:63759] Moved PostBackup class to module (see r63758)
* ![rev:63637] Added SSCli class to help with outputting coloured text on the command line
* ![rev:63579] Deprecated HTTP::sendFileToBrowser() in favour of more testable HTTPRequest::send_file()
* ![rev:63563] Created CSVParser class and updated CSVBulkLoader to use it
* ![rev:63468] Deprecated Form->resetData() - use Form->resetField()
* ![rev:63465] Changed parameters for Debug::friendlyError()
* ![rev:63337] Deprecated DataObject->listOfFields() - use custom code instead
* ![rev:63310] Removed SiteTree->canView_page() - originally created under the false assumption that SiteTree->can('view_page') is still valid. Every canView() can be instance specific. Original patch by simon_w in r53183 and #2198
* ![rev:63182] Deprecated URL parameter ?buildmanifest=1 (please use ?flush=1)
* ![rev:63177] Removed Text->Att(), use Text->ATT_val() instead
* ![rev:63176] Deprecated Varchar->Attr(), use Varchar->ATT_val() instead
* ![rev:63077] Removed useless File->test() method
* ![rev:62883] TableListField::sourceFilter() can be overloaded to change the querying logic.
* ![rev:62847] Deprecated Member::isInGroup() - use Member::inGroup() instead
* ![rev:62846] Deprecated Member::isInGroup() - use Member::inGroup() instead
* ![rev:62843] Removed Debug::warning()
* ![rev:62325] Moved DataReport and SQLReport into the ecommerce module, since this is the only place it is used, plus it's going to be deprecated soon anyway
* ![rev:62324] Moved DataReport and SQLReport into the ecommerce module, since this is the only place it is used, plus it's going to be deprecated soon anyway
* ![rev:62316] Deprecated LabelledLiteralField by adding a @deprecated note with alternate approaches, and added a PHP notice for people currently using it
* ![rev:62309] Moved ProgressBar and support files to newsletter/trunk module, as this is the module where it's used
* ![rev:61683] TableListField::ajax_refresh is deprecated. Removed all calls to it from the core, instead getting HTML fragments by visiting the field's URL.
* ![rev:61632] BasicAuth is now disabled by default on test sites
* ![rev:61505] Allow definition of DataObject::getCMSAddFormFields() to alter modeladmin step 1
* ![rev:61485] Deprecated GroupedDropdownField, DropdownField should now be used instead
* ![rev:60894] Added Validator::set_javascript_validation_handler() and ->setJavscriptValidatorHandler(), to choose a different way of dealing with javascript validation. Currently 'none' and 'prototype' are the only legal options, but 'jquery' would be an obvious thing to implement.
* ![rev:60711] Template precedence changed. Page_results now takes precedence over HomePage. That is, all action templates of parent classes take precedence over the actionless templates.
* ![rev:60665] TableListField utility links no longer have target=_blank
* ![rev:60405] Removed merged USZipCode field - should be custom code until we figure out proper localization
* ![rev:60392] Renamed static Member::autologinhash() to static Member::member_from_autloginhash() to be more in line with naming convnetions, and not conflict with Member.AutoLoginHash in the database
* ![rev:60376] Allow the definition of SS_ERROR_LOG in _ss_environment.php to set up Debug::log_errors_to().
* ![rev:60368] Added Debug::log_errors_to(), to log errors to a file.
## Bugfixes
* ![rev:71923] In SSViewer::parseTemplateContent($content, $template=""), when the $content is a xml template, we should not wrap anything around it, for web browser able to correct parse the xml
* ![rev:71872] #3491 - Fix nonexistant plugin stopping tinymce from working in safari.
* ![rev:71846] #3481 - Check if classes exist before trying to instantiate a singleton on database build, to work around stale manifest errors
* ![rev:71841] #2723 - Allow more than more subclass of RelationComplexTableField on a page at a time.
* ![rev:71797] removed doubled up pipes and border on switch view links in footer.
* ![rev:71764] Fix wrong conditional
* ![rev:71709] BUGFIX Fixed redirection to external URLs through Security/login with BackURL parameter (merged from trunk
* ![rev:71642] Disable DataObject validation temporarily while importing yaml fixtures
* ![rev:71568] CRM "select all" and "select none" doesn't work when the crm manages multiple models.
* ![rev:71499] i18n::include_by_locale() should skip check the web root level and ../webroot level for language file, this is not only "not necessary" but also "must" because some server configuration prevent from any file access above the site root folder.
* ![rev:71436] Error adding custom header in Email because of non-existant array key. Thanks ed! Ticket #3485
* ![rev:71348] Removed unused ComplexTableField->unpagedSourceItems - was already commented out in r70956, and doesn't seem to be used across parent- or subclasses. Added ticket #3484 to re-enable popup pagination, which was broken and disabled due to the deprecation of $unpagedSourceItems (see r53830)
* ![rev:71250] fixed site page restoration
* ![rev:71177] cms ui, fixed loading spinner style
* ![rev:71024] #3429: Fixed CMS change detection
* ![rev:71023] #3443: Fixed refreshing of relation CTFs after editing data
* ![rev:71018] #3442: Fix pagination in HasManyComplexTable, HasOneComplexTableField, ManyManyComplexTable
* ![rev:70997] #3441 funkygibbon: Stop ThumbnailStripField breaking on orphaned images
* ![rev:70994] CMS UI site content > search > add criteria select element now returns back to prompt & tweaked layout
* ![rev:70935] adjust positioning of SilverStripeNavigator published/draft message
* ![rev:70895] Ensure string "0" is not considered a NULL value when CsvBulkLoader imports values from a CSV file
* ![rev:70893] reinstating silverstripe navigator and restyling to match cms ui
* ![rev:70891] removed extra colon appearing in SilverStripeNavigator
* ![rev:70848] Removed reference to Requirements::javascript() for including jquery as it's already included, and causes JS errors in MemberLoginForm
* ![rev:70847] Fixed correct path to jquery.js in MemberLoginForm
* ![rev:70832] $hide_ancestor hides Page as well when set from multiple subclasses of Page. Thanks dio5!
* ![rev:70784] #3415 ajshort: Requesting root page via ajax now preserves isAjax value.
* ![rev:70781] #3430 page versions don't appear automatically in Safari - versions DOM panel was floated behind the edit form
* ![rev:70775] Fixed "cancel" button for inline "create folder" functionality (was not stopping event in IE7)
* ![rev:70773] Disabled faulty usage of setStyle() with object literals instead of strings in SWFUpload
* ![rev:70766] Removed hack that hid the Avatar field for the forum
* ![rev:70750] Fix incorrect URL when adding a new Member via the MemberTableField
* ![rev:70747]
* ![rev:70743] 1. TableListField exportfunality random bug. 2. make Email_BounceRecord::canCreate() return false; so that it can not be manully create from CRM, instead, it should create through email buncing system.
* ![rev:70741]
* ![rev:70729] Add EditForm to list of allowed actions
* ![rev:70725]
* ![rev:70724] Fixed loader_frame.html scrollbar madness. Removed hacked CSS and tidied up popup to work in IE6/7 and Firefox consistently
* ![rev:70698] Group::AllChildrenIncludingDeleted() should filter on canEdit() rather than a can() call
* ![rev:70695] $_POST[$this->Name] in TableField::SubmittedFieldSet are not always set
* ![rev:70691] show flash icon and box if flash file exists. MINOR: created a default editor.css file which has base css styles for the CMS.
* ![rev:70683] cms ui added colon to image upload prompt (inline with other step)
* ![rev:70682] cms ui remove errant dashed borders in IE6
* ![rev:70681] cms ui text size in righthand image panel
* ![rev:70680] Fixed behaviour.reapply() call in TableListField->refresh() javascript to applyToParent (the actual DOM container). Otherwise methods of the TableListField prototypes aren't properly attached to the DOM nodes, which causes problems like #3377
* ![rev:70671] Fixed newsletter send button alignment
* ![rev:70616] stopped double scrollbars on popups in IE7 (IE6 still broken)
* ![rev:70613] Fixed styling for "Delete selected files" in the left-hand tree actions for AssetAdmin. Thanks ajshort!
* ![rev:70609] Defined jsValidation() and validate() so that inherited validation from DateField doesn't break PopupDateTimeField - this still needs fixing, and PopupDateTimeField shouldn't inherit from CalendarDateField
* ![rev:70604] autocomplete style change.
* ![rev:70603] cms ui fix files & images upload images styling
* ![rev:70602] cms ui fix files & images table styling
* ![rev:70601] cms ui removed backgound from delete button on files & images
* ![rev:70583] cms ui fixing up treetool
* ![rev:70573] cms ui removed extra padding from bottom of tools
* ![rev:70572] cms ui fix styling of tools on files & images section
* ![rev:70567] cms ui fix styling of tools on files & images section
* ![rev:70566] reverted previous tree tool change
* ![rev:70565] when the total number of rows is 0 the pagination says 1 to 0 of 0
* ![rev:70563] cms ui fix styling of tools on files & images section
* ![rev:70561] cms ui padding on tree
* ![rev:70545] Hidden field needs to exist for DateField_Disabled in order for validation to pass correctly
* ![rev:70541] cms ui padding on tree in right pane (eg. image selector)
* ![rev:70508] cms ui tidying up tree tools
* ![rev:70507] cms ui tidying up tree tools
* ![rev:70497] merged patch from ajshort. Fixed getURL() so it preserved the extension
* ![rev:70496] cms ui tidying up padding of tree tools elements
* ![rev:70495] cms ui fix specifivity of alignment of radio buttons and labels in right pane
* ![rev:70486] cms ui fix alignment of radio buttons and labels in right pane
* ![rev:70481] If __form.elements.ID is not defined, don't cause an error in the CMS under certain circumstances
* ![rev:70479] cms ui site tree tools style fix
* ![rev:70474] Fixed float issue caused by change in r70303
* ![rev:70445] fixed size of popup on 1024x768 resolutions
* ![rev:70441] added scroll bars
* ![rev:70404] site tree form element alignment
* ![rev:70397] stopped swfupload div appearing behind cms ui in firefox 2 on windows
* ![rev:70396] cms ui sitetree tools padding
* ![rev:70395] IE6 cms login remember me alignment
* ![rev:70393] cms ui sitetree padding across cms sections
* ![rev:70392] centered GreyBox popup in the CMS
* ![rev:70390] cms ui form site tree input alignments
* ![rev:70389] cms ui form site tree input alignments
* ![rev:70388] cms ui fixed width of tools at top of site tree
* ![rev:70377] fixed site tree padding issue
* ![rev:70376] URL input validation for RestfulServer
* ![rev:70356] fixed positioning on site tree actions on left tree for Security and comment tags
* ![rev:70172] due to changeset 65289 by phalkunz, the ImportForm() and import() functions need to move from CRMAdmin class to CRMAdmin_CollectionController class, fix relative bugs by the move.
* ![rev:70160] Add workaround for PHP bug #46753
* ![rev:70135] Fixed spacing at the top of right forms in the CMS caused by the `<legend>` element. Fixed by hiding it via CSS instead of removing it completely
* ![rev:70130] Fixed issue of not enough space in the AssetAdmin "Upload" tab for multiple file uploading, mostly affecting IE6/7
* ![rev:70127] Changed the FieldHolder method to use explicit functionality instead of statically calling FormField::FieldHolder()
* ![rev:70117] Fixed clearing issue in IE7 for the left hand tree
* ![rev:70077] Removed ANSI compatible SQL that shouldn't be in branches/2.3 - this feature is available in trunk
* ![rev:70063] Removed ID for back links table which is ambiguous, unncessary and caused the CSV export to break
* ![rev:70052] Deleted setting of $content variable that broke HTTP::findByTagAndAttribute()
* ![rev:70049] Strip out any "~" characters that may stop the staging link from working in IE6/IE7
* ![rev:70046] Check for form object before calling observe() on the element. The CheckBoxRange constructor allows for a null form, so a check for a form object is essential.
* ![rev:70026] Disallow execution from DailyTask and HourlyTask by website visitors.
* ![rev:69988] `<% end_if %>` was breaking the template where it should've been a `<% end_control %>`. This fixes the export link in #3333
* ![rev:69986] Added page-limiting back to CMS tree querying
* ![rev:69975] Fixed FileField->getFolderName() - it was not returning $this->folderName, instead it was returning an undefined variable in error
* ![rev:69973] error when creating a form
* ![rev:69951] More solid string-parsing through regular expressions in SQLQuery->filtersOnID() and SQLQuery->filtersOnFK(), incl. unit tests
* ![rev:69943] #3329: Improved speed of folder creation in files + images
* ![rev:69931] Fixed flash HTML that gets inserted into the content so it's cross browser compatible with browsers that don't support the `<object>` tag (`<embed>` is added inside)
* ![rev:69930] Checkbox "Remeber me next time?" now works because of a missing method call logIn() on Member
* ![rev:69927] #3024 - Stopped style dropdowns from getting stuck by making them regular dropdowns. Not as pretty but more stable.
* ![rev:69921] Fixed minor error on dev/buildcache
* ![rev:69910] Allowing to pass $context into Hierarchy->markPartialTree() and Hierarchy->markChildren()
* ![rev:69909] Making sure a valid DataObjectSet is returned from Hierarchy->stageChildren()
* ![rev:69899] Explicitly setting "lang" as a GET var when getting a page within the CMS (if the language chooser DOM object is available, hence translation mode is enabled). Used in CMSMain->init() to set the "current language". (merged from branches/translatable in r64523, thanks wakeless!)
* ![rev:69894] Using baseDataClass() in Translatable::get_existing_content_languages()
* ![rev:69893] Added extension point for augmentAllChildrenIncludingDeleted(), augmentNumChildrenCountQuery(), augmentStageChildren() in Hierarchy (merged from branches/translatable in r64523, thanks wakeless!)
* ![rev:69891] Using SQL DISTINCT in get_existing_content_languages()
* ![rev:69879] Fixed label positioning in CompositeFields for original language fields in translation mode (was shifted left before)
* ![rev:69878] Fixed $add_action behaviour for SiteTree classes (through i18n_singular_name() method). Deprecated in favour of "`<myclassname>`.TITLE" entity to enable localized page titles. Limited add_action behaviour to SiteTree (was implemented on DataObject before)
* ![rev:69872] Fixed status checking in SiteTree->getIsDeletedFromStage()/getIsModifiedOnStage()/getIsAddedToStage() for new pages with non-numeric IDs
* ![rev:69870] Fixed use of undefined constant error, and undefined variable error in TableField stopping CMS user from adding records to a TableField
* ![rev:69832] #3235: Fixed linking of images and other HTML tags
* ![rev:69830] #3219: dev/buildcache showing up in static links
* ![rev:69828] Fixed styling for caption checkbox field on the right hand image panel in CMSMain
* ![rev:69803] If TreeDropdownField source object is "Folder", don't show "File" tree items unless the marking filter function is explicitly set. This fixes the bug where files were appearing for selecting a folder in the thumbnailstrip field in CMS
* ![rev:69752] somtimes +/- icons hidden. ticket #893
* ![rev:69728] #3254 - Fixed fatal errors when creating subclass of member
* ![rev:69720] #3199: No longer warned about saving changes if you have actually pressed save.
* ![rev:69718] #2550 - Fixed bug with draggability of newly created nodes.
* ![rev:69715] #2342: Database names with hyphens and other special characters can now be used.
* ![rev:69700] #3224 ajshort: Get HTTP::setGetVar() working with variables that contain array indexes
* ![rev:69697] #3165 nicolaas: Fixed Director::history() in some cases.
* ![rev:69696] #3248: Fixed TreeDropdownField when using non-ID key field
* ![rev:69695] #3188: Fixed default HeaderField name to be non-conflicting with other fields, for backward compat
* ![rev:69694] #3097: Removed buggy template feature
* ![rev:69693] #3249: Allow altering of encryption algorithm
* ![rev:69690] #3081 simon_w: Fixed pagination on spam comments
* ![rev:69689] Don't include Validator.js if Validator->javascriptValidationHandler is set to 'none' (in Validator::__construct()).
* ![rev:69681] Fixed HTML insertion through TinyMCE in Safari - TextArea fallback for lacking Codepress-support wasn't working. Known bug in Codepress JS Highlighter, see http://sourceforge.net/tracker/index.php?func=detail&aid=1913725&group_id=186981&atid=919470
* ![rev:69657] Fixed js error due to inlined inclusion of CMSMain_upload.js which was conflicting with inline initialization. Disabled initializiation as the flash uploader was pulled out a while ago anyway (see #3251)
* ![rev:69504] Fixed SiteTreeHandlers.loadTree_url url concatenation
* ![rev:69442] Fixed permissions in CMSMain->revert() - only needs edit permissions, not publish permissions
* ![rev:69378] CountryDropdownField now allows for title to be optional, which uses the name of the field if not set. This makes it consistent with DropdownField
* ![rev:69377] Added check before foreach() to fix potential HMCTF bugs
* ![rev:69360] Get DrodpownField::$emptyString working when used with a SQLMap source
* ![rev:69321] Added `<td class="action">` to AssetTableField.ss to comply with template semantics of parent classes (necessary to detect javascript actions)
* ![rev:69222] Strip potential whitespace from the beginning and end of string before limiting word count in Text->LimitWordCount(), fixing potential interference with truncation process
* ![rev:69220] Fixed Text->LimitWordCount() not returning the correct number of words in the truncated text.
* ![rev:69204] Making Password formfield in Member->getCMSFields() translatable
* ![rev:69203] Making "Main" tab in FormScaffolder translatable
* ![rev:69065] Fixed notice-level error in no-get-var URL processing when there is no querystring.
* ![rev:68999] Make sure the website URL that the commenter posts has a correct "http://" or "http://" bit at the start of the string
* ![rev:68940] Fixed bug in SQLQuery::unlimitedRowCount() when used with grouped queries, that should fix a lot of pagination situations.
* ![rev:68935] Fixed PHP notice potential error in MemberTableField->addtogroup()
* ![rev:68921] Turned english text into translatable entity for PageCommentInterface link for RSS feed of all comments for all pages
* ![rev:68890] "console not defined" error in IE in en_US.js, check typeof(console) is not undefined before calling console.error()
* ![rev:68881] remove Debug::message
* ![rev:68875] Fix uglyness when title is longer than the tree dropdown field
* ![rev:68858] Added closing tags to relation XML in XMLDataFormatter. Was relying on ContentNegotiator fixing self-closing tags automatically, but this form of content parsing is disabled for xml content by default now (see r68484)
* ![rev:68834] Make sure date is a string before trying to use strtotime
* ![rev:68817] Fixed sprintf detection bug in SiteTree->getClassDropdown()
* ![rev:68810] Making only formfields readonly (not formactions) when comparing versions and showing historical versions within CMSMain
* ![rev:68809] Check hasChanged method exists before calling it
* ![rev:68764] Fixed translation of CommentAdmin_SiteTree.ss
* ![rev:68762] Fixed label spacing in Date->TimeDiff()
* ![rev:68757] Fixed additional tabs for image popus in AssetTableField. They we're not being generated in non-english interfaces due to the translated title being used as the tab identifier
* ![rev:68754] Limiting readonly transformation of form in CMSMain->EditForm() to fields only (excluding actions). FormAction readonly transformations were fixed a while ago, which meant that they were actually enforced now, causing unavailable cms actions in certain scenarios (e.g. with a page deleted from live, which should make the fields readonly, but leave buttons functional)
* ![rev:68752] Fixed TranslatableTest to instanciate Page instead of SiteTree fixtures - pages in the database should never have ClassName=SiteTree. This was causing failing tests due to the changes in SiteTree->getClassDropdown()
* ![rev:68751] Including all translated language tables by default in i18n::_t() instead of selectively including modules based on filename. This caused bugs where entities were located in language tables in a different module than their filepath would suggest. Example: Page.SINGULARNAME is stored in sapphire/lang/en_US.php, while Page.php is stored in mysite/Page.php
* ![rev:68746] Don't overwrite existing module arrays in i18nTextcollector - fixing bug with entities for "foreign modules" being reset during parsing
* ![rev:68702] Updated CMS to support HtmlEditorField changes in r68701
* ![rev:68662] #3166 jam13: Fixed caching in RestfulService
* ![rev:68628] Fixed HasManyComplexTableField/ManyManyComplexTableField issue with source items which broke from changes in r66080. Thanks hamish!
* ![rev:68627] Fixed javascript error in the CMS
* ![rev:68626] Fixed javascript error in the CMS
* ![rev:68603] Fixed new searchform changes for Live/Stage
* ![rev:68515] Making sure phpinstaller works on subdomains (see #3167)
* ![rev:68463] Fixed PHP notice in RebuildStaticCacheTask
* ![rev:68331] Fixed ModelAdmin import success message (too few arguments for sprintf())
* ![rev:68194] Allowing FormAction instances to be readonly by setting disabled="disabled". Adding CSS class "disabled".
* ![rev:68177] Moved creation of "help" menu entry from cms/_config.php to LeftAndMain::init() to get localized titles (locale isn't set at _config.php level)
* ![rev:68176] Fixed i18n display of menu titles rendered by CMSMenu in LeftAndMain->MainMenu()
* ![rev:68170] Escape table name in versioned to allow creation of page type classes with the same names as SQL reserved words
* ![rev:68159] Changing i18n entity format in CMSMenu->provideI18nEntities() to have actual class as namespace (related: r66264)
* ![rev:68155] Added stub PDODatabase->renameField() implementation to avoid errors when batch-instanciating singletons
* ![rev:68130] Supporting URLs with folder-structure in "sake -start `<myprocessname>` `<myurl>`"
* ![rev:68039] Improved DataObjectSet->PaginationSummary() to show full context (instead of halved) when on first or last page
* ![rev:68027] Don't show template comments in RSSFeed, or it'll break the XML document
* ![rev:68026] Fixed undefined variable $matches in SSViewer::parseTemplateContent()
* ![rev:68024] SSViewer::set_source_file_comments(false) wasn't working because of lack of checking if enabled.
* ![rev:67777] Added check ot i18n::include_by_class() to prevent repeated calls.
* ![rev:67681] Add a unique identifier to the "direction" method for Email::obfuscate() to avoid duplicate custom CSS being included in the page header
* ![rev:67678] Method not found error. Requirements::customCSS() should be calling self::backend()->customCSS() not custom()
* ![rev:67609] #3182 - Fix URL fixing on machines where url is case insensitive (hamish)
* ![rev:67605] #3204 - Broken link tracking is broken (ajshort)
* ![rev:67587] #3174 - Unable to drop widgets into widget areas in CMS (marcink)
* ![rev:67584] #3218 - Spelling mistake in RestfulService (hamish)
* ![rev:67582] Fixed a check for CSV field formatting.
* ![rev:67580] Fixed an aliasing problem when saving popup items, and a bug with when associating a new record with the parent ID associated with the field.
* ![rev:67530] SSDatetime can handle being given a NZ date in dd/mm/yyyy format
* ![rev:67529] Only setting LockedOutUntil to NULL in Member->logIn() if the column is actually present in the database. Otherwise this setting will case an UPDATE Member SQL query to fail on the first /dev/build call on a 2.2->2.3 upgrade if not in dev-mode (=requiring login) (see #3171)
* ![rev:67526] Added $CurrentLink to templates of AssetTableField and MemberTableField in order to support auto-refreshing after popup-close (see #2925)
* ![rev:67520] Fixed i18n::get_owner_module() to detect template paths in themes (array notation) correctly (see #3022)
* ![rev:67519] Added GoogleSitemap.ss from sapphire
* ![rev:67506] Avoid ugly border in CMS forms by adding "border: none" in CSS to cms/css/layout.css
* ![rev:67503] disabling template comments for xml output like sitemap.xml
* ![rev:67455] Fixed incorrect parameter variable name in Mailer->sendPlain()
* ![rev:67417] Added `<legend>` element immediately after `<fieldset>` for SearchForm and Form templates. This is required to validate these templates as W3C compliant
* ![rev:67401] Moving Requirements::combine_files() calls from cms/_config.php to LeftAndMain->init() to avoid side-effects in non-CMS contexts. Examples:
* ![rev:67363] $allowHTML argument was not passed to DatalessField::__construct
* ![rev:67304] Since ModelAsController->handleRequest() expects a URLSegment, we make the ErrorPage Link() return a relative URLSegment in ErrorPage->publish()
* ![rev:67299] Changed Director::test($this->URLSegment) to Director::test($this->Link()) in ErrorPage->publish() to be more robust
* ![rev:67290] Added parent::setUp() and parent::tearDown() calls to various tests, in preparation for push/pop a mock controller the controller-stack
* ![rev:67271] dev/build should function even when new classes are referenced in _config.php
* ![rev:67268] Filter on the baseclassid in Hierachy, not the class id, in case the class doesnt have a table (aoneil)
* ![rev:67221] Save default locale for new members, so the profile form doesn't show first available locale in dropdown because its defaults are overwritten by Member->Locale = NULL (see #3159)
* ![rev:67201] Declared behaviour.js variables as local for better recursive functionality
* ![rev:67199] Fixed incorrect permission checking when the current member isn't being used
* ![rev:67162] Scrollbars didn't appear properly in CMS without resizing the window manually, so used jQuery to properly detect when document is ready before attempting resize. Ticket #3089
* ![rev:67150] Checking for "$this instanceof VirtualPage" instead of "$this->class == 'VirtualPage' to support subclassing in VirtualPage->onBeforeWrite()
* ![rev:67147] Fix requirements not being restored after an email is sent
* ![rev:67140] Checking for existence of $this->record in VirtualPage_Controller->init()
* ![rev:67137] Fix publishing of error pages
* ![rev:67083] Fixed StaticExporter output format
* ![rev:67078] Put the order of save and publish buttons back to normal (so save and publish are next to eachother)
* ![rev:67045] Fixed Enum::scaffoldSearchForm() to always include an (All) option
* ![rev:67035] Fixed error in javascript (because of commented out code) that broke IE6/7 in the CMS
* ![rev:66946] Fixing tests
* ![rev:66940] Fixed warning on AssetAdmin (merged from trunk)
* ![rev:66922] #3100: Graceful degradation for codepress in safari
* ![rev:66918] #3115 ajshort: Fixed backslashes in temp folder location in manifest builder
* ![rev:66894] Friendlier error when you have a site running on a PHP4 server, or a server without PHP.
* ![rev:66891] Don't make blank dates show 1/1/1970
* ![rev:66888] Better generation of PastMember cookie when you have stale login info
* ![rev:66828] Fixed sortWidgets() function in WidgetAreaEditor not working because it was picking up comment nodes
* ![rev:66820] Added extension to email address when accessing Security/passwordsent since the . (dots) are split into extensions when the URL is parsed
* ![rev:66799] Fixed importer not working because of i18n_singular_name(), just use the class name of the model instead
* ![rev:66793] Made use of Convert::raw2att() before returning the ModelName for Import spec fields
* ![rev:66791] Fixed "Show specification..." link not working because ModelName had spaces in it
* ![rev:66784] Only including ModelAdmin->ImportForm() if an actual importer was specified
* ![rev:66740] Passing through $member param from SiteTree->canPublish() to SiteTree->canEdit()
* ![rev:66723] fixed typo in filesystem
* ![rev:66707] Fixed notice-level errors in PhoneNumberField
* ![rev:66701] Add LeftAndMain:$url_rule to minimise bugs in modules
* ![rev:66698] Fixed sake bug when checking for an argument in bash script. Ticket #3112. Thanks simon_w.
* ![rev:66638] Fixed flaw logic checking for $member variable, since it's always set the alternative for choosing Member::currentUser() would never work.
* ![rev:66635] Fixed SiteTree->getCMSActions() so it returns a FieldSet, instead of a DataObjectSet. This makes it consistent with DataObject->getCMSActions() as well as SiteTree->getCMSFields()
* ![rev:66632] Fixed SiteTree->getCMSActions() not extending properly because it was passing an array to the extend() 2nd argument, which expected a FieldSet object
* ![rev:66629] Fixed incorrect class name in user_error message for deprecated function HTTP::sendFileToBrowser()
* ![rev:66608] ModelAdmin clear search now preserves the result column selection
* ![rev:66505] Consistenly returning cloned instances for all FormField classes when calling performReadonlyTransformation() or performDisabledTransformation(). Making sure that these instances are actually flagged as readyonly/disabled. Addd unit tests to dynamically instanciate most FormField classes to check for this behaviour. Originally, this bugfix was necessary to avoid changed FormField state when recursively calling replaceField() on FieldSet->dataFields() in Translatable->updateCMSFields()
* ![rev:66431] Removed SearchForm->FormMethod() and used $this->setFormMethod() in SearchForm constructor instead which is a nicer solution instead of overloading a Form method
* ![rev:66334] Hiding "change password" fields by default in admin/myprofile, they shouldn't validate the input by default. Replaced with a link to toggle those fields (#3106)
* ![rev:66332] Include jquery_improvements.js whenever jquery.js is required, so jQuery.noConflict() is set. This is required to ensure $() behaves in the prototypey way (alias for document.getElementByID()) rather than jQuery style (document.getElementsBySelector())
* ![rev:66331] Removed overloaded $() function which added support for multiple string arguments in behaviour.js - was conflicting with argument usage in jQuery when not in noConflict() mode. As far as i can tell, multiple string arguments in $() were never used anyway.
* ![rev:66319] Removed dependency on ComplexTableField JS in LeftAndMain for "My Profile" popup
* ![rev:66318] Check if $member variable isn't empty before looking for first name in MemberLoginForm
* ![rev:66317] Fixed call to incorrect case of function name, Member::currentUser() should be used
* ![rev:66313] Fixed ForeignKey->scaffoldFormField() usage of model class instead of relation class to generate dropdown list
* ![rev:66309] Fixed far too small height and width of "Profile" popup in CMS, popupHeight and popupWidth should be defaultPopupHeight and defaultPopupWidth instead according to the ComplexTableField prototype
* ![rev:66306] Fixed HasManyComplexTableField, and subclass fields HasOneComplexTableField and ManyManyComplexTableField saving bug because javascript wasn't being included properly
* ![rev:66305] Fixed recursion bug with FieldSet::fieldPosition
* ![rev:66274] Improved reliability of LeftAndMain->CMSVersion() - not failing on empty $URL$ placeholder with subversion path to determine version numbers
* ![rev:66269] Merged from trunk; fix DataObject::hasDatabaseFields()
* ![rev:66266] Fix test/cookie conflict in ErrorPage rendering
* ![rev:66252] Immediately apply behaviours that are added after the Behaviour.apply() call, in Behaviour.register() calls as well as Class.applyTo() calls
* ![rev:66251] Removed unnecessary and bug-causing Behaviour.apply() call.
* ![rev:66250] Made Behaviour.apply calls more specific
* ![rev:66229] Added flash button to tinymce_ssbuttons
* ![rev:66196] #2714 - Cookie::set doesn't operate correctly with expiryDays 0 (wakeless)
* ![rev:66195] #2694 - Mathspam question clear
* ![rev:66194] Fixed draggable bug in AssetTableField - thanks for ajshort for the patch - ticket #3051
* ![rev:66162] #118 - Fixed count of marked pages (hamish)
* ![rev:66137] Fixed editable formfields not showing up in translation mode (#3083). Updated Translatable->updateCMSFields() by partially merging wakeless' patch from (r64523)
* ![rev:66136] Disabled js code in CMSMain->switchlanguage() which was assuming wrong DOM structure (TODO: Replace with more robust selectors)
* ![rev:66135] Fixed field labels for original readonly fields in translation mode
* ![rev:66107] Fixed PHP variable initialization in SiteTree->getClassDropdown() which broke class dropdown in behaviour tab (regression from r66092)
* ![rev:66091] $cache flag wasn't passend through from ViewableData_Customised->XML_val() to ViewableData->XML_val()
* ![rev:66079] #3051 ajshort: Improved layout of assettablefield drag icon
* ![rev:66070] Fixed HTTP->findByTagAndAttribute missing variable error causing HtmlEditorField to break since it used HTTP::getLinksIn()
* ![rev:66067] #3065: Fixed restore page
* ![rev:66066] #3012 jam13: Fixed tabstrip default tab selection when working with querystrings
* ![rev:66065] Fixed security tabs for JSoD code
* ![rev:66062] #3063: Allow old-school method of adding menu items to LeftAndMiain:
* ![rev:66052] #3087 simon_w: Added ResfulService::connect() back, for backward compatability
* ![rev:66049] Fixed unescaped html display in DevelopmentAdmin (#3080)
* ![rev:66044] Fixed `<% require %>` call in ModelAdmin_left.ss
* ![rev:66043] Fix PHP notice where variable with array didn't exist in HTTP->findByTagAndAttribute()
* ![rev:66029] use a undefined variable $member.
* ![rev:66027] Fixed incorrect call to Permission::checkMember() - missing second argument, first argument should've been a Member object or Member ID
* ![rev:66026] Fixed PHP notice level error in some circumstances in DataObject->buildDataObjectSet()
* ![rev:65944] #3073: Fixed LeftAndMain::deleteitems()
* ![rev:65923] #3066: Fix ?isDev=1 option
* ![rev:65900] #2868: Fix after-popup-close behaviour on security member table
* ![rev:65899] #2820: Fixed use of buggy reflection in Object::uninherited()
* ![rev:65896] #2706: Fixed JS error in multi-nested pages deletion
* ![rev:65895] #2232: Prevent requirements from breaking ErrorPage publication
* ![rev:65894] #1721: Fixed del/ins styling in page comparison
* ![rev:65881] Don't let permission errors on assets/ folder completely prevent javascript from loading
* ![rev:65865] Fixed tabstrip JS error in ReportAdmin
* ![rev:65863] Ensure that menu items of the same priority show the first added item closes to the left
* ![rev:65860] Fixed JS error in ReportAdmin
* ![rev:65851] #3062: Fixed ondemand support for jQuery responses as well as prototype
* ![rev:65850] Alow decoration of Member with has_many relationships
* ![rev:65843] #3062: Fixed ondemand support for jQuery responses as well as prototype
* ![rev:65842] #3061: Text.FirstSentence returns '.' instead of empty string on an empty field
* ![rev:65827] Fixed flash uploader not searching for the correct files, due to changes in r65820
* ![rev:65825] Tidied up messages in flash uploader right hand panel in CMS
* ![rev:65769] Fixed deletion of RedirectorPage
* ![rev:65763] Missing variable in some circumstances caused Requirements::include_in_response() to break
* ![rev:65761] Missing variable in some circumstances caused Requirements::include_in_response() to break
* ![rev:65711] Added support for CSS media types to CSS on demand
* ![rev:65680] there is no horizontal scroll bar for Model Admin right panel if the results table is long.
* ![rev:65671] temp fix for flash inserter.
* ![rev:65616] Fixed searching on sapphire/trunk due to Form changes - FormAction was useless on SearchForm anyway
* ![rev:65612] Removed offending $this->canEdit() which returned a boolean, not appropriate to be passed into Member::mapInCMSGroups()
* ![rev:65583] Adjusted Translatable to api changes from r65581
* ![rev:65554] a lot of methods in this class now passed $params as HTTPRequest object, rather than as a array if the function is called from Ajax or top-level of front-end, some method is called in both manner, ie. called from Ajax and called internally as well, so we need to check $params type and do further process. This is a partial fix of open source ticket #3035
* ![rev:65539] Setting correct user locale in ImageField and FileIframeField - the controller is separate from the CMS context, so wasn't initialized with i18n (see #1727)
* ![rev:65538] Using 'SiteTree' classname instead of 'Page' in UpgradeSiteTreePermissionSchemaTask to avoid clashes in schema when Page.php has its own tables
* ![rev:65536] Making Metadata fields writeable in translation mode (see #2993)
* ![rev:65518] Removed project-specific hack in DataObject->getManyManyComponentsQuery() as it was breaking Translatable saving
* ![rev:65517] Fixed breadcrumb exploding in DebugView when base-URL is "/" - was confusing the str_replace() logic
* ![rev:65515] Fixed Translatable::default_lang() call in CMSMain
* ![rev:65512] Fixed SiteTreeMaintenanceTask from extending unkown class Task to extending Controller
* ![rev:65510] #3015: Fixed close buttons on tinymce side panels
* ![rev:65502] Fixed bug with // placement in CMSMenu Director rule generation
* ![rev:65469] Better initial-site-setup boundary condition checking needed after the manifest builder update
* ![rev:65462] Setting Director::set_site_mode('site') in RootURLController in newly added init() method, which fixes Translatable::choose_site_lang(). The original bug was a wrong selected language in the `<meta>` tags through SiteTree->MetaTags()
* ![rev:65456] Using uncached DataObject::get_one() calls in ModelAsController to avoid stale data with subsequent Director::test() calls which alter the page relations inbetween
* ![rev:65424] #2987 - IE8 support via IE7 compatability mode
* ![rev:65394] Fixed broken dev/build compilation of manifest
* ![rev:65361] Added SSViwer support for i18n namespaces in templates with `<% _t('MyNamespace.MyEntity', ... %>`, to work around magically added namespaces from the parsed template file. Those auto-namespaces were logically not working in includes, as the parsing context is always the including template. Legacy support for auto-namespaces is still present due to its high usage.
* ![rev:65336] Making ModelAdmin labels in left panel translatable again (regression from moving them into one common panel)
* ![rev:65335] Respecting $dontEscape in FormAction
* ![rev:65293] Using empty title in TreeDropdownField->Field() if the related DataObject cannot be found
* ![rev:65291] Reverted text replacement performance improvement in SQLQuery - it was replacing more ocurrences via str_replace() than the previous implementation based on arrays, which broke queries augmented by Translatable (originally committed in r60468 and r54044)
* ![rev:65282] Fixed page comment javascript to suit new Form name
* ![rev:65275] #2243: Fixed ViewableData::Odd
* ![rev:65271] #2630 - Removed notice-level error
* ![rev:65269] #2954 - Fixed support for negative numbers in decimal fields
* ![rev:65250] #2992: Fixed T_PAAMAYIM_NEKUDOTAYIM error in RequestHandler
* ![rev:65242] fixed canPublish() so it actually got the member if none was passed and fixed notice with $results not existing
* ![rev:65232] #2056: Removed all references to deprecated Member::isAdmin()
* ![rev:65229] Allow DBField::__construct() without a name
* ![rev:65214] Remove LeftAndMain entry from CMSMenu (#3014). Thanks to hamish for the patch!
* ![rev:65213] Only enforcing record-level permissions in LeftAndMain if passed ID is numeric to avoid breaking AssetAdmin with string-based IDs (regression from r65152). See #3017
* ![rev:65212] Calling parent constructor in ComplexTableField_ItemRequest, was confusing RequestHandler
* ![rev:65180] Add magic methods on ModelAdmin to $allowed_actions (regression from r64988)
* ![rev:65174] MemberTableField use of sourceFilter should be treated as a string, not an array as per the API of TableListField
* ![rev:65152] Enforce permission checks in LeftAndMain and CMSMain through SiteTree->canView()/canEdit()/canAddChildren()/canPublish()/canDelete() (see #2701)
* ![rev:65151] Fixed SiteTreeAccess.js DOM IDs to field changes made in r65150
* ![rev:65150] Disallow SiteTree->canEdit() if SiteTree->canView() is not granted
* ![rev:65148] Fixed js error in LeftAndMain_right.js when displaying readonly pages
* ![rev:65141] TableField delete row inconsistency with TableListField which caused table fields to not fade the row out
* ![rev:65135] Fixed call to Member function that didn't exist
* ![rev:65127] Fix potential PHP notice opening a ComplexTableField popup
* ![rev:65123] Fixed bug with ID-less generation of YamlFixture entries that trigger $this->write() in setters
* ![rev:65106] Setting menu titles for CMSMenu items in LeftAndMain::init() to get translated values for the current user locale (see #2873)
* ![rev:65104] Fixed menu titles entity references in CMSMain and AssetAdmin
* ![rev:65094] Fixed SearchContextTest to comply to new scaffolded searchfield in Text DBFIeld
* ![rev:65071] Reverted auto-detection of i18n statics like $db in DataObject through provideI18nEntities() - was getting too complicated with decorated properties. Overload DataObject->fieldLabels() or DataObjectDecorator->updateFieldLabels() instead
* ![rev:65063] Checking for array existence before iterating through DataObjectDecorator->provideI18nEntities()
* ![rev:65062] Dont instanciate abstract classes in i18nTextCollector
* ![rev:65061] Using SiteTree::get_by_url() (see r65060)
* ![rev:65057] Collecting i18n entities for decorators separately from the decorated classes, as decorated properties like $db have to be stored in the module of the decorated, not in the module of the decorated class.
* ![rev:65030] Different class_implements() usage without instanciating the class in i18nTextCollector - not all classes are instanciatable without arguments. This raises the minimum requirement for text collection to PHP 5.1+
* ![rev:65028] Fixed SecurityAdminTest to work with i18n enabled
* ![rev:65026] Fixed CsvBulkLoaderTest to comply to hasHeaderRow API change (r64806)
* ![rev:65024] Fixed CMSMainTest to check for translated entities to avoid failing tests with i18n enabled
* ![rev:65023] Changed i18nTextCollectorTest to only trigger _t() calls in instance methods (they don't fully work in __construct()). Manually adding ClassInfo state for the fakewebroot needed to test textcollection - ManifestBuilder/ClassInfo currently don't support setting of other webroots, or flexible inclusion/exclusion of certain subfolders which would be necessary to do this without hacks.
* ![rev:64981] Don't allow calling of magically added methods via URL unless explicitly listed in allowed_actions
* ![rev:64976] Fixed wrong case of class names for ImageIFrameField causing errors
* ![rev:64879] Fixed title-handling in FormAction, regression from r64410
* ![rev:64878] Fixed missing $H() reference in i18n.js (#2989)
* ![rev:64850] Avoid ajax evaluator errors by checking if $resizedImage actually exists before calling relativePath() on it
* ![rev:64812] Content wasn't saving on subsequent page loads, after TinyMCE3 upgrade
* ![rev:64798] Fix DataObject::write() with a specified ID and forceInsert to be true
* ![rev:64788] in IE, overflow left pane is hidden and cannot enable scrollbar
* ![rev:64771] Made ContentController work properly if it doesn't have a dataRecord
* ![rev:64770] merged patch from ajshort to fix checkbox fields in the cms
* ![rev:64754] Fixed old references to GenericDataAdmin in ModelAdmin.php and ModelAdmin_Results.ss
* ![rev:64739] Security->passwordsent() didn't get the "Email" variable from the URL properly, because of updates to HTTPRequest
* ![rev:64736] Fixed non-object or not null error in TreeSelectorField
* ![rev:64732] New folders weren't getting their name set correctly, instead they would just be called "NewFolder". This occurred in the Site Content section of the CMS, creating a folder using the right hand panel in that section.
* ![rev:64604] Fixed incorrectly reverted methods related to sizing of the popup.
* ![rev:64601] Fixed extra class addition on various FormField->Field() methods
* ![rev:64562] Using include_once() instead of include() for _ss_environment.php in install.php and Core.php to avoid PHP notice errors about double constant defines (see r64561)
* ![rev:64506] Renamed "Save & Publish" to "Save and Publish" since this value is used in the value attribute of input elements, properly parsed, this would produce &amp; instead of &
* ![rev:64494] Fixed distribution of textcollector files to modules (was collecting all entities into all modules before) - added unit tests
* ![rev:64491] Fixed wrongly formatted _t() call in Security class
* ![rev:64490] Fixed $module parameter for i18nTextCollectorTask
* ![rev:64471] Fix issue with language files not being included
* ![rev:64467] Removed duplicate setValue() method on Time (was supposed to be deleted instead of renamed from setVal() to setValue())
* ![rev:64466] posix_isatty sometimes returns a benign error
* ![rev:64462] Don't run migration code for permissions if the old field doesn't exist.
* ![rev:64443] Fixed RestfulServerTest fixture path
* ![rev:64440] Unit tests for RestfulServer (see r64439)
* ![rev:64439] Returning 409 Conflict HTTP Header when trying to create a resource on an existing URL through RestfulServer
* ![rev:64438] Removed $headingLevel reference from LabelField (was supposed to go into HeaderField)
* ![rev:64437] Second constructor argument $title for HeaderField should be optional for legacy reasons
* ![rev:64427] Using PasswordField instead of deprecated EncryptField
* ![rev:64423] Adjusted HeaderField and LabelField implementation to new constructor arguments (see r64421)
* ![rev:64422] Adjusted HeaderField and LabelField implementation to new constructor arguments (see r64421)
* ![rev:64361] #2963 - Fix RSSFeed to work with new add_cache_headers
* ![rev:64334] Reverted Member->isAdmin() removal since it's being used in a lot of places, we shouldn't deprecated it... yet.
* ![rev:64329] correct wrong syntax of TableField class in its frontend javascript
* ![rev:64328] avoid a CSSClass is added to a veiwable data twice.
* ![rev:64325] $this->extraData is not alway set for an TableField_Item
* ![rev:64320] If DropdownField->Field() lack of source checking before looping through it
* ![rev:64318] Fixed DropdownField handling of Iterator objects rather than arrays in the newly created getSource()
* ![rev:64314] If ajaxActionsOnTop is called twice, the actions are removed.
* ![rev:64313] Don't use singleton() to create DataFormatter instances, as it will cause weird side-effects with multiple formatter instances with different parameters (broke subsequent test runs of RestfulServerTest and SoapModelAccessTest) - all aboard the failboat!
* ![rev:64310] Unsetting $_SERVER globals in RestfulServerTest to avoid side-effects across unit tests
* ![rev:64309] Added RestfulServerTest->testApiAccessBoolean()
* ![rev:64307] Fixed RestfulServerTest->testAuthenticatedGET()
* ![rev:64275] fixed default_country_value so that it will actually call the default country if IP lookup doesnt work
* ![rev:64263] Fix disappearing fields when a field without a name was being pushed onto a FieldSet (eg a CompositeField)
* ![rev:64251] Fixed ComplexTableField->saveComplexTableField() success message object link - was assuming same context as ComplexTableField_ItemRequest
* ![rev:64239] Adjusted ForeignKey->scaffoldFormField() to new scaffolding notation ("ajaxSafe" instead of "ajax")
* ![rev:64237] Fixed FormScaffolder string literal parsing FALE in getFieldSet()
* ![rev:64229] Storing HTTP "Referer" header from $_SERVER in Director::direct() and passing it along in Director::test()
* ![rev:64228] Checking for an empty array for $postVars in Director::test() to determine HTTP method - an existing array should cause POST rather than GET, even if its empty
* ![rev:64227] Fixed stupid ommission from r64223 which caused HTTPRequest to construct without a proper URL
* ![rev:64224] Using fieldLabel() for $has_one relationships in FormScaffolder
* ![rev:64173] Fixed wrong call to scaffoldCMSFields() in Member->getCMSFields(), removed addScaffoldRelationFields() call as this is done by the newly called parent::getCMSFields() already
* ![rev:64153] #2906 - Fixed manifest conflict in web-tests
* ![rev:64142] fixed ss.i18n.sprintf() call in Validator.js
* ![rev:64124] #2936: Define STDOUT if it's not already defined...
* ![rev:64109] Fixed order of arguments.
* ![rev:64099] Bad XHTML in en_US language file (#2624) - thanks tiwoc!
* ![rev:64098] Director::fileExists() fails on windows with absolute paths (#2935) - thanks to ajshort!
* ![rev:64097] Fixed CSSContentParser to only use tidy on CLI mode if its available, and first check for existence of PHP tidy extension. Fixes failing unit tests on standard WAMP windows installations.
* ![rev:64096] Fixed CSVParser assumptions about absolute unix-style filepaths - using Director::absFile() instead now
* ![rev:64081] Consistent usage of ss.i18n.sprintf() instead of ss.i18n.printf() - the method is returning a string rather than outputting directly, so should be sprintf()
* ![rev:64077] Fixing AssetAdmin translations which were previously moved to Folder.php - i18n::include_by_class() doesn't like filenames/namespaces which are in a different folder than the language file they're referenced in (see #2359) - started in r64076
* ![rev:64076] Fixing AssetAdmin translations which were previously moved to Folder.php - i18n::include_by_class() doesn't like filenames/namespaces which are in a different folder than the language file they're referenced in (see #2359)
* ![rev:64074] Fixed AssetTableField javascript errors caused by r64049
* ![rev:64072] Fixed DebugView Breadcrumbs to not include query string as separate link, and don't append an arrow after the last element
* ![rev:64049] fix the bug that add some rules for summary columns even when they are not there.
* ![rev:64042] Using _t() to check content strings in unit tests and avoid tests failing when i18n is enabled
* ![rev:64038] Removed $_ALL_CLASSES in ReportAdmin::has_reports() - this doesn't need to be here anymore, due to changes in ManifestBuilder
* ![rev:64013] Limited error message scope on invalid classname for TestRunner
* ![rev:64011] Ignore TestOnly classes when collecting permissions
* ![rev:64010] Removed dependency of ss.i18n.js on other libraries by replacing $$ with document.getElementsByTagName() and implementing a custom event attacher - see #2927
* ![rev:64007] Making less assumptions about object structure in FieldSet->addFieldToTab() error messages
* ![rev:64005] YamlFixture->saveIntoDatabase(): In order to support reflexive relations which need a valid object ID, the record is written twice: first after populating all non-relational fields, then again after populating all relations (has_one, has_many, many_many). Fixes a bug where FileTest was testing onBeforeWrite() behaviour
* ![rev:64004] Writing record from yml before parsing relations in YamlFixture->saveIntoDatabase() to avoid missing lookups for reflexive relations on the same object
* ![rev:64002] Moved RecordController and CollectionController to external module (see r63905)
* ![rev:64001] Adjusted FormTest->testLoadDataFromObject() to new assumptions about changed behaviour on loadDataFrom() from $loadBlanks to $clearMissingFields - which means that form fields are cleared regardless if they have blank values in the passed object or not
* ![rev:64000] Making sure that DataObject->has*Field() methods always return an array, in order not to fail any array_key_exists() checks
* ![rev:63999] Fixing DataObject->hasField() to detect dynamic getters by using hasMethod("get$fieldName")
* ![rev:63998] Fixed Form->loadDataFrom() to properly populate FormField->setValue() when an object is passed as the first parameter (needed e.g. for CheckboxSetField->setValue()) - see mailinglist discussion at http://groups.google.com/group/silverstripe-dev/browse_thread/thread/717bada8ccafdd70
* ![rev:63983] Fixes so ?flush=1 doesn't stop showing the Reports tab in CMS
* ![rev:63981] Allow use of ClassInfo methods in _config.php when manifest is being rebuilt
* ![rev:63945] Added missing slash in TableListField_Item->Link()
* ![rev:63939] Improved RedirectorPage's handling of invalid configuration options to prevent infinite loops and segfaults
* ![rev:63927] Improved detection of CLI colour support
* ![rev:63920] Fix broken breadcrumbs
## Bugfixes
* ![rev:63915] #2588 Fix issue with IIS not stripping GET variables from the URL (mackeyn)
* ![rev:63909] Prevent misconfigured redirector pages from breaking static publishing
* ![rev:63890] Validation result was ignoring the $valid flag passed as the first argument.
* ![rev:63858] Fixed js i18n entity names for TableField (see #2916)
* ![rev:63857] Properly merging different dictionaries for javascript i18n implementation (see #2916)
* ![rev:63839] Added missing default english text to i18n call in TableField and TableListField javascript
* ![rev:63828] MemberTableField_Popup had an odd way of overloading saveComplexTableField() - this should be on MemberTableField instead, since that's the direct subclass of ComplexTableField for where saveComplexTableField() is defined. This broke the "Add Member" button in CMS Security, probably due to the way the form URLs have been changed. See ticket #2907 for the reported problem.
* ![rev:63825] Don't let Director::test() clobber current stage
* ![rev:63824] Fix FieldSet::replaceField() so that it doesn't clobber tabs
* ![rev:63823] SiteTree::onAfterPublish() will still pass an object to the handlers on the first publish
* ![rev:63819] Fixed pagination in TableListField after hsmith's changes
* ![rev:63813] Fixed array_key_exists check in DataObject->setField that was failing when DataObject->record was not yet initialised by DataObject->setField.
* ![rev:63809] PHP Notice in InlineFormAction_Readonly
* ![rev:63804] Side reports weren't working on initial opening of the side tab
* ![rev:63799] Fixed blatant error where $SNG_member wasn't defined
* ![rev:63797] Member->getCMSFields() should use scaffoldCMSFields() instead of scaffoldFormFields() - currently it is operating in the wrong context.
* ![rev:63793] MemberTableField->AddLink() was calling &methodName=add - this should be just "add", as per changes to the forum URLs in sapphire
* ![rev:63786] Removed query that was causing issues displaying members in the security groups. Open ticket #2591
* ![rev:63785] URLs to security groups in CMS were not linked correctly. Removed Director::link() references and replaced with strings. Director::link() is deprecated and shouldn't be used.
* ![rev:63769] Fixed paths to CSV fixtures for case-sensitive file systems.
* ![rev:63768] Fixed $fixture_file for Ext2fs and other case-sensitive file systems.
* ![rev:63748] Use of getOwnerID() in ReportAdmin which doesn't make sense, since ID() is sufficient.
* ![rev:63739] Fixed bug in getCMSFields scaffolding of relations
* ![rev:63716] Fixed createTag for proper generation of DropdownField blank items
* ![rev:63698] Only include i18n.js if javascript files are included - and to be safe, include the required prototype.js along with the library
* ![rev:63691] Removed old reference to ?executeForm=EditForm
* ![rev:63681] Requiring a parentController for RecordController
* ![rev:63649] Fixed unclear SQL escaping responsibilities in SearchFilter subclasses - it now expects unescaped data, and escapes automatically when adding to the query)
* ![rev:63647] Making "add %s" translatable for ComplexTableField
* ![rev:63640] Automatically including sapphire/javascript/i18n.js in Requirements::process_i18n_javascript() to avoid errors when Requirements are manually overwritten
* ![rev:63635] #2901 - RootURLController didn't properly manipulate the Controller stack
* ![rev:63634] Reverted earlier change to ModelAdmin.js statusMessage() display
* ![rev:63629] Translated Member formfields through fieldLabels()
* ![rev:63627] php notice in CountryDropdownField
* ![rev:63622] Disabled user_error in ComplexTableField->sourceID() when no formfield 'ID' is found in ComplexTableField->$detailFormFields - not strictly required as we can deduce it from the URL. It was causing conflicts with DataObject->scaffoldFormFields() not returning an 'ID' field
* ![rev:63621] Making sure that Dataobject->getManyManyJoin() inserts a valid database table for the relation - not all component classes returned by ComponentSet->ownerClass are valid tables (see r54797 and r60909 for previous commits on this issue)
* ![rev:63618] Escaping added database columns in queries for TableListField
* ![rev:63611] typo mentioned in #2775
* ![rev:63602] Fixed bounce-address generation so that it doesn't have a human component to the email address
* ![rev:63593] #1816: Added a little padding to page version table
* ![rev:63581] Fixed ComplexTableField export
* ![rev:63571] typo in js file
* ![rev:63570] typo in js file
* ![rev:63549] Updated TreeSelectorField to work properly within CTF popups
* ![rev:63527] Removed notice-level errors in ListboxField
* ![rev:63525] #2883 - Remove use of short tag
* ![rev:63509] Fixed DataObject::dbObject() operation with CompositeDbFields
* ![rev:63467] Fixed Upload->isValidExtension() - was checking array keys instead of array values ....
* ![rev:63464] Fixed hardcoded HTTP protocol information in BasicAuth
* ![rev:63457] AssetAdmin->Link() returned a trailing slash that was not necessary. See ticket #2884
* ![rev:63452] Fixed ReportAdmin breakages - changes to HTTPRequest required that show($params) be changes to show($request) and then check $request->allParams() for the URL parameters - this caused major breakages as this code was not updated to reflect the new URL handling changes.
* ![rev:63432] #2753: Couldn't have fields named the same as methods
* ![rev:63304] #2529: Fixed HTTP/1.0 support
* ![rev:63297] Fixed loading indicator in for add form in ModelAdmin.js
* ![rev:63296] wrong jsparty PATH references
* ![rev:63295] wrong jsparty PATH references
* ![rev:63294] Fixed ModelAdmin Requirements path references
* ![rev:63291] Don't try to use HTTP_HOST environment variable if its not set in Director::protocolAndHost(). Throw a warning, then return false - before if script execution was not set to stop on WARNING, you'll get a NOTICE as well.
* ![rev:63290] Moved *_PATH and PR_*constants from main.php/cli-script.php back to Core.php - was causing problems with installer (directly includes Core.php, but doesn't run through main.php) - see ticket #2867 for improvement suggestions in bootstrapping code to avoid these bugs
* ![rev:63204] Moved TEMP_FOLDER define back from main.php/cli-script.php to Core.php, as it was causing problems with the installer
* ![rev:63157] Reverted Director class using BASE_PATH instead of dirname(dirname(['SCRIPT_FILENAME'])), originally committed in r63154
* ![rev:63079] decrease width of elements in image/flash/link panel on right-hand side to avoid close-button being shoved off to the void (#1669)
* ![rev:62910] #2390: Not indexed pages are removed from sitemap.xml
* ![rev:62909] Fixed bug introduced into AssetTableField by previous CTF change
* ![rev:62892] #2721 - Show decent preview on FileIFrameField
* ![rev:62885] Fixed a number of really basic problems with a number of date fields - got basic loading and saving working across them all
* ![rev:62875] More robust setting of defaults; necessary due to altered ViewableData::__isset()
* ![rev:62868] #2697 - Removed junk slash from login message
* ![rev:62701] Changed URL format for password sent confirmation display, to avoid issues with new request handling trying to detect the email-TLD as a pseudo-file-extension (which resulted in truncated email-addresses in display). Old: /Security/passwordsent/myemailaddress. New: Security/passwordsent/?email=myemailaddress
* ![rev:62490] createTag() on FormField subclasses should use getTabIndex() instead of getTabIndexHTML() as createTag() is responsible for generating the HTML, and all we need is the tabindex value
* ![rev:62471] Allowing HTTPRequest::match() to match rules with extensions (e.g. /sitemap.xml used for GoogleSitemap)
* ![rev:62463] Pushing current controller into stack in RootURLController->handleRequest to Session-usage in Translatable if enabled. Session::get() is dependent on controllers, and is needed to determine the current language for any Translatable queries (like RootURLController::get_homepage_urlsegment())
* ![rev:62381] Type checking problem in LookupField->Field(), merged in from r62387
* ![rev:62325] Removed DataReport.js calls in LeftAndMain until we figure out a better way of doing
* ![rev:62324] Removed DataReport.js calls in LeftAndMain until we figure out a better way of doing
* ![rev:62320] Allow creation of a tab and a field of the same name; bug cause by the duplicate field merging code introduced recently.
* ![rev:61975] not all decorators has a summary_fields defined, so the code need to deal with this.
* ![rev:61699] Fixed bulk loader constructor
* ![rev:61686] Fixed styling, searching, and pagination of CommentTableField
* ![rev:61505] Fix direct access of (class)/(id)/edit on the ModelAdmiN
* ![rev:61395] SetHeight() was calling SetWidth using getFormattedImage()
* ![rev:61292] fixed ManyMany relation for same object
* ![rev:61202] Reverted change r61158 which stopped scrollbars working
* ![rev:61195] Asset area in CMS refused to load because of error in code from r60920 - #2751
* ![rev:61162] sourceFilter should be a string, not an array
* ![rev:61155] HtmlEditorField_Toolbar->LinkForm() for editing a link inside an HtmlEditorField instance was showing page titles using the "Title"
* ![rev:61151] ComplexTableField_popup.css "overflow: auto" should only be applied to the container HTML element instead of HTML and BODY which can
* ![rev:60920] #1458 - GEOIP now does not return any error if it cannot look up the ip address (as it uses a shell command this is not enabled on many WAMP systems)
* ![rev:60897] fixed Member name not being saved in database with ReadonlyField()
* ![rev:60757] Fixed TableListField->Link() to allow for instanciation without a form/controller (e.g. for unit tests)
* ![rev:60756] Fixed ScaffoldINGComplexTableField file name
* ![rev:60726] Fixed DataObject::fieldLabels() to detect labels on inherited database fields
* ![rev:60723] Fixed partial merge from nzct (originally from r47039, partially merged in r60440)
* ![rev:60712] Fixed ModelAdmin typo in $searchCriteria method parameter
* ![rev:60710] Fixed $this reference in static Member call
* ![rev:60643] Reinstated error_handling(E_ALL) for dev environments in main.php after clarifying with sam - we want to force developers to recard notice-level errors unless they expicitly opt-out in their _config.php
* ![rev:60636] Disabled mandatory override of default PHP error handler to E_ALL when in dev mode (which means you have no way of overriding error_reporting() in your _config.php, and by that no way of disabling e.g. E_NOTICE level errors)
* ![rev:60635] Fixed CMSMainTest to use /admin/crm as a standard URL rather than /admin (which could be overloaded by other admins for application-like interfaces without CMS components)
* ![rev:60573] Fixed bug with unpaginated TableListFields. Added tests for TableListField pagination
* ![rev:60415] Added Requirements::path_for_file() to support external URLs in required paths (incl. unit test)
* ![rev:60413] Fixed RequirementsTest combine_files() testing to accept new javascript inclusion format with added modified flags
* ![rev:60412] Fixed JSON.php include path in Convert.php
* ![rev:60410] Fixed test runner's handling of errors
* ![rev:60404] Further fixes to Director::test()
* ![rev:60397] Changes to DataObject::get_one() caching to try and fix segfaults
* ![rev:60393] Fixed superglobal masquerading in Director::test()
* ![rev:60388] Fixed Yaml fixtures for SapphireTest
* ![rev:60382] Re-added additional GroupTest tests (merge error from branches/roa)
* ![rev:60378] Removed duplicate GroupTest.php files
* ![rev:60224] Fixed merge error in ModelAsController
* ![rev:60219] Fixed reverted access checks in Controller->handleAction() due to merge error
* ![rev:60213] Javascript error in ComplexTableField_popup.js - missing a comma in an object literal which broke ajax updates in the CMS
* ![rev:60092] Using $extraClass in AutocompleteTextField
* ![rev:59340] Fixed TableListField->setClick_PopupLoad() to parse ID-value out of new `<td>` identifiers
* ![rev:59285] Changed span.middleColumn to .middleColumn in cms_right.css in preparation for building proper HTML/XHTML nesting in formfields
* ![rev:59284] Changed span.middleColumn to .middleColumn in cms_right.css in preparation for building proper HTML/XHTML nesting in formfields
* ![rev:59283] Fixed i18n namespacing issue in TableListField_Item.ss - was using _t('Form.DELETE'), but templates don't allow to re-use variables outside their own namespace
* ![rev:59282] Removed duplicate SecurityID fields on each row of a TableField (calls $myForm->Fields() which by default will include more than the actual form fields passed to the constructor)
* ![rev:59281] Fixed colspan on `<td class="actions">` in MemberTableField.ss
## Enhancement
* ![rev:71650] Applying the asynch request patch to our tag field. We use a simple queue management idea to keep only the latest ajax request is valid, ie, we abort all requests before the current request is submitted, so that there is only at most one request spanning in the client side, so no early request's response cover late request's response, also greatly enhance the performance of both sides, especially in case of complicated operations in server side and complicated post-events in client side.
* ![rev:71597] delete button keep spinning when cancel a deletion operation from the confirm window.
* ![rev:70956] Ticket 2756: Newsletter performance problem, run out of memory.
* ![rev:70861] Allow selection of the unique identifier field on Member by setting Member::set_unique_identifier_field(AnotherField). Default is "Email".
* ![rev:70846] When MemberLoginForm controller page has loaded, focus on the Email input field so the user doesn't have to focus the field themselves. Ticket #3418
* ![rev:70809] Removed blacklist newsletter specific code out of core and into newsletter module
* ![rev:70783] Export to CSV data of MemberTableField gets all fields on the member from the db array, instead of just FirstName, Surname and Email
* ![rev:70775] Removed BrowserDetect javascript library which was randomly placed in Security_login.js and just included in AssetAdmin. Reverted to regex-matching for simple browser detection for now
* ![rev:70465] Allow Member::getCMSFields() to be extended via DataObjectDecorator->updateCMSFields()
* ![rev:70190] Added nicer (and more useful) error message if ErrorPage cannot open the error HTML file for writing
* ![rev:70131] Creation of a new page type now uses a consistent source of classes that respect $hide_ancestor on SiteTree.
* ![rev:70064] Default to "Page" for new page type dropdown
* ![rev:70060] Added a table for showing linked pages in the Report -> BackLinks tab
* ![rev:69954] Calling augmentSQL() on decorators in DataObject::get(), which is necessary (among others) to limit ContentController->getMenu() with Translatable enabled to the currently active language. Was previously just implemented in DataObject::get_one()
* ![rev:69953] Passing through same arguments in SiteTree::get_by_url() than in the wrapped DataObject::get_one()
* ![rev:69952] Removing specialized routing for Translatable from Director->currentPage() and ModelAsController->getNestedController. Calls SiteTree::get_by_url() now, which abstracts out the Translatable handling.
* ![rev:69924] #3313 gigtech: Added ComplexTableField::setAddTitle()
* ![rev:69909] Allowing for passing of $context in Hierarchy->markChildren()
* ![rev:69896] Allowing more arguments in Object->extend() (merged from branches/translatable in r64523, thanks wakeless!)
* ![rev:69895] Added SQLQuery->filtersOnFK() (merged from branches/translatable in r64523, thanks wakeless!)
* ![rev:69891] Moved i18n::get_existing_content_languages() to correct namespace in Translatable::get_existing_content_languages().
* ![rev:69888] Added DataObjectSet->replace()
* ![rev:69864] Allow selection of parent page with adding page through URL - Ticket #3177. Thanks simon_w!
* ![rev:69833] Separated the class name for captioned images to normal images, so styling can be separately applied
* ![rev:69824] Caption support for the HtmlEditorField in the SS CMS. Ticket #2937
* ![rev:69823] Caption support for the TinyMCE editor in the SS CMS. Ticket #2937
* ![rev:69821] #3180: Added RsyncMultiHostPubilsher to 2.3 from trunk
* ![rev:69734] Allow specifying application URL for the top right logo instead of hardcoded silverstripe.com. Thanks hamish!
* ![rev:69661] Removed /cms URL alias for CMS interface to allow for pages named "cms" (see #3267)
* ![rev:69660] Removed /silverstripe URL alias for CMS interface to allow for pages named "silverstripe" (see #3267)
* ![rev:69449] Added .message styles to cms/css/layout.css
* ![rev:69370] Add a `<span class="highlight">` around all keywords (space delimited) and not just the entire search phrase
* ![rev:69360] Update ForeignKey and Primary key default fields to use SQLMap for their dropdown source for better performance.
* ![rev:69323] Added styling for "form .message.notice" in sapphire/css/Form.css
* ![rev:69322] More readable (and linked) output of "you are comparing..." message when viewing version of a page
* ![rev:69244] Added renameField() to FieldSet
* ![rev:69224] Allow choosing ellipsis for truncated text on Text->LimitWordCountXML()
* ![rev:69218] Added ability to define the ellipsis for LimitWordCount() setting "..." as the default
* ![rev:69207] Changed order of array merging in DataObject->db() - contains fields from subclasses at end of the array instead of the beginning. Important because db() is used by FormScaffolder, which shoved custom fields on the front of auto-generated forms. Shouldn't have any effect on the actual content of returned array
* ![rev:69204] Hiding Member->BlacklistedEmail field in getCMSFields() by default - only relevant in newsletter/bounce context at the moment
* ![rev:68860] Added RestfulServerTest->testGETRelationshipsXML()
* ![rev:68818] Appending classnames to translated pagetype titles in CMSMain->getPageTypes() when the cms is loaded in a non-english version - see inline comment
* ![rev:68817] Appending classnames to translated pagetype titles in SiteTree->getClassDropdown() when the cms is loaded in a non-english version - see inline comment
* ![rev:68771] Improved display of class permissions in /admin/security by using the menu title in addition to the classname (users won't necessarily know which classname an admin area corresponds to). Also using "Access to all CMS interfaces" as a permission description for CMS_ACCESS_LeftAndMain
* ![rev:68761] Making Date->Ago() translatable
* ![rev:68747] Using i18nEntityProvider on SiteTree to ensure entities in "Page" namespace get stored on sapphire instead of the "module folder" for Page.php - we can't make those properties translatable within core if they are in a custom folder
* ![rev:68745] Allowing textcollection of multiple modules selectively
* ![rev:68701] Allow HtmlEditorField on front-end forms
* ![rev:68508] Checking for $_FILE_TO_URL_MAPPING in DevelopmentAdmin if called in CLI mode to avoid nasty bugs e.g. during FunctionalTest sessions (Example: Controller stack was failing for some weird reason in LeftAndMainTest)
* ![rev:68460] Added CMSMenu::get_viewable_menu_items() and using it in LeftAndMain->MainMenu()
* ![rev:68193] Added Email->setTemplate() and Email->getTemplate() (as the Email_Template class is deprecated)
* ![rev:68160] Added support for specifying target module in i18nEntitityProvider->provideEntities()
* ![rev:68156] Added support for specifying target module in i18nEntitityProvider->provideEntities()
* ![rev:67984] Documented and improved DataObjectSet->PaginationSummary(). Removed DataObjectSet->paginationSummaryDots
* ![rev:67675] Fixed Email::obfuscate() to include custom CSS for reversing the email address using the "direction" method
* ![rev:67638] Added "reverse" method to Email::obfuscate() to reverse the email address in PHP, then CSS can be used to reverse it back to normal to avoid email harvesting
* ![rev:67502] Added SSViewer::get_source_file_comments()
* ![rev:67422] Allow setting of the legend value in the Form template by use of Form->setLegend('my legend')
* ![rev:67398] Added ability to include a blockquote in the CMS WYSIWYG editor
* ![rev:67345] Allowing custom methods in DataObjectSet->column()
* ![rev:67321] Only showing import form in ModelAdmin if an importer is set
* ![rev:67294] Added SITETREE_GRANT_ACCESS permission code to SiteTree to control editability of the "Access" tab (incl. unit tests)
* ![rev:67292] Supporting object parameter in FieldSet->makeFieldReadonly()
* ![rev:67291] Added mock controller instances to each FunctionalTest, which passes the existing mock session object into the controller stack. This means Sesssion::get()/set() in application code will use the test session. Helpful mainly for overriding login information used by Member::currentUser().
* ![rev:67242] Make it easier to create pageless subclasses of Page_Controller
* ![rev:67224] Adding "close popup" link after saving /admin/myprofile (see #3195)
* ![rev:67139] Added TreeDropdownField->refresh() js method
* ![rev:67138] Allowing usage of extraClass() in TreeDropdownField
* ![rev:67083] Using TEMP_FOLDER for StaticExporter
* ![rev:67072] Disallowing CMSMain->revert() if SiteTree->canPublish() is not granted (used to be SiteTree->canEdit()). If a user isn't allowed to publish, he shouldn't be allowed to revert the live state of a page either.
* ![rev:67061] Moving "save" and "delete" cms actions from CMSMain->EditForm() into SiteTree->getCMSActions() to make them decoratable (e.g. disallow delete action) and easier to cover with unit tests. Leaving fallback "save" and "delete" actions in CMSMain in case no actions are defined (necessary e.g. for Group class in SecurityAdmin)
* ![rev:66958] Added SearchForm->setPageLength() and SearchForm->getPageLength()
* ![rev:66946] Add `<%-- --%>` comments
* ![rev:66830] Disabled sending of warnings through Debug::send_errors_to() by default. If you need extended error reporting including warnings (e.g. for a site which is still in active development), use Debug::send_errors_to('example@example.com', true) or Debug::send_warnings_to('example@example.com')
* ![rev:66803] Just redirect back after "import" action called, and set the session message on the Form object instead of hardcoded ID
* ![rev:66654] Renamed tab "Meta-data" to "Metadata" for better readability (see #3142)
* ![rev:66646] Fixed default level in HeaderField - was duplicating defaults already present in two other places (see r66639)
* ![rev:66625] Allow CheckboxSetField to use extra classes as other FormField classes do. Also dded test for this behaviour in CheckboxSetFieldTest.
* ![rev:66622] Sort test class list by alphabetical order so it's easier to read
* ![rev:66596] Defaulting to show all columns in ModelAdmin CSV export, ignoring user selection of result table columns (users can always limit CSV columns by manually deleting them e.g. in Excel)
* ![rev:66583] Added experimental support using (relname)Query methods to pass complex relations (those defined by methods) into searchfilter
* ![rev:66343] Added comments in rendered templates to indicate the source .ss files, on dev sites only:
* ![rev:66333] Added ConfirmedPasswordField->setShowOnClickTitle()
* ![rev:66323] If there are no files in a folder in AssetAdmin, show a message
* ![rev:66322] Added SearchFormTest
* ![rev:66320] Added more known file extensions (tiff, js, html, css, ico) to File->getFileType()
* ![rev:66312] Added support for $relationCallbacks on the importer class (in addition to methods on the model class)
* ![rev:66173] Moving GoogleSitemap functionality (priority dropdown and database fields) from SiteTree to GoogleSitemapDecorator
* ![rev:66168] Removed GoogleSitemap references in SiteTree (moving to decorator implementation)
* ![rev:66137] Added TranslatableTest with minimal assertions about existing form fields in translation mode
* ![rev:66045] Added support for custom importer methods in CsvBulkLoader
* ![rev:65827] Added error messages to flash uploader panel, to be consistent with the image uploader one
* ![rev:65582] Using actual classname in DataObjectSet->debug()
* ![rev:65581] Added unit tests for FieldSet->insertBefore()/insertAfter()
* ![rev:65513] Using currently used content languages for options in the TinyMCE spellchecker (see http://open.silverstripe.com/ticket/2498#comment:2)
* ![rev:65508] Added language tables for tinymce_ssbuttons Plugin, incl. German translation
* ![rev:65495] Calling UpgradeSiteTreePermissionSchemaTask from SiteTree->requireDefaultRecords as a temporary workaround for missing migration infrastructure. This means that upgrading the schema for 2.3 can be done without manual task triggers, just the usual dev/build (see http://open.silverstripe.com/ticket/2847#comment:4)
* ![rev:65494] Added DatabaseTest
* ![rev:65464] Better CLI output for browsing dev/tests
* ![rev:65463] Allowing strings instead of arrays in ModelAdmin::$managed_models to make it less error-prone for beginners
* ![rev:65457] Allowing to pass strings instead of arrays into FunctionalTest->assert*() methods, and convert them internally to arrays
* ![rev:65455] Adjusted AssetAdmin to Folder->can*() changes
* ![rev:65454] Added LeftAndMainDecorator
* ![rev:65453] Added stub methods to DataObjectDecorator for documentation purposes
* ![rev:65452] Allowing decoration of can*() methods in File and Folder
* ![rev:65361] Added unit tests for i18n template parsing
* ![rev:65266] Folder name can now be used for uploading files. Ticket #3026 - Thanks simon_w!
* ![rev:65181] Updated LeftAndMain->getMenuTitle() to use classname as fallback if $menu_title is not defined - one less thing to specify in a minimalist ModelAdmin subclass
* ![rev:65173] Refactored CSS applied to filter boxes by using common selector
* ![rev:65153] Added UpgradeSiteTreePermissionSchemaTask as a manual migration of SiteTree schema upgrades in 2.3 (see #2847)
* ![rev:65150] Added unit tests for SiteTree permissions
* ![rev:65147] Only logging out users on Security::permissionFailure() is called in non-ajax context. For ajax requests, we now return a 403 HTTP Status in a HTTPResponse Object, with a ":NOTLOGGEDIN" body for backwards compatibility. If a logout+redirection is required after an ajax-request, this should be handled by the clientside.
* ![rev:65125] Added a "strict-mode" for Member->inGroup() and Member->inGroups() to determine true membership to a group (without inheritance)
* ![rev:65092] Scaffolding TextField instead of TextareaField in Text DBField due to size
* ![rev:65073] Added fieldLabels() overloading to various DataObject subclasses. Use this method instead of directly calling _t() in getCMSFields(), and use fieldLabel('MyField') to get the label for a specific FormField. This way, we can transparently support formfield scaffolding and re-use the labels for search fields automatically.
* ![rev:65072] Added fieldLabels() overloading to various DataObject subclasses. Use this method instead of directly calling _t() in getCMSFields(), and use fieldLabel('MyField') to get the label for a specific FormField. This way, we can transparently support formfield scaffolding and re-use the labels for search fields automatically.
* ![rev:65056] Removed DataObjectDecorator->updateSummaryFieldsExcludeExtra() - was a straight copy of updateSummaryFields()...
* ![rev:65055] More solid fulltext checks against master language tables in i18nTextCollectorTest
* ![rev:65054] Using eval() in textcollector to test for valid PHP syntax
* ![rev:65051] Added unit tests for i18nTextCollector handling of newlines in entity values
* ![rev:65029] Using namespaces for filenames in RequirementsTest
* ![rev:65027] Using safer get_by_id() call in SecurityAdmin->getMemberForm()
* ![rev:65022] Added i18nEntityProvider interface (see comments in #1625) incl. unit tests
* ![rev:65020] Allowing translation of some static properties on DataObject and subclasses through DataObject->fieldLabels(). Part of the provideI18nEntities() work which was started in r64881 (see #1625)
* ![rev:64881] Ignoring entity-names with $ signs (most likely dynamic properties) in i18nTextCollector->collectFromCode()
* ![rev:64878] Added unit tests for i18n.js
* ![rev:64682] Changed FormField->Field() to make use of FormField->createTag() over complicated dynamic string building
* ![rev:64596] Allow use of RestfulService->setQueryString() and test to support it. Patch from ticket #2973. Thanks to simon_w!
* ![rev:64558] Used _t() entity instead of hardcoded "not set" string in TextareaField->Field()
* ![rev:64556] Clearer indication of setting disabled attribute in DropdownField->Field() since the disabled attribute shouldn't be set if the field isn't to be disabled
* ![rev:64553] Clearer indication of setting disabled attribute in CheckboxField->Field() since the disabled attribute shouldn't be set if the field isn't to be disabled
* ![rev:64552] If TextField->disabled has been set to true, then add the "disabled" attribute to the input type text attribute list
* ![rev:64551] Made use of FormField->createTag() functionality for creating a textarea field in TextareaField->Field()
* ![rev:64494] Using ksort() in textcollector to get alphabetized language master files (=easier to compare and debug)
* ![rev:64493] Made _t() global function in Core.php an alias for the new i18n::_t() method
* ![rev:64492] Refactored i18nTextCollector and added unit tests
* ![rev:64489] Added ClassInfo::classes_for_file()
* ![rev:64447] Moving i18n->textcollector() and related methods to new class i18nTextCollector and i18nTextCollectorTask - enabling running textcollector through CLI, refactored to instance methods for better testability
* ![rev:64446] Improved TaskRunner and BuildTask metadata and styling
* ![rev:64421] Using createTag() to create HeaderField and LabelField, which adds support for HTML id attributes and extra css classes through addExtraClass()
* ![rev:64410] Made use of createTag() on FormAction->Field()
* ![rev:64408] Added ID to allow CSS styling of forgot password link on MemberLoginForm
* ![rev:64406] Added a message if no email address was specified, for user feedback purposes on MemberLoginForm->forgotPassword()
* ![rev:64405] Changed the "I've lost my password" action to a link instead, since the button is too prominent, and usability is poor having this as a form submit button.
* ![rev:64397] Versioned::get_one_by_stage() and Versioned::get_by_stage() were missing parameters from their get_one() and get() counterparts in DataObject. Those parameters have been added. See ticket #2965 for the origin of this patch.
* ![rev:64366] Pulled out Newsletter specific stuff from Member, the changes in the newsletter module were done on r64365
* ![rev:64356] Added additional known file types, for audio and video files
* ![rev:64311] Added unit tests for Silverstripe's custom static handling (with lots of commented out failing tests)
* ![rev:64306] is_array() checks in DataFormatter to respect empty arrays as a form of denying permissions on fields
* ![rev:64305] Added BankAccountField::is_valid_array_structure() to avoid PHP Notices when converting empty array values
* ![rev:64304] Added DropdownFieldTest
* ![rev:64252] Making confirmation message in ConfirmedFormAction translatable
* ![rev:64238] Showing image thumb before input field in a separate block `<div class="thumbnail">` in SimpleImageField
* ![rev:64236] Added unit tests for form session messages and session validation, FormTest->testSessionValidationMessage() and FormTest->testSessionSuccessMessage()
* ![rev:64229] Storing a "fake referer" in TestSession->lastURL to allow for redirectBack() calls, e.g. after failed form validation
* ![rev:64224] Disrecard $includeRelations setting when scaffolding $has_one relationships in FormScaffolder - use $restrictFields to limit instead
* ![rev:64223] Making URL accessible through HTTPRequest->getURL()
* ![rev:64157] Added $params parameter to all DBField->scaffoldFormField() subclasses
* ![rev:64144] Setting default level for ContentController->getMenu($level = 1) to allow for calls without arguments
* ![rev:64078] Using $locale in _t() instead of repeatedly calling i18n::get_locale()
* ![rev:64075] Replaced hardcoded "en_US" references in i18n class with $default_locale
* ![rev:64073] Supporting titles in FieldSet->findOrMakeTab()
* ![rev:64071] Added german translation for ModelAdmin
* ![rev:64067] Using i18n fieldlabels for column-headlines in TableListField
* ![rev:64041] Re-enabled RSSFeedTest - seems to work now due to Director::baseURL() fixes (#2861)
* ![rev:64012] Improved error message on invalid classname for TestRunner
* ![rev:64003] Added DataFormatter->setCustomRelations()
* ![rev:64001] Made FormTest fixtures more expressive
* ![rev:63999] Re-enabled two test cases in DataObjectSet as a result of the above fixes
* ![rev:63996] Added unit test CheckboxSetFieldTest?->testLoadDataFromObject()
* ![rev:63995] Using fixtures in CheckboxSetFieldTest?, restructured from hard-to-debug manymany-join on self to a Article`<->`Tag relation
* ![rev:63955] Pulled out Report::has_reports() which was hardcoded into LeftAndMain, and put into cms/_config.php which makes more sense
* ![rev:63763] Reformatted and documented Form->loadDataFrom() - no functionality changed
* ![rev:63762] Added unit tests for "_unchanged" handling in Form->loadDataFrom()
* ![rev:63761] Added unit tests for Form->loadDataFrom()
* ![rev:63748] Added missing "abstract" Report class to compliment ReportAdmin. Currently it is unclear what abstract base class you're supposed to implement from.
* ![rev:63681] Custom getViewer() methods to use Page main templates if CollectionController is nested in a ContentController
* ![rev:63680] Added SSViewer->getTemplateFileByType() and SSViewer->setTemplateFile()
* ![rev:63679] Added HTTPRequest::detect_method()
* ![rev:63653] Added Controller->getRequest()
* ![rev:63652] Added Controller->render($params) as a shortcut for Controller->customise($params)->renderWith(array('MyTemplate','MySubTemplate')) - templates are auto-detected by Controller->getViewer() and Controller->getAction()
* ![rev:63651] Consistently allowing for $restrictFields and $fieldClasses parameters passed to DataObject->scaffoldFormFields(), DataObject->scaffoldSearchFields(), DataObject->scaffoldCMSFields()
* ![rev:63650] Added RequestHandlingTest->testNestedBase()
* ![rev:63648] Added support for customize parameters to ViewableData->renderWith() to avoid unnecessary chaining ($this->customize($params)->renderWith($template))
* ![rev:63633] Better i18n for TableField and ComplexTableField
* ![rev:63632] Using DataObject->Title for has_one dropdowns generated in DataObject->scaffoldFormFields()
* ![rev:63630] Added DataObject->fieldLabel() and removed $fieldname parameter from DataObject->fieldLabels($fieldName) to simplify overloading of fieldLabels() for i18n
* ![rev:63628] Added FieldSet->hasTabSet() incl. unit test
* ![rev:63626] Removed overloaded MemberTableField->DetailForm() and reduced overloaded constructor logic - same behaviour found in parent classes
* ![rev:63624] Scaffolding Member->getCMSFields() to allow for easy extension
* ![rev:63623] Calling DataObjectDecorator->updateCMSFields() in DataObject->getCMSFields() - was previously only called in SiteTree instances
* ![rev:63620] Only list ID field in DataObject->summaryFields() if no summaryfields are defined (or can be autodetected). Listing all fields was not feasible, as some subclasses have more fields than fits the column layout
* ![rev:63619] Added ObjectTest->testSingletonCreation()
* ![rev:63615] Added FieldSetTest->testRemoveTab()
* ![rev:63614] Updated translations from translate.silverstripe.com
* ![rev:63613] Updated translations from translate.silverstripe.com
* ![rev:63572] Removed project-specific requirements from CMSMain
* ![rev:63569] Started using ss.i18n clientside javascript in LeftAndMain classes (only a fraction made translatable)
* ![rev:63567] Using ss.i18n in all sapphire form fields with clientside language strings
* ![rev:63566] Added javascript i18n support through Requirements::process_i18n_javascript() and ss.i18n javascript lib
* ![rev:63565] Added ViewableData->i18nLocale, used in LeftAndMain.ss to determine interface language through meta tags (see r63564)
* ![rev:63564] Added ViewableData->i18nLocale, used in LeftAndMain.ss to determine interface language through meta tags
* ![rev:63554] Checking for instanceof DataObject instead of has_one() in DataObject->update() to support virtual relations as well (fix to r63531)
* ![rev:63528] #1848 - Select the title field for new pages
* ![rev:63526] #2875: Make CLI execution more robust when FILE_TO_URL_MAPPING not set
* ![rev:63493] Added support for dot syntax to DataObject::update()
* ![rev:63470] Setting SimpleImageField->allowedExtensions to sensible defaults
* ![rev:63468] Added Form->resetField()
* ![rev:63465] Showing contact information in Debug::friendlyError() from Email::getAdminEmail()
* ![rev:63463] Added Director::get_environment_type()
* ![rev:63452] Better URL handling. Instead of "admin/showreport/something", we do "admin/report/show/something", which is more consistent with the rest of the CMS.
* ![rev:63388] Director::forceWWW() now does a 301 redirect for SEO (to be consistent with Director::forceSSL())
* ![rev:63337] Added DataObjectTest test cases for checking various field existence levels
* ![rev:63327] #2172: Added counts to comment admin submenu items
* ![rev:63321] Updated cli-script handling to be more in line with web calls, and improved Director::setBaseURL() calls.
* ![rev:63289] Tidied up DropdownField->Field() by making use of FormField->createTag() as other FormField subclasses such as TextField do
* ![rev:63249] Moved UserDefinedForm and related code, templates, CSS and javascript out of cms and sapphire classes into userforms/trunk
* ![rev:63198] Added user_error() if RebuildStaticCacheTask is called without a Page->allPagesToCache() method defined
* ![rev:63182] Added ManifestBuilder::$cache_expiry_mins
* ![rev:63181] Using HTTP Status 301 for RedirectorPage class, to be nice to search engines and improve SEO (with 200 page rank gets split between pages, with 301 its all transferred to the target page)
* ![rev:63175] Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
* ![rev:63154] Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
* ![rev:63153] Moved procedural bootstrapping code hiding away between function definitions in Core.php to main.php and cli-script.php (TEMP_FOLDER and PR_* constants)
* ![rev:63057] Updated argument handling for sake
* ![rev:63025] Better CLI output of 'sake dev'
* ![rev:63022] #2853 - Added dev/build as a the new name for db/build; prettied it up
* ![rev:62995] Prevent CMS session timing out and losing content - Added a ping to Security/ping every 5 mins, and altered the onSessionLost behaviour to open login form in a pop-up instead of closing the CMS (see #2242)
* ![rev:62994] Prevent CMS session timing out and losing content - Added Security/ping as a destination for session-preserving ajax pings
* ![rev:62894] #2700 - Added section title to CMS title tag
* ![rev:62883] ComplexTableFilters used to edit relations have their filter automatically set, as well as the foreign key on new records.
* ![rev:62867] #2417: Replaced http://www.yoursite.com with the actual base URL
* ![rev:62848] Allowing to specify dropdown title field in TypeDropdown->setTitleFieldName() - patch by nicolaas (#2689)
* ![rev:62847] Allowing usage of ID, Code-String or Object as $group parameter in Member::inGroup()
* ![rev:62844] Allowing usage of $member parameter for Member::check() as ID, Code or Object
* ![rev:62843] Added Debug::send_warnings_to()
* ![rev:62841] Using optional $member parameter for DataObject::can*() methods
* ![rev:62477] Improved ajax error display within the CMS: Using Firebug (or Firebug Lite) for plaintext output instead of cramming everything into the CMS-status field
* ![rev:62468] In Debug::showError(), if error is displayed through ajax with CliDebugView, use plaintext output
* ![rev:62467] Removed "ERROR:" prefix hack for ajax error responses - clientside evaluation should inspect HTTP status codes instead
* ![rev:62397] Adjusted ModelAdmin->import() to new BulkLoader_Result API (see r62403)
* ![rev:62267] Added DBFieldTest to test prepValueForDB()
* ![rev:61685] You can now use Controller::join_links() to add querystring arguments to a URL
* ![rev:61627] Added dev/tests/startsession and dev/tests/endsession to allow the use of fixtures with external test frameworks, such as Windmill
* ![rev:61618] wakeless - Added SQLQuery::filtersOnID()
* ![rev:61485] DropdownField now allows for `<optgroup>` elements in the field source by passing in a two dimensional array - this was taken from GroupedDropdownField
* ![rev:61420] RequiredFields->php() uses quotes around title of field, falling back to the name of the field if title isn't available
* ![rev:61415] Added LowerCase() to DBField to return the raw2xml converted value as lower case for any type of field if applicable
* ![rev:61394] Added SetHeight() to the Image class, so we can call it from the templates
* ![rev:61392] Added SetSize() to the Image class so we can use it in the templates
* ![rev:61166] Consistent styling of TypeDropdown in the CMS
* ![rev:61165] Added h3, h4 and h5 CSS styles
* ![rev:61157] Added FieldSet->removeFieldsFromTab() which does exactly what removeFieldFromTab() does, but with an array of field names
* ![rev:61154] Director::forceSSL() redirects are now 301 instead of 302 redirects, which is better for SEO
* ![rev:61153] ErrorPage:: should also list ShowInSearch as 0, since it is not required to be searched
* ![rev:61149] Added getter method for CompositeField->children
* ![rev:61147] If title not passed into TextareaField constructor, it defaults to the name value
* ![rev:60724] Removed recently added DataObject::$result_permissions and replaced with more specific TableListField::permissions_for_object()
* ![rev:60645] Added Maori to i18n::$common_languages
* ![rev:60637] Showing error level in custom error handlers on DebugView and CliDebugView
* ![rev:60635] Added default /admin/cms route to cms/_config.php to clear default namespace for other controllers
* ![rev:60395] Using Requirements instead of hardcoded template logic to include some LeftAndMain js/css
* ![rev:59286] Added `<div class=""middleColumn">` around TableListField templates and all subclasses
## Minor changes
* ![rev:71706] Make FirstName and Surname of Member table be indexed.
* ![rev:71621] Allow setting page size for MemberTableField
* ![rev:71569] some label, texture change for AHIP project SC #99
* ![rev:71345] added user friendly labels - should really be _t compatible I guess
* ![rev:71292] Fixed tab-spacing in cms/upload js files
* ![rev:71194] Fixed CSVParserTest with encoding issues
* ![rev:70960] Added basic tests for Date and DateField
* ![rev:70953] Code formatting fix in DateField
* ![rev:70895] Updated tests to check boolean values in CsvBulkLoaderTest
* ![rev:70843] Added phpDoc comments for documentation that needs to be written explaining the different source data that can be used with CheckboxSetField
* ![rev:70833] Ensure that $result is defined before calling array functions on it in SiteTree::getClassDropdown()
* ![rev:70807] Code formatting cleanup in Member
* ![rev:70799] Code formatting fix in SecurityAdmin_left.ss
* ![rev:70783] Code formatting fix
* ![rev:70769] Defensive handling of events in TreeSelectorField->hideTree
* ![rev:70761] Added important piece of information for where the callback method should be defined for duplicate checks in BulkLoader
* ![rev:70693] fixing flash insertion and removing console log messages
* ![rev:70678] Use FormResponse instead of echoing strings as JS
* ![rev:70677] Removed hard-to-debug error trap in SecurityAdmin_right.js
* ![rev:70666] merged r70665 from trunk
* ![rev:70664] removed dulicate css code
* ![rev:70663] merged r70323 from trunk
* ![rev:70662] tinymce toolbar improvements. Fixed gradient image and border issue
* ![rev:70657] #3416 MCE Editor Minor Beautification (thanks ajshort!)
* ![rev:70647] Changed $title parameter to HtmlEditorField constructor to null to be consistent with TextareaField and so title is derived based on the name of the field if no title is given.
* ![rev:70635] Patch from ajshort. changed site tree shortcut icon to transparent.
* ![rev:70608] Code formatting fix in FormField
* ![rev:70598] ticket 1846. Changed Action to title case
* ![rev:70596] ticket 1846. changed logout text to title case
* ![rev:70591] merged patch from simon_w. Fixed language in model admin
* ![rev:70587] fix for ticket 3384. Instead of messing round with added requirements back if you cannot merge them just return
* ![rev:70571] in-line documentation correction
* ![rev:70548] Added default english text for "Email" in Secrity->LostPasswordForm()
* ![rev:70540] Added default english text for "Email" and "Password" fields in MemberLoginForm
* ![rev:70530] merged patch from keeny. Put comment data into Cookie and load if user fails maths spam question. Clear comment cookie on successful posting
* ![rev:70498] Fixed incorrect parameters breaking PasswordField HTML validity because maxlength and size were being populated by non-numeric characters
* ![rev:70494] merged patch from simon_w. Removed unnesscary comments
* ![rev:70493] merged patch from simon_w. Changed can*() methods to check they are sent valid member objects rather then arrays
* ![rev:70484] merged patch from rjmackay. Fixed inclusion of BBCode filters and reported error supression
* ![rev:70483] merged patch from simon_w: added check to Children() to make sure user has canView() rights
* ![rev:70411] added empty statics for decoration
* ![rev:70409] added empty statics to allow decoration
* ![rev:70408] added empty statics to PageComment to allow for decoration
* ![rev:70400] SilverStripeNavigator toolbar is now i18n friendy
* ![rev:70360] removed Gallery Module code from AssetTableField
* ![rev:70355] CSS hover background fix. Merged from ticket #3264. Thanks gigtech
* ![rev:70269] Update ResetFormAction to make use of createTag() method instead of patching together strings to make the form input
* ![rev:70257] Fixed undefined variable error in TableListField->generateExportFileData()
* ![rev:70255] Whitespace removal at end of DataObjectDecorator class
* ![rev:70252] Update phpDoc for DataObject->getFrontEndFields()
* ![rev:70251] Renamed DataObjectDecorator->updateFormFields() to updateFrontEndFields() to be more accurate to the extended method
* ![rev:70238] Removed "Groups" field that wasn't used in Member::getCMSFields()
* ![rev:70236] Code tidy up and coding style fixes for MemberTableField
* ![rev:70188] If the error-404.html or error-500.html file can't be opened, supress the warning so an error isn't shown in the CMS
* ![rev:70154] phpDoc for Varchar->getName()
* ![rev:70153] Removed redundant code from Varchar
* ![rev:70133] Fix potential undefined variable errors in Query->column() and Query->keyedColumn() by always returning an array, even if it's empty. This now conforms to the phpDoc for these two functions, instead of returning null if there's no $column variable set
* ![rev:70132] Defined $column as an array so "undefined variable" error is supressed
* ![rev:70070] tidied up padding in headings complextablefields with long titles
* ![rev:70065] Removed redundant code in CMSMain->AddPageOptionsForm()
* ![rev:70061] Removed redundant code
* ![rev:70059] Code formatting fixes in HtmlEditorField
* ![rev:70053] Added test for HTTP::getLinksIn() which subsequently tests HTTP::findByTagAndAttribute()
* ![rev:70048] fix on-line documentation syntax so that phpDocumentor can creating automatically the API doc
* ![rev:70032] fix on-line documentation syntax so that phpDocumentor can creating automatically the API doc
* ![rev:69955] Passing context object through in LeftAndMain->getSiteTreeFor() (necessary for Translatable)
* ![rev:69939] Removed "edit image" button since the image editor has been removed
* ![rev:69890] Updated language tables
* ![rev:69889] Added Extension->getOwner()
* ![rev:69883] Fixed alignment of "Create translation" button in CMS - removed unnecessary horizontal floating and removed background
* ![rev:69871] merged r69857 from trunk
* ![rev:69865] Removed old references to check-php, which has since been removed
* ![rev:69843] Moved form session error set up from Form constructor to method so it can be used again if need be
* ![rev:69840] Added SiteTreeActionsTest
* ![rev:69839] Merged r69410 from trunk
* ![rev:69838] Merged r69409 and r69410 from trunk
* ![rev:69749] Fixed Sitetree expand and collapse icons alignment in FF3
* ![rev:69717] added support for :-) as well as :) in the Similes
* ![rev:69706] search interface design improvements
* ![rev:69686] Updated correct HTTPRequest class for @deprecated notice on HTTP::sendFileToBrowser()
* ![rev:69611] Updated cms master tables
* ![rev:69592] Added french translation (see #3290)
* ![rev:69591] Added french translation (see #3290)
* ![rev:69562] merge patch from ajshort: allow db build without running requireDefaultRecords
* ![rev:69514] fixed ModelAdmin right tab layout. Removed scrollbar off the tab strip. Ticket #2900
* ![rev:69419] Code syntax tidy up
* ![rev:69369] Removed @todo from Text->ContextSummary as it's already done
* ![rev:69368] Added phpDoc to Text->ContextSummary() $string argument
* ![rev:69348] Added todo and phpDoc to Text->ContextSummary()
* ![rev:69249] Disable caching in RestfulService test
* ![rev:69248] Removed debug message
* ![rev:69244] Added test for FieldSet->renameField() to test method behaviour
* ![rev:69226] Added tests for Text->LimitWordCountXML()
* ![rev:69225] Added phpDoc to Convert::raw2xml() and Convert::raw2js()
* ![rev:69221] Removed comment that isn't appropriate
* ![rev:69220] Added TextTest for testing Text class methods
* ![rev:69219] Updated phpDoc cautionary message on Text->LimitCharacters()
* ![rev:69218] Added documentation to various Text class methods for limiting field values
* ![rev:69206] logical bug in FormScaffolder
* ![rev:69205] translation
* ![rev:68973] reorganized layout of bbcode list elements to move longer ones to bottom row for BBCode popouts
* ![rev:68858] renamed $json to $xml in XMLDataFormatter
* ![rev:68853] added link to all Comments feed in Page Comments
* ![rev:68771] Updated language tables
* ![rev:68763] translation
* ![rev:68760] Making Folder->getCMSFields() translatable
* ![rev:68759] translation
* ![rev:68758] Making CTF save button translatable
* ![rev:68753] translation
* ![rev:68749] translation
* ![rev:68748] translation
* ![rev:68747] translation
* ![rev:68743] Translation
* ![rev:68742] Translation
* ![rev:68741] translation
* ![rev:68600] Removed debug message
* ![rev:68534] Hardcoded yoursite.com in assets treeview (see #3230)
* ![rev:68531] fixed javascript initialization bug in SecurityAdmin_left.js (see #3211)
* ![rev:68526] Hiding border around `<fieldset>`s in ModelAdmin add form (see #3214)
* ![rev:68517] fixed php notices on AssetAdmin (see #3187)
* ![rev:68457] formatting in Security.php
* ![rev:68195] Styling for input.disabled
* ![rev:68178] updated translations
* ![rev:68162] Updated language master table
* ![rev:68161] Updated language master table
* ![rev:68147] Updated cms lang master table
* ![rev:68029] Added whitespace after <!-- end include to be consistent
* ![rev:67705] formatting
* ![rev:67689] Documented ClassInfo::subclassesFor() and added unit tests
* ![rev:67682] Updated phpDoc for Requirements::customCSS() and Requirements_Backend::customCSS()
* ![rev:67676] Code formatting cleanup
* ![rev:67675] Code formatting cleanup
* ![rev:67468] Removed whitespace after ?> end PHP tag
* ![rev:67467] Removed whitespace after ?> end PHP tag
* ![rev:67424] Tidy up of Form.ss template in sapphire/templates/Includes
* ![rev:67380] Documentation in Email class
* ![rev:67327] Added test for ErrorPage
* ![rev:67301] Declared Director::direct() and Director::test() as static functions to avoid confusion
* ![rev:67300] Code formatting improvements for Director->test()
* ![rev:67295] Re-enabled calls to updateCMSFields() accidentally disabled in r67294
* ![rev:67293] Removing custom mock controller from SearchFormTest, now handled in FunctionalTest (see r67291)
* ![rev:67230] ImageEditor indentation
* ![rev:67213] Merged r66794 from trunk (related to #3192)
* ![rev:67188] fixed typo in email_template docblock and added note from sean
* ![rev:67176] Reverted r64384 and re-added Email_Template (see #3183)
* ![rev:67083] Documentation for StaticExporter
* ![rev:67075] removed debug code
* ![rev:66958] Deprecated internal property SearchForm->$numPerPage, use $pageLength instead
* ![rev:66944] merged from trunk
* ![rev:66942] merged r66670 from trunk
* ![rev:66939] Merged r66681 from trunk
* ![rev:66819] Code formatting conventions in HTTPRequest->param()
* ![rev:66803] phpDoc comments for ModelAdmin->import()
* ![rev:66800] Added code example of $model_importers array item
* ![rev:66751] Reverted replacement of jQuery.js with minified version, we're doing minification on the fly, and there's jQuery-packed.js as a readymade alternative (see r66708)
* ![rev:66748] Revered jquery/orig folder, not necessary as we have an unminified jQuery.js anyway (see r66717)
* ![rev:66747] Reverted reference to jquery-packed.js which causes problems by double minification in cms (see r66735)
* ![rev:66745] Revered accidental deletion of jQuery.js in r66719
* ![rev:66736] Formatting in Permission::checkMember()
* ![rev:66735] fixed path include for jquery
* ![rev:66700] merged r66672 from trunk
* ![rev:66643] Removed unused action "waitingon" from CMSMain::$allowed_actions
* ![rev:66642] Removed TaskList remnants of old cms workflow code
* ![rev:66640] Removed redundant code
* ![rev:66637] Code formatting of !isset($member) on SiteTree->canAddChildren() for consistency with other can*() methods
* ![rev:66636] Renamed to correct updateCMSActions() in php comment
* ![rev:66631] Removed unused private static $dataobject_select in File
* ![rev:66630] phpDoc comments for File->getAbsoluteSize()
* ![rev:66628] Code formatting cleanup on CheckboxSetField->Field()
* ![rev:66624] Added tests for checking extra class was added to DropdownField
* ![rev:66623] Added tests for checking extra class was added to FormField subclasses (TextField, EmailField and OptionsetField)
* ![rev:66615] Readd of end php tag as per coding conventions
* ![rev:66614] Added missing end php tag for ImageEditor, as per coding conventions
* ![rev:66613] Removed whitespace after end php tag for AssetTableField
* ![rev:66612] Removed commented out code that shouldn't be lying around
* ![rev:66542] actually allow youtube / blip videos to be embedded into the cms content area
* ![rev:66426] added setter function to write_js_on_body() so I can override the settings
* ![rev:66386] SecurityAdmin code formatting cleanup
* ![rev:66385] Removed old references to "rightbottom", which is now obsolete and caused a big box to appear in the CMS sometimes
* ![rev:66373] Tidied up messy template syntax in LeftAndMain.ss
* ![rev:66333] Documentation for ConfirmedPasswordField
* ![rev:66322] Documentation for SearchForm
* ![rev:66318] Coding conventions, inconsistent use of tabs and spaces
* ![rev:66317] Code conventions (spaces should be between operator characters)
* ![rev:66311] Removed old references from workflow in SiteTree and VirtualPage (AssignedToID and RequestedByID were old properites of a workflow page type)
* ![rev:66310] Removed old workflow instances in the cms module. See ticket #3044
* ![rev:66302] Added isset($_SERVER['HTTP_HOST']) checks to Director->isDev() and Director->isTest() - these environment variables are not available in CLI mode, and show up as PHP notices in a default cli-script/sake execution
* ![rev:66270] Code formatting in FormField
* ![rev:66167] Fixed class naming in LeftAndMainDecorator.php
* ![rev:66093] Removed debug code in AjaxUniqueTextField
* ![rev:66092] Fixed PHP Notice in SiteTree
* ![rev:66024] Removed debug code committed in r65554
* ![rev:65616] Removed unused code from SearchForm, commented out junk etc
* ![rev:65537] removed debug commits from r65523 in Folder.php
* ![rev:65516] Updated merge-info
* ![rev:65485] type enviroment -> environment
* ![rev:65484] Removed obsolete code from MySQLDatabase
* ![rev:65458] Removed duplicate dev/simpletest, already present in thirdparty/simpletest
* ![rev:65457] PHPDoc for FunctionalTest
* ![rev:65446] Tidied up ThumbnailStripField->getimages() formatting
* ![rev:65445] Tidied up ThumbnailStripField->getflash() formatting
* ![rev:65444] Tidied up ThumbnailStripField->getimages() formatting
* ![rev:65443] Tidied up formatting - spaces to tabs
* ![rev:65437] Changed die() to user_error() so that correct error level is returned
* ![rev:65418] Tidied up messy code formatting
* ![rev:65409] Tidied up AssetAdmin->SiteTreeAsUL()
* ![rev:65398] images for the new imageeditor which didnt get included in the patch
* ![rev:65292] JS translations in LeftAndMain
* ![rev:65233] Removed redundant code
* ![rev:65205] phpDoc of HtmlEditorField
* ![rev:65190] Improve robustness of some of the widget definition
* ![rev:65149] Moved tasks from sapphire/cli to new folder sapphire/tasks
* ![rev:65146] Fixed PHP Notices in Member.php
* ![rev:65145] Fixed PHP Notices in TreeMultiSelectField
* ![rev:65135] Check if OldPassword data exists before running checkPassword()
* ![rev:65127] Code formatting in ComplexTableField
* ![rev:65126] Code formatting in CMSMenuItem
* ![rev:65124] Formatting in Group.php
* ![rev:65095] Disabled LeftAndMainTest, now covered by CMSMenuTest
* ![rev:65075] Updated master language tables
* ![rev:65074] Updated master language tables
* ![rev:65067] formatting
* ![rev:65058] Restructured code in Object.php to consistently have properties and important methods like __call() at the top of definitions (no logic changes). Added minor documentation.
* ![rev:65052] rearranged methods in i18nTextCollector
* ![rev:65043] Collecting entities for language master table with new i18nTextCollector functionality. The table is now sorted alphabetically by namespace and entity. Entities now include more translatable statics from DataObject subclasses like $db, $has_one etc.
* ![rev:65035] Collecting entities for language master table with new i18nTextCollector functionality. The table is now sorted alphabetically by namespace and entity. Entities now include more translatable statics from DataObject subclasses like $db, $has_one etc.
* ![rev:65025] Moved i18n tests into sapphire/tests/i18n subfolder
* ![rev:65022] documentation for i18nTextCollector
* ![rev:65021] package information for ModuleManager
* ![rev:65019] Moved js unit tests from sapphire/javascript/tests to sapphire/tests/javascript to have a consistent location for all tests on server- and clientside
* ![rev:64986] Renamed variable to avoid confusion in SecurityAdmin->SiteTreeAsUL()
* ![rev:64982] Tests for r64981
* ![rev:64871] Code formatting in TextareaField->Field()
* ![rev:64850] Code formatting cleanup
* ![rev:64786] Added deprecated note to ConfirmedFormAction
* ![rev:64771] phpDoc update for ContentController->getMenu()
* ![rev:64733] Code formatting cleanup in AssetAdmin->addfolder()
* ![rev:64560] Temporarily disabled Debug::message() calls in i18nTextCollector as they're disturbing unit test output and we currently dont have context switches for this
* ![rev:64559] Adjusted i18nTextCollector to use DataObject->i18nCollectStatics()
* ![rev:64557] Unnecessary check of trim() twice on TextareaField->Field()
* ![rev:64555] whitespace removal
* ![rev:64551] Documentation tweaks in TextareaField
* ![rev:64550] Convert::raw2att() isn't required because FormField->createTag() already does this
* ![rev:64505] Added to @deprecated note for TypeDropdown about why this class shouldn't be used
* ![rev:64503] phpDoc changes in LeftAndMain - removal of @usedby which doesn't exist, replaced with @uses on the remote function
* ![rev:64502] Code formatting changes to be more consistent
* ![rev:64498] Moved CollectionController_Results template into genericviews module
* ![rev:64460] documenting my new method, correct a coding convention about whitespace
* ![rev:64442] moved RestfulServerTest from cms to sapphire module, same as the actual RestfulServer class
* ![rev:64441] moved RestfulServerTest from cms to sapphire module, same as the actual RestfulServer class
* ![rev:64429] deprecation notes
* ![rev:64419] Misc deprecation notes
* ![rev:64418] Changed visibility of SiteTree->getClassDropdown()
* ![rev:64415] documentation
* ![rev:64414] Removed unused DatabaseAdmin->makeURL()
* ![rev:64413] documentation
* ![rev:64412] Marked some Convert methods as deprecated, as their purpose is unclear, they're neither documented nor tested. Stuff like Convert::xml2js() is just way too fuzzy
* ![rev:64411] phpDoc comment error fix
* ![rev:64409] Changed visibility of Convert::recursiveXMLToArray
* ![rev:64406] Tidied up code formatting for MemberLoginForm->forgotPassword() to be clearer
* ![rev:64404] Security->LostPasswordForm() code formatting changes for clarity
* ![rev:64403] Moved Controller::init() to top of file
* ![rev:64400] Misc deprecation notes
* ![rev:64397] phpDoc for Versioned::get_by_stage() to be consistent with Versioned::get_one_by_stage()
* ![rev:64396] Removed deprecated method addmember() from CMSMain - this should be contained on SecurityAdmin instead
* ![rev:64395] Removed commented out code in CMSMain->PageTypes()
* ![rev:64385] Misc deprecation fixes
* ![rev:64382] Misc deprecation notices
* ![rev:64369] Removed Group_Unsecure which was never used
* ![rev:64364] Removed Director::addRules() item for Unsubscribe_Controller that should will be done by the Newsletter _config.php file instead
* ![rev:64362] Fixed FileTest for changes to getFileType() on the File class
* ![rev:64356] Tweaked text of file type descriptions slightly
* ![rev:64344] Whitespace changes in TextField
* ![rev:64338] delete some unnecessary duplicated variable in a assignment statement.
* ![rev:64322] Removed useless comment and commented out code that went along with it in Group class
* ![rev:64319] fixed php notice error in DataObject
* ![rev:64312] Todos for ObjectTest
* ![rev:64301] Added mergeinfo
* ![rev:64300] Added mergeinfo
* ![rev:64261] Moved HTTPRequest constructor to beginning of method definitions
* ![rev:64079] Documentation in i18n class
* ![rev:64068] Removed CollectionController language strings from master table
* ![rev:64020] Removed subtree mergeinfo
* ![rev:64014] Formatting
* ![rev:64009] Swapped $mainFields and $fields assignments in Member->getCMSFields() to reflect what they're actually containing
* ![rev:64008] Syntax fix in CliTestReporter which was causing wrong array indices
* ![rev:64006] Fixed PHP notice in CLITestReporter
* ![rev:63985] Documentation
* ![rev:63982] Removed unnecessary $this->extend() on SSReport->getCMSFields()
* ![rev:63961] Updated inconsistent documentation on SSReport
* ![rev:63959] Updated SSReport class documentation to make sense
* ![rev:63958] Documentation and @package phpDoc code additions to ReportAdmin and SSReport
* ![rev:63937] Reformatting
* ![rev:63898] Add warning for deprecated function.
* ![rev:63897] Change memory limit to -1 on publishall to stop sapphire running out of memory on unit tests.
* ![rev:63873] Updated entities from translate.silverstripe.com
* ![rev:63869] Updated entities from translate.silverstripe.com
* ![rev:63864] Updated language master table
* ![rev:63861] Updated language master table
* ![rev:63856] Reverted manual setting of i18n fallback strings in r63839, fixed original problem (wrong entity name)
* ![rev:63840] Renamed Report to SSReport as it was conflicting with project code
* ![rev:63822] Fix to SiteTreeTest's data fixtures
* ![rev:63815] Tidied up argument list for Object::create() in ComplexTableField->AddForm()
* ![rev:63802] Fixed JS undefined errors with 'addgroup' and 'deletegroup' elements
* ![rev:63801] Fixed JS undefined error with 'Loading' element
* ![rev:63790] Line break between static variables on SecurityAdmin
* ![rev:63766] removed subtree mergeinfo on ModelAdmin_Results.ss in preparation for client branch merge
* ![rev:63760] Documentation for Form class
* ![rev:63753] Code formatting cleanup
* ![rev:63752] Very minor whitespace change
* ![rev:63747] Removed PageTypes directory from cms which is not used anymore
* ![rev:63680] Documentation and formatting in SSViewer and Controller
* ![rev:63657] Documentation for HTTPRequest and RequestHandlingData
* ![rev:63655] Documentation for HTTPRequest and RequestHandlingData
* ![rev:63632] Removed scaffolded header field in DataObject->scaffoldFormFields()
* ![rev:63617] Documentation
* ![rev:63616] Documentation
* ![rev:63608] fixed formatting on no images found
* ![rev:63568] Documentation
* ![rev:63531] Documentation in DataObject
* ![rev:63530] Reverted my email address with something more spambot safe from r63489 ;)
* ![rev:63492] removed `< and >` characters from @author phpdoc token
* ![rev:63491] phpdoc tweaks
* ![rev:63490] phpdoc tweaks
* ![rev:63489] Filled in Ingo's email for phpdoc since he failed to do it himself
* ![rev:63469] Formatting in Member
* ![rev:63468] Documentation for Form
* ![rev:63466] Documentation in ErrorPage
* ![rev:63459] Code formatting inconsistency
* ![rev:63458] Added TODOs for areas of code that needs some work, either in documentation or code cleanup.
* ![rev:63456] Committed missing files related to r63452
* ![rev:63453] Fixed wrong position of return array() in ReportAdmin->showWithEditForm()
* ![rev:63452] Documentation and TODO for ReportAdmin methods
* ![rev:63449] Fix undefined variable error in ManifestBuilder::get_manifest_info()
* ![rev:63420] Code formatting changes for readability and consistency in DropdownField->Field()
* ![rev:63390] Ticket #2869 Fixed PHP notice in Director::forceWWW()
* ![rev:63388] Fix PHP notice in checking $_SERVER['HTTPS']
* ![rev:63385] Fixed PHP notices in ListboxField->Field() by defining the variables first
* ![rev:63370] documentation
* ![rev:63355] allow tinymce to suck down script code at least in tinymce
* ![rev:63339] todos for DataObjectTest
* ![rev:63293] Documentation
* ![rev:63180] Added externals for thirdparty JSON library
* ![rev:63179] Moved JSON library to thirdparty externals
* ![rev:63178] Reverted accidental commit to main.php from r63177
* ![rev:63174] Documentation for image uploads
* ![rev:63156] Reverted accidental disabling of ManifestBuilderTest cleanup code
* ![rev:63155] Temporarily disabled RSSFeedTest as its overriding environment variables that should be handled by Director class with Director::setBaseURL() (which is currently not fully working). Added stub-tests for Director.
* ![rev:63127] Fix phpdoc parsing error
* ![rev:63125] Fix phpdoc parsing error
* ![rev:63124] Fix phpdoc parsing error
* ![rev:63123] Fix phpdoc parsing error
* ![rev:63122] Fix phpdoc parsing error
* ![rev:63121] Fix phpdoc parsing error
* ![rev:63081] Added CMS->SiteTreeAsUL() to $allowed_actions (#2733)
* ![rev:63080] Removed stale version number from `<meta name="generator">` tag (#1908)
* ![rev:62877] Added some more api doku for DataObject::
* ![rev:62845] Added documentation and TODOs for RestfulServer
* ![rev:62843] Documentation and formatting for Debug class
* ![rev:62842] Documentation
* ![rev:62841] Added documentation to DataObject about permission handling
* ![rev:62484] Changed console.log() to console.error() in ajax error handling
* ![rev:62470] documentation
* ![rev:62462] documentation
* ![rev:62461] documentation
* ![rev:62424] FileField->Field() code formatting changes
* ![rev:62313] HTMLVarchar->scaffoldFormField() was referencing a class name of different case that didn't exist (change it to the correct one to be sure)
* ![rev:61840] fixed comment on MathSpamProtection
* ![rev:61826] #2696 - Add message when trying to load the CMS with javascript
* ![rev:61825] Fixed PHP notice
* ![rev:61702] Remove commented out code
* ![rev:61484] added @deprecated note in PHPdoc to show that Email_Template is deprecated
* ![rev:61483] phpdoc of @package and @subpackage to reflect the actual package and subpackage
* ![rev:61482] comment changes to allow better readability of comments of what we're testing
* ![rev:61481] Additions to FieldSetTest to test removeByName() and removeFieldsFromTab()
* ![rev:61217] setRelationAutoSetting function adding
* ![rev:61164] Fixed PHP notice in CheckboxSetField when transforming to readonly
* ![rev:61161] PHPdoc for FieldSet->replaceField()
* ![rev:61160] PHP notice fix for FileIFrameField->Field()
* ![rev:60949] Added FieldSetTest to the test library
* ![rev:60409] Re-activated tabstrip.js in LeftAndMain (merge error?)
* ![rev:60408] Renamed jquery_improvement.js to plural form (consistent with prototype_improvements.js)
* ![rev:60407] Re-enabled DataObjectDecoratorTest
* ![rev:60406] Moved sapphire/misc* to sapphire/thirdparty and sapphire/integration
* ![rev:60401] Moved ScaffoldComplexTableField to separate file
* ![rev:60400] Removed DataObject->mapRelationshipObjects() - incomplete functionality
* ![rev:60398] Removed sapphire/tools
* ![rev:60371] Documentation
* ![rev:60370] Removed debug code from Member.php
* ![rev:60367] removed obsolete code from DataObject.php
* ![rev:60217] syntax error
* ![rev:60216] syntax error
* ![rev:60210] Documentation
* ![rev:60157] Fix php notice
* ![rev:59518] Fixed crazy messed up indentation in TableField
* ![rev:59279] wording for "IP Range" description
## Other
* ![rev:71921] Undo the change committed in r71918 since the commit message is missing
* ![rev:71758] Improved DataObject validation tests to use PHPUnit's setExpectedException stuff.
* ![rev:71755] Disable xdebug in the test runner, because it has a habit of causing bus errors
* ![rev:71170] BUGIX: CMS UI search spinner style tweak
* ![rev:71169] BUGIX: CMS UI changed search spinner, hide search button while processing (better interaction feedback)
* ![rev:71035] Include the media widget into the CMS
* ![rev:71034] Removed media plugin code that got copied into ssbuttons
* ![rev:70995] Disable basicauth in RestfulServiceTest
* ![rev:70900] BUGIFX tweak to navigator layout and tidying up unnecessary styles
* ![rev:70894] BUGIFX tweak to navigator layout
* ![rev:70860] Made selection of custom security templates easier
* ![rev:70845] Don't let content negotiator clobber the mime types of things other than HTML & XHTML
* ![rev:70844] Replaced HTTPReponse settings of Content-type header with Content-Type, to match RestfulServer
* ![rev:70747] 2. make Email_BounceRecord::canCreate() return false; so that it can not be manully create from CRM, instead, it should create through email buncing system.
* ![rev:70740] Undoing change committed in r 70734
* ![rev:70738] Undoing change committed in r 70734
* ![rev:70725] 2. Not all DataObject has a 'Title' database field, but all DataObject has a 'Title' field due to function DataObject::getTitle() exists.
* ![rev:70702] Merged patch submitted by ajshort that calls loadDataForm on a newly created object in ModelAdmin so that properties of the object are loaded properly
* ![rev:70372] fixed ajax button alignment
* ![rev:70303] cms ui: site tree tools visual update
* ![rev:70240] cms ui: fixed line background to drop down from root node
* ![rev:70239] cms ui: fixed line background for open nested lists
* ![rev:70237] cms ui fix: styles for uniform site tree line
* ![rev:70235] cms ui fix: make site tree hierarchy line uniformly dotted
* ![rev:70206] cms ui fix: adding separator above allow drag and drop
* ![rev:70143] IE6 ui fixe for search filter date input width
* ![rev:70141] IE6 ui fixes for calendar in search filters (positioning and when sidebar is expanded)
* ![rev:70136] ui fixes for calendar in search filters (positioning and when sidebar is expanded)
* ![rev:70127]
* ![rev:70091] stopped null properties being added when images inserted in cms (hspace, vspace, align)
* ![rev:70090] Added missing Decimal->nullValue method.
* ![rev:69983] Removed unnecessary db query in CMS tree generation
* ![rev:69982] Pre-cache page version numbers when querying CMS tree for query efficiency
* ![rev:69981] Added Versioned::prepopulate_versionnumber_cache() to allow for querying efficiencies
* ![rev:69977] Added cache to Permission::checkMember() to reduce the number of queries
* ![rev:69933] Reverted change because it wasn't necessary
* ![rev:69925] EHANCEMENT #3326 hamish: Added Image::getOrientation()
* ![rev:69815] Added getter to retrieve alternative database name.
* ![rev:69731] Better error messages when HasManyComplexTableField can't configure itself properly.
* ![rev:69681] See #3275
* ![rev:69382] Fixed label of back button
* ![rev:69350] Simplified implementation of FieldSet::makeReadonlyField()
* ![rev:69349] Simplified implementation of FieldSet::makeReadonlyField()
* ![rev:69052] Fixed URL in the list of tasks.
* ![rev:68945] Fixed loading of CMS toolbar with the HtmlEditorField
* ![rev:68873] Improved rendering of [php] tags in BBCode view
* ![rev:68700] Made CalendarDataField JS more self-suffficient
* ![rev:68598] Added SearchForm::classesToSearch() to set the classes that you want it to search. Still limited to SiteTree and File but you can exclude one of those.
* ![rev:68474] Merged r67482 to branches/2.3 - let db/build add auto_increment
* ![rev:68326] Added ability for comment authors to leave a URL as a separate form field
* ![rev:67877] PaginationSummary return all pages by default
* ![rev:67793] Added PaginationSummary function that enable DataObjectSet to display a portion of page list
* ![rev:67776] Added headers_sent() check to header() call in main.php to stop it from being so brittle.
* ![rev:67583] Restore requirements after sending email
* ![rev:67432] Improved graphs displayed on dev/viewmodel
* ![rev:67427] Added diagrams to dev/viewmodel
* ![rev:67414] Added simple model viewer at dev/viewmodel
* ![rev:67401] - including greybox.js had caused the screen to become unscrollable because of an (unrelated) inclusion of LeftAndMain.js which sets `<body>` to overflow:hidden on javascript page load
* ![rev:67194] Merged r67152 from trunk
* ![rev:67169] Add TableListField::setFieldList()
* ![rev:67165] Added ModelAdmin:: for changing the class used to generate results tables
* ![rev:67131] Moved LegacyIDs from BlogEntry and File to Decorators
* ![rev:67114] Added LegacyID for keeping orginal ID. Used for site migration
* ![rev:66941] Fixed SiteTreePermissionsTest login failure tests
* ![rev:66923] #1885: Fixed safari bold, italic, underline by removing HTML scrubbing.
* ![rev:66889] Better checking of tabstrip stuff
* ![rev:66834] Removed call-time pass by reference from CsvBulkLoader
* ![rev:66824] Removed unnecessary updateCMSFields call; DataObject::getCMSFields does this for us
* ![rev:66719] getting things tidied up
* ![rev:66717] trying to get jquery to stick
* ![rev:66712] packed jquery
* ![rev:66708] packed jquery and jquery ui
* ![rev:66645] DataObject::relObject() throws an exception rather than an error so that it can be caught
* ![rev:66639] Set default level for HeaderField
* ![rev:66634] Added white background for tabs in all places; not just the right frame
* ![rev:66626] Allow passing of columns to ColumnSelectionField() and allow different ColumnSelectionField() values to influence the result columsn
* ![rev:66582] Added support to DataObject::relObject() for looking at $casting to get information about the relation - good for dynamic relations
* ![rev:66546] Fix incorrect logic in r66544
* ![rev:66544] Make sure only fields that exist can be autocompleted on MemberTableFields, and never autocomplete on password.
* ![rev:66431]
* ![rev:66394] 1. Add note to each record in 1-many relation. Add the tab "Notes" for showing/editing/deleting notes of a record.
* ![rev:66356] Merged pre-2.3-oct08 into 2.3 (via trunk)
* ![rev:66353] Merge pre-2.3-oct08 into 2.3 (via trunk)
* ![rev:66350] Fix to LeftAndMain to ensure that jquery doesn't break other admin sections
* ![rev:66304] Fixed bug in test makefile
* ![rev:66296] Build database before testing, for RestfulService test, etc
* ![rev:66267] Return an HTTPResponse consistently from controllers
* ![rev:66265] Fixed RequirementsTest
* ![rev:66225] #2771: Fix SQLQuery::filtersOnID() (wakeless)
* ![rev:66192] #2635 - More informative errors in DataObject (simon_w)
* ![rev:66103] FIX: permission migrator for missing groups
* ![rev:66086] Merged pre-2.3-oct08 into branches/2.3 (via trunk)
* ![rev:66084] Merged pre-2.3-oct08 into branches/2.3 (via trunk)
* ![rev:66008] Boundary condition check for top-level pages with 'inherit' permission
* ![rev:65981] Update sapphire so that it can run with the default .htaccess and mysite/_config.php files provided in the phpinstaller. If database config is missing, then redirect to install.php
* ![rev:65971] Include tabstrip js and css for modeladmin
* ![rev:65970] Fixed WYSIWYG styling
* ![rev:65967] Added validation for DataObject::db, has_one, has_many, many_many, belongs_many_many properties, so that improper use of the array syntax doesn't raise strange bugs elsewhere.
* ![rev:65959] #3068 - Fixed memory issue in IE
* ![rev:65939] Replace source view with one based on codepress
* ![rev:65938] Added advcode tinymce plugin that is a wrapper around codepress
* ![rev:65915] Set default view/edit permissions
* ![rev:65913] Added light blue colouring to notinmenu items
* ![rev:65912] Added notinmenu class to CMS tree items that aren't in menus
* ![rev:65861] Fixed dropdown-based ModelAdmin navigation
* ![rev:65859] Fixed root node not displaying correctly
* ![rev:65828] Removed console debug messages for ThumbnailStripField
* ![rev:65824] Merged in image search capabilities from trunk version - r65820, r65823
* ![rev:65802] Fixes for IE support of script tags being down the bottom
* ![rev:65789] #2991 - Fixed change detection in mce fields
* ![rev:65783] Fixed fatal error in CommentTableField:
* ![rev:65782] New test for old URL redirection
* ![rev:65781] #2679: Auto-redirect renamed pages
* ![rev:65778] Get sapphire to self-allocate at least 64M of memory, if possible.
* ![rev:65735] Fixed media-type selection on demand in IE
* ![rev:65718] Added livequery to leftandmain install
* ![rev:65717] Refactored tabstrip.js to use livequery for loading
* ![rev:65716] Refactored tabstrip.js to use livequery for loading
* ![rev:65709] Removed time limit when minifying files and disabled processing of multiple files if on dev.
* ![rev:65673] Change back to english on teardown
* ![rev:65530] No execution time limit on test runner
* ![rev:65529] Replaced 300-second 'long execution' times with unlimited
* ![rev:65524] Merged branches/2.2
* ![rev:65523] Merged from branches/2.2
* ![rev:65507] Ensure that Requirements backend instance is preserved between tests
* ![rev:65506] Reformatted memory usage to be more concise
* ![rev:65503] #2997 - Added `<% require %>` tag to SSViewer
* ![rev:65471] Added default for HTTP_USER_AGENT
* ![rev:65465] Cleaned up the commented-code
* ![rev:65438] Bugfixes to Requirements alterations
* ![rev:65436] ARCHITECTURE #3034 wakeless: Make Requirements mockable by pushing the meat of the functionality to Requirements_Backend
* ![rev:65407] Removed redundant code
* ![rev:65397] Removed redundant code
* ![rev:65385] dquote> API CHANGE: Simplified Core.php manifest include to just call ManifestBuilder::include_manifest() - manifest takes care of its own cache file
* ![rev:65332] IMPROVEMENT Fix tab display and button position when adding a record (ticket #3029)
* ![rev:65289] IMPROVEMENT moved managed models' forms to one panel (ticket #2898)
* ![rev:65287] #2135 - Disallow XSS bug in development RestfulService use
* ![rev:65252] Added deprecation method for LeftAndMain::add_menu_item()
* ![rev:65229] API CAHNGE: Allow augmentPopulateDefaults on data object decorators
* ![rev:65189] Added spellchecker to CMS
* ![rev:65175] Reverted previous change, as MemberTableField has it's own use of sourceFilter - not the most documentation situation however.
* ![rev:65173]
* ![rev:65150] Note: Use dev/tasks/UpgradeSiteTreePermissionSchemaTask/run to migrate legacy data to the new schema as outlined above
* ![rev:65140] Simplified CliTestReporter output so that buildbot can read it
* ![rev:64952] Text scaffolds to a TextareaField, not a TextField
* ![rev:64947] #2975 - Malformed javascript language string (ajshort)
* ![rev:64896] In general all Form Fields should imply with this rule if a page contain mulitiple forms, but this is not under our current developing cycle, since our form fields validation is changing to use jQuery.
* ![rev:64880] Deleted SmallerThanFilter - please use LessThanFilter
* ![rev:64863] Changed default # of rows on HTMLEditorField from 15 to 30
* ![rev:64862] Fixed TinyMCE stylihg
* ![rev:64839] Fixed CMS uploading
* ![rev:64814] call $this->extend('updateFieldLabels', $labels) in FieldLabels() to get its decorator's customized field labels
* ![rev:64778] Removed scrubbing of the HTML
* ![rev:64768] #2957 - Fixed entity decoding in Convert::html2raw
* ![rev:64760] Fixed bug in tinymce_ssbuttons plugin inclusion
* ![rev:64759] Added LinkText field to link inserter
* ![rev:64684] Removed sapphire/images/fe_icons - these will be put in the userforms module instead, where the FieldEditor
* ![rev:64470] Removed junk text from CSSContentParserTest
* ![rev:64368] HTTP:add_cache_headers() - don't throw warning when not passed
* ![rev:64345] dquote> API CHANGE: HTTP::add_cache_headers() now designed to manipulate an HTTPResponse object rather than add headers directly
* ![rev:64343] Removed TextField_Disabled - this is unnecessary
* ![rev:64340] Included jquery.js before prototype.
* ![rev:64339] Implemented a jQuery based version of documents.getElementsBySelector
* ![rev:64326] API: add CurrencyField_Readonly
* ![rev:64325] API: add funcion TableField_Item::IsAddRow()
* ![rev:64324] Feature: attach extraClasses to a FormField when it is transform to readonly
* ![rev:64323] API: add TextField_Disabled
* ![rev:64152] Removed #! entry from cli-script.php; its unreliable and cli-script.php should be called as 'php cli-script.php' instead
* ![rev:64070] ENHANCMENT Making ModelAdmin translatable (#2874)
* ![rev:63938] Improved backtrace generation in test reporter, to limit the amount of unnecessary waffle.
* ![rev:63912] BGFIX: #2587 Fix HTTPS detection on IIS (mackeyn)
* ![rev:63904] BGFIX: #2527 - Fix mysql version detection on hosts with custom mysql version names (HakTom)
* ![rev:63892] Added PHP doc for the ValidationException thrown by DataObject::write
* ![rev:63891] DataObject::write now throws a ValidationException rather than calling user_error if the call to DataObject::validate fails. This allows the validation exception to be caught and handled by tests or other controllers.
* ![rev:63883] Added missing TableListField_printable.ss template.
* ![rev:63882] Corrected reverted merge. ComplexTableField::setPopupSize is now present.
* ![rev:63843] Removed legacy Report.php
* ![rev:63842] BUGF Renamed Report class to SSReport, file name wasn't altered but class name was
* ![rev:63837] Updated Member's getCMSFields() to consistently work with fields in a tab
* ![rev:63821] Moved error_reporting setting from main.php to Core.php
* ![rev:63820] Removed relational CTFs reliance on DataObject->ClassName
* ![rev:63807] Merged from branches/nzct-trunk. Use 'svn log -c `<changeset>` -g' for full commit message. Merge includes stability fixes and minor refactor of TableListField and ComplexTableField.
* ![rev:63806] Merged from branches/nzct-trunk. Use 'svn log -c `<changeset>` -g' for full commit message. Merge includes stability fixes and minor refactor of TableListField and ComplexTableField.
* ![rev:63748]
* ![rev:63745] Updated Member::isInGroup() to function as well as being deprecated
* ![rev:63733] Added get data to a form submission of SearchForm/search, so that ResultAssembly is passed
* ![rev:63715] Updated errorMessage() call in ModelAdmin to actually show the message to the user. For example, 404s return messages of the form 'your search returned no results'
* ![rev:63636] Added instructions to try and prevent #2901 issues reoccurring
* ![rev:63625] ENHANCMENT Using errorMessage() instead of statusMessage('bad') for ModelAdmin.js
* ![rev:63594] Fixed FormField::createTag() generation for empty `<select>` tag, which meant that page version history was displayed in single-language mode
* ![rev:63583] Updated file functions to use HTTPRequest::send_file
* ![rev:63582] Added tests for security group export
* ![rev:63580] Break sake dev/tests/all status dots onto lines of 80
* ![rev:63552] Updated BankAccountField to allow setting it to blank without a notice-level error
* ![rev:63548] #2397 - Fixed HTMLEditorField style dropdown
* ![rev:63546] Added groups field on member details, so that you can add members to other group
* ![rev:63545] Added dev/modules/remove and cleaned up rebuilding code on add and remove module
* ![rev:63537] Fixed dumb error in my makeRelative change
* ![rev:63535] Added security for experimental module manager
* ![rev:63534] Added initial module manager API, with the capability of adding a module to svn:externals
* ![rev:63532] Secured SapphireInfo
* ![rev:63531] ENHANCMENT Checking for valid has_one relationship on dot-notation-usage in DataObject->update
* ![rev:63506] Don't claim that there's an invalid password if no password is set - members may be created for newsletters, etc.
* ![rev:63488] fixed fix position of action area (status message and ajax action buttons) in IE6 using javascript
* ![rev:63452]
* ![rev:63431] Fixed bug in cli-script argument parsing
* ![rev:63389] Reverted r63388
* ![rev:63388]
* ![rev:63383] removed debug::show
* ![rev:63382] - commented out this.style.position = "absolute"; in LeftAndMain.js
* ![rev:63251] Reverted en_US.php changes from r63249
* ![rev:63113] Turned dos line endings into unix
* ![rev:63078] Link Editor: Close button dissapears in Firefox 3 (#2478)
* ![rev:63020] EHANCEMENT #2853 - You can now use db/build instead of db/build?flush=1
* ![rev:62998] Fixed bug with ComplexTableField inappropriately referencing a relation field that doesn't exist
* ![rev:62912] Added status notifications to cli test runs
* ![rev:62866] Corrected layout of field groups
* ![rev:62865] Replaced alert()s in UniqueFields.js with statusMessage()s, to be less obnoxious
* ![rev:62756] Fixed bug publishing homepage using Director::test
* ![rev:62692] Added CountryDropdownField::defaultToVisitorCountry(false):
* ![rev:62689] Removed save button from add form
* ![rev:62654] Update test runner so that password validation config isn't tested by default
* ![rev:62653] This results in more reliable log-in redirection
* ![rev:62648] Fixed bug with preivous CheckboxSetField change
* ![rev:62641] Fixed loadDataFrom for CheckboxSetFields that are used to edit a many-many relation, if loadBlanks is set to true
* ![rev:62599] comment Debug.traceback that occur when the field is a tab
* ![rev:62386] Added empty string as a default (first item)
* ![rev:62335] Improved ModelAdmin.js - removed formData and showRecord, creating .fn('loadForm') instead; used livequery more to reduce the amount of behaviour reapplication that was necesary.
* ![rev:62334] Updated ModelAdmin's javascript to provide more status indicator (loading icons, success/failure messages), using HTTP status codes and custom status text.
* ![rev:62331] Fixed ConfirmedPasswordField validation for min password length
* ![rev:62325]
* ![rev:62324]
* ![rev:62322] Merged branches/roa into trunk
* ![rev:62321] Merged branches/roa into trunk
* ![rev:62318] Add another test for addFieldToTab when creating tabs
* ![rev:62312] SearchContext generates SELECT DISTINCT query rather than SELECT, so that duplicate records aren't shown as a result of certain search filters
* ![rev:62311] MemberTableField delete just removes the member from the group
* ![rev:62310] Fixed MemberTableField ajax actions after a search
* ![rev:62295] Allow MetaTags to be extended by a decorator.
* ![rev:62287] Introduce notion of using HTTP status text to pass status message to the end user
* ![rev:62278] Reorganised ModelAdmin javascript to be better structured
* ![rev:62268] Fixed bugs with #1403 changes made in r62218.
* ![rev:62267]
* ![rev:62213] Made allowed_actions case insensitive
* ![rev:62188] Null values fixed for PHP 5.3
* ![rev:62184] Multiple 'protected' variable declaration fixed
* ![rev:61826] disabled (simon_w)
* ![rev:61721] Show result-assembly columns so that you read down the column instead of zigzagging
* ![rev:61720] Removed Created from member summary fields
* ![rev:61714] adding ?flush=all option which clears all cached templates from the LOLCACHE
* ![rev:61698] Updated CSV bulk loader to import unix/windows files on a mac server
* ![rev:61685] TESTS: Added tests for Controller::join_links()
* ![rev:61634] Windmill test - whacked up timeout on CMS load for slow build slave
* ![rev:61631] Fixed setup of windmill admin tests
* ![rev:61630] Disabled across-the-board use of windmill tests in continuous integration; instead a specific build is set up for it
* ![rev:61629] Included windmill testing in the continous integration again
* ![rev:61628] Fixed glitch in test
* ![rev:61626] Updated windmill tests to use python syntax, as this will scale better
* ![rev:61614] Fixed bugs in MemberTableField search
* ![rev:61613] Fixed bug in TableListField::ajax_refresh
* ![rev:61578] added a call to magic method to check extra (crm) permission
* ![rev:61525] Added EPMU's process control sake
* ![rev:61523] add Created as summary_fields
* ![rev:61511] The searchCriteria will be added as $_GET to the form action, rather than that TableListField's extraLinkParams
* ![rev:61509] getSummaryFields() will also get those summary fields defined in Member's decorator applied to the results and export
* ![rev:61497] Reverted r61492
* ![rev:61462] Improved File tests
* ![rev:61461] Fixed coverage reporting on test runner
* ![rev:61411] Fixed saving of TableField and added tests
* ![rev:61410] Better error message if you have forgotten to set fixture_file
* ![rev:61370] Undeprecated a critical feature of TableField, and reimplemented in the Group's permission field. Cleaned up its implementation to be more in line with TableListField
* ![rev:61351] Fixed display of Permission dropdown in SecurityAdmin
* ![rev:61344] Fixed bug with manifest generation
* ![rev:61184] Merged branches/kiwiselect into trunk
* ![rev:61155] field, changed to "MenuTitle" to be consistent with the main CMS site tree and to avoid confusion
* ![rev:61152] Work to decouple the ManifestBuilder from the database, so that you can run manifest builder tests without an active database existing
* ![rev:61151] introduce double scrolling and thus poor usability
* ![rev:61136] Fixed bug with CsvBulkLoader
* ![rev:61135] uncommmented processRecord that process each record because it was mistakenly commented previously
* ![rev:61123] $resultsCount now gets int value from loader directly instead of DataObjectSet
* ![rev:61122] change the return type of processAll of CsvBulkLoader from DataObjectSet to int, the number of affected row
* ![rev:61120] modified csv import function documention. It returns number of affected records.
* ![rev:61067] Made some methods on SearchFilter public so that SearchFilters can be co-opted for other purposes. Really, moving the magic to a DataQuery object would be better
* ![rev:61066] Fixed action handlers on fields of ResultsForm (notably the TableListField) by adding querystring arguments to the Link() of the form.
* ![rev:61065] Fixed bug in TableListField sort links
* ![rev:61064] Fix FormField::Link() to allow querystrings in the form's action
* ![rev:61063] Turn off default caching
* ![rev:61056] Added back button to ModelAdmin detail views
* ![rev:60937] Removed double quoute from the from fields as it means field terminator
* ![rev:60913] Updated AssetTableField to work with ComplexTableField updates
* ![rev:60912] Fixed bug in Member::mapInCMSGroups()
* ![rev:60911] Reverted Folder::CanEdit() to its original behaviour; that of returning a many-many join. Note that this conflicts with DataObject::CanEdit() now.
* ![rev:60910] Added ComplexTableField::getCustomFieldsFor() that you can overload in subclasses of ComplexTableField to create alternative pop-up forms
* ![rev:60909] Added table references to many-many join used by scaffolder, to remove 'ambiguous column' bugs
* ![rev:60907] replaced `<br />` with newline for CSV export
* ![rev:60886] Removed memory limit for publication
* ![rev:60885] Added warnings for parts of Member that require the newsletter module. Note that this code should really be moved to the newsletter module at some stage.
* ![rev:60874] Made all sapphire/thirdparty classes _manifest_exclude'd
* ![rev:60873] Renamed illegal function that was hiding in Time.php
* ![rev:60870] Removed time-limit for publication process
* ![rev:60841] Fixed page comment system for new URL handler
* ![rev:60830] Fixed saving of blank values to the has_one relations on versioned objects
* ![rev:60829] Fixed HasManyComplexTableField and ManyManyComplexTableField in trunk
* ![rev:60789] Fixed layout of CMS RHS panel to suit new form HTML structure
* ![rev:60779] Fixed bugs with Image upload fields
* ![rev:60778] Trap potential data-integrity bug
* ![rev:60717] Ensure that a theme template is tried before getting a non-theme template
* ![rev:60711] Added logging of SSViewer and Controller behaviour when using ?debug_request=1
* ![rev:60664] Added tests for CheckboxSetField
* ![rev:60612] Removed notice level error when ArrayLib::valuekey() is passed an empty array
* ![rev:60608] Correct line numbers in error source fragment view
* ![rev:60607] Ensure that MySQLDatabase::tableList() always returns an array
* ![rev:60606] Fix error in Geoip when REMOTE_ADDR isn't set
* ![rev:60605] Include full traces in unit test failures, for easier debugging
* ![rev:60604] Removed unnecessary chatter from test runner
* ![rev:60603] Improved db/build output for CLI
* ![rev:60602] Removed junk output from stderr
* ![rev:60601] Added Debug::get_rendered_backtrace() for rendering backtraces from other contexts (such as exceptions)
* ![rev:60597] Improved performance of testrunner so that it doesn't create a new database for each test, instead only once per test run.
* ![rev:60592] Removed warning when session_regenerate_id can't be set. It's not strictly necessary and just causes testing headaches
* ![rev:60586] Passed controller argument to ChangedPasswordForm constructor
* ![rev:60582] Fixed MemberAuthenticator::authenticationFailedUnknownUser code
* ![rev:60581] Improve CLI use of Debugging tools and test execution.
* ![rev:60579] Removed code that used 2nd arg as HTTP_HOST value, in favour of more robust $_FILE_TO_URL_MAPPING
* ![rev:60578] Add checks to see if REMOTE_ADDR is set before making use of it.
* ![rev:60577] Improvements to better allow for CLI-based testing
* ![rev:60575] Ensure that IP-based security can't be bypassed if an IP address isn't set.
* ![rev:60572] Improved DataObjectTest to use more helpful assertions
* ![rev:60571] Blocked [rev:47113].
* ![rev:60570] Merged [rev:47110]: Hack fix for an email validation problem. Needs better solution.
* ![rev:60569] Blocked [rev:47109].
* ![rev:60568] Merged [rev:47108]: Ajax requests no longer trigger the audit trail hook in LeftAndMain::init.
* ![rev:60567] Merged [rev:47107]: Added audit logging hook.
* ![rev:60563] Fixed bug in Requirements::clear()
* ![rev:60561] Blocked [rev:47106].
* ![rev:60560] Merged [rev:47105]: Fixed a typo.
* ![rev:60558] Blocked [rev:47104].
* ![rev:60557] Merged [rev:47103]: MemberTableField.js now uses named sheets.
* ![rev:60556] Merged [rev:47102]: Optimization for Behaviour sheets that allows you to provide a unique identifier so that duplicate sheets aren't applied twice.
* ![rev:60555] Changed Debug::loadErrorHandlers to use value returned by error_reporting() rather than E_ALL. This way, the user can adjust the error handler screens with the error_reporting function.
* ![rev:60548] Merged [rev:47101]: Adds class=action to action cells in MemberTableField.
* ![rev:60546] Merged [rev:47094]: Fixes Session IP addresses in reverse order.
* ![rev:60544] Blocked [rev:47093].
* ![rev:60543] Refactored [rev:47092]: Add TableListField::getCastedValue
* ![rev:60536] Merged [rev:47091]: Added Round and NiceRound to Float.
* ![rev:60529] Refactored [rev:47088]: File::getFullPath now compares the filename with Director::baseFolder and returns filename if the filename stars with Director::baseFolder.
* ![rev:60526] Blocked [rev:47084]: Needs refactoring for new Sapphire code which provides similar functionality.
* ![rev:60522] Refactored [rev:47082]: Modified Member::mapInCMSGroups to make use of CMSMain::providePermissions.
* ![rev:60515] Merged [rev:47081]: Modified construction of manifest to allow custom definition of MANIFEST_FILE constant filename in _config.php.
* ![rev:60514] Merged [rev:47080]: Fix for pagination when using customSourceItems in TableListField.
* ![rev:60512] Merged [rev:47079]: Fix for template logic.
* ![rev:60511] Refactored [rev:47078]: AccessLogEntry will be created via an object extension.
* ![rev:60510] Blocked [rev:47074] to [rev:47077].
* ![rev:60509] Merged [rev:47074]: Added register and unregister as aliases to Authenticator.
* ![rev:60508] Merged [rev:47073]: Fix for pagination in TableListField::sourceItems.
* ![rev:60507] Blocked [rev:47072]: Changeset needs to be refactored so Session logging isn't strictly required.
* ![rev:60506] Merged [rev:47071]: Added Session::get_timeout.
* ![rev:60505] Blocked [rev:47070].
* ![rev:60504] Merged [rev:47069]: Replaced explicit calls to AccessLogEntry::create with more flexible calls to extensions. AccessLogEntry to be refactored into separate module.
* ![rev:60498] Refactored [rev:47068]: Member::logOut now calls memberLoggedOut on any extensions on Member.
* ![rev:60491] Blocked [rev:47065] to [rev:47067].
* ![rev:60490] Merged [rev:47064]: Set 'show' as the default action for ComplexTableField.
* ![rev:60488] Blocked [rev:47062].
* ![rev:60487] Merged [rev:47061].
* ![rev:60486] Merged [rev:47060].
* ![rev:60485] Merged [rev:47059]: Session expiry times can now be set based on the client's IP address.
* ![rev:60481] Blocked [rev:47057] to [rev:47058].
* ![rev:60480] Merged [rev:47056]: Adds unique identifier when creating Behaviour rule sheets to prevent duplicate behaviours from being applied repeatedly.
* ![rev:60479] Merged [rev:47055]: Modified FormResponse to append Behaviour rules last.
* ![rev:60478] Blocked [rev:47047] to [rev:47054].
* ![rev:60477] Merged [rev:47046]: Minor optimisation to BankAccountField and added methods to get specific parts of the account number.
* ![rev:60474] Reverted accidental change
* ![rev:60473] Included regression test
* ![rev:60470] Ability to lock down comments to logged-in members only
* ![rev:60469] Merged [rev:47044]: Introduces modifications to Sapphire's form handling that allows it to ignore fields marked as Disabled when saving the contents of a form's fields to a DataObject.
* ![rev:60468] Merged changes from 2.2.2-assets - everything except the asset refactoring
* ![rev:60448] Allow object-methods to be used as columns in TableListField
* ![rev:60446] Fixed js error when defaultAction isn't set
* ![rev:60442] Reverted Hierarchy::extraDBFields() because it interfered with normal generation of the site hierarchy. Note that children(), stageChildren(), and liveChildren() cannot be simply labelled as relations because they are methods with a different semantic meaning. I recommend the use of something similar to to enable access to information beyond relations via the data formatters
* ![rev:60440] Refactored [rev:47041] to [rev:47043]: Moved to project-specific PhoneNumberField.
* ![rev:60437] Refactored [rev:47040]: Functionality moved to project-specific Member subclass.
* ![rev:60433] Merged [rev:47039]: Introduces custom actions to TableListField and ComplexTableField. By default, the show, edit and delete actions are included.
* ![rev:60431] API Change: Turned Requirements::clear_combined_files() into Requirements::delete_combined_files() and Requirements::clear_combined_files()
* ![rev:60428] Fix test runner to show errors as well as assertion failures
* ![rev:60427] Updated SecurityTest to use new FunctionalTest system consistently
* ![rev:60426] Added FunctionalTest->autoFollowRedirection, so that redirection following can be disabled on a test by test basis
* ![rev:60425] Improved error checking in TestSession
* ![rev:60411] Fixed call to badly named static method
* ![rev:60394] Update SecurityTest to use the FunctionalTest base-class
* ![rev:60391] Improved robustness of MemberTest
* ![rev:60390] Improved Debug::backtrace() output
* ![rev:60385] Blocked [rev:47034] to [rev:47038].
* ![rev:60383] Merged [rev:47033]: TableListField::performReadonlyTransformation now sets show permission.
* ![rev:60377] Added argument checking to Controller::handleRequest()
* ![rev:60375] Set [REQUEST_URI] in cli-script for better error reporting
* ![rev:60362] Fixed URL handling for /dev after merge from branches/roa to trunk
* ![rev:60355] Fixed sake to pass cli-script error levels through
* ![rev:60354] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60353] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60352] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60348] Blocked [rev:47098] to [rev:47100].
* ![rev:60347] Blocked [rev:47020] to [rev:47026].
* ![rev:60346] Blocked [rev:47012] to [rev:47014].
* ![rev:60345] Blocked [rev:47006].
* ![rev:60343] Blocked [rev:46198].
* ![rev:60342] Blocked [rev:46193].
* ![rev:60341] Blocked [rev:47029].
* ![rev:60340] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60339] Blocked [rev:47027].
* ![rev:60338] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60336] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60335] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60334] Blocked [rev:46974] to [rev:47005].
* ![rev:60333] Blocked [rev:46960] to [rev:46972].
* ![rev:60332] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60331] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60330] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60329] Blocked [rev:46953] to [rev:46958].
* ![rev:60328] Blocked [rev:46951].
* ![rev:60327] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60326] Blocked [rev:46262] to [rev:46288].
* ![rev:60324] Blocked [rev:46261].
* ![rev:60323] Committing missing mergeinfo for [rev:47028] for ManifestBuilder and ComplexTableField.ss
* ![rev:60322] Blocked [rev:46192] and [rev:46197]
* ![rev:60321] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60320] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60319] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60314] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60311] Merged [rev:47028]: Encountered a problem with Form::formHtmlContent not always including javascript validation, so added a call to includeJavascriptValidation on the validator in Form::formHtmlContent. Also modified Validator to notify the form that the client-side validation JavaScript has already been included. This way it isn't included twice.
* ![rev:60307] Merged [rev:47019]: Actual merge in [rev:60309]
* ![rev:60303] Committing merge info for [rev:60309]: Merge was performed manually.
* ![rev:60302] Merged [rev:47018]: Some additions made to use Object::create to allow MemberTableField to deal with subclasses of Member. Also merged a modification to MemberTableField::__construct that allowed greater control over the details form's fields (defaults to same behaviour as trunk), and MemberTableField::DetailForm, although this might need to be removed later.
* ![rev:60290] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60289] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60287] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60281] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60279] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60278] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:60276] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60268] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60266] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60265] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60264] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60261] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60259] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60258] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60257] Merged [rev:47017]: Modified behaviour for MemberTableField popups so that the behaviour is applied if the Security section uses a subclass of MemberTableField rather than an instance of MemberTableField.
* ![rev:60256] Committing missing svn:mergeinfo for [rev:46973].
* ![rev:60255] Merged [rev:47016]: Used Object::create to allow SecurityAdmin to use subclasses of MemberTableField to list members.
* ![rev:60236] removed duplicate RestfulServerTest files, they're already in /cms (merge error)
* ![rev:60235] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60234] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60233] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60232] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60231] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60230] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60229] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60228] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60227] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60226] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60225] (manually merged from branches/roa)
* ![rev:60215] blocked r54568
* ![rev:60214] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60212] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60211] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60209] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60208] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60207] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60206] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60205] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60204] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60203] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:60179] Merged [rev:47015]: Moved call to DataObject::write and makes use of DataObject::destroy.
* ![rev:60178] Improved behaviour of ViewableData_Iterator. It's not clear why, but this was causing a bug on our build slave. Maybe a PHP version difference?
* ![rev:60175] Merged [rev:47011]: Additional CSS for GenericDataAdmin.
* ![rev:60173] Merged [rev:47010]: Modified GenericDataAdmin::buildResultFieldValue to accept relations of the form: obj1.obj2...objN->MethodCall, similar to TableListField_Item.
* ![rev:60169] Merged [rev:47009]: Calls bind using Prototype Event.
* ![rev:60168] Merged [rev:47008]: Disables the create button while creating a new entry with GenericDataAdmin.
* ![rev:60167] Merged [rev:47007]: Fix to prevent GenericDataAdmin setting a status on a new record and thus overwritting a data field named 'Status'. Includes a fix for onclick on Ajax buttons if event is not passed.
* ![rev:60162] Merged [rev:46973]: Notes a correction that will need to be made in the future.
* ![rev:60137] Blocked [rev:46952]
* ![rev:60123] Merged [rev:46959]: Summary values calculated on server are shown in the summary row when displaying a ComplexTableField.
* ![rev:60108] Merged [rev:46289]: Committing the missing meta-data for sapphire.
* ![rev:59969] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:59927] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:59925] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:59923] (blocked bidirectional merge from trunk into branches/roa)
* ![rev:59922] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:59920] (merged from branches/roa. use "svn log -c `<changeset>` -g `<module-svn-path>`" for detailed commit message)
* ![rev:59897] r52080, r52101, r52102 (merged from branches/roa)
* ![rev:59890] r52079 (merged from branches/roa)
* ![rev:59876] Merged [rev:46959]: ComplexTableField.ss now includes server-generated values in summary row cells.
* ![rev:59875] Merged [rev:46289]: Spaces in SCRIPT_FILENAME are now replaced with underscores.

View File

@ -0,0 +1,68 @@
# 2.3.1 (2009-03-19)
## New Features
* ![rev:72804] #3659 - Update key to show what purple means (ezero)
* ![rev:72791] #3614 - Allow spell checking in HTMLEditorField when used outside of the CMS
* ![rev:72788] #3612 - Option to auto-login with basic auth (jshipman)
* ![rev:72771] added ability to disable AJAX commenting
* ![rev:72763] #3610 - Require ADMIN permissions for ?flush=all
* ![rev:72517] Allow access to the live site via RESTful api
* ![rev:73435] more robust conditional check before we go to foreach loop, more robust conditional checking before we call a FormField function where we are not sure the caller is a FormField object.
* ![rev:73285] Added Director::is_relative_url() and Director::is_site_url()
* ![rev:73149] Allow calling methods on DataObjects using RESTful API. Methods which can be called must be specified in the $allowed_actions array of the DataObject.
* ![rev:72574] Made JS i18n optional; disable it by calling Requirements::set_js_i18n(false)
* ![rev:72497] Database will fix itself if you view the site and the database doesn't exist
* ![rev:72496] Added BASE_SCRIPT_URL that lets you run a site without rewriting rules
* ![rev:72346] Added onBeforeSecurityLogin event handler to Security/login, for extensions to plug into
* ![rev:72229] Fixed invalid RSSFeed format - added `<atom:link>` and `<dc:creator>` elements, removed `<author>` element (invalid unless it contains an email address)
* ![rev:72119] #3232 lenix: Added Date::FormatI18N()
## Bugfixes
* ![rev:73437] Fixed possible SQL injection in file name part for File::find()
* ![rev:73318] Added missing action 'DeleteImageForm' to Image::$allowed_actions
* ![rev:73304] Added missing action 'EditImageForm' to Image::$allowed_actions
* ![rev:73301] Fixed too strict permission checking on Image::$allowed_actions. Replaced broken * permission check with explicit method names
* ![rev:73299] Fixed array to string conversion caused by patch commited in r73285
* ![rev:73291] Using $allowed_actions in Image_Uploader (Merged from r73255)
* ![rev:73290] Validating $_FILES in Upload->validate() (Merged from r73254)
* ![rev:73289] Existence check for Member autologin token (Merged from r73253)
* ![rev:73288] Checking for Director::is_site_url() before redirecting in Controller->redirectBack() and MemberLoginForm (Merged from r73252)
* ![rev:73286] Added isDev() and Permission::check() directives to DatabaseAdmin and DevelopmentAdmin (Merged from r73251)
* ![rev:73285] Validating $_FILES array in Director::direct()
* ![rev:73284] Using $allowed_actions in ImageEditor (Merged from r73248)
* ![rev:73261] Interpret 401s and 403s created init() methods as 'finished' requests
* ![rev:73117] Fixed ajax-response for multiple-item deletion
* ![rev:73099] Fix notice-level error in rewriteless operation of homepage when db needs to be created
* ![rev:73084] #3715: Show the changes message in a popup instead of a blank confirm box
* ![rev:73082] #3716: Added error trapping to WYSIWYG side forms
* ![rev:73080] #3714: Added default value to modeladmin search button
* ![rev:73016] redirect user down to their posted comment if it was not posted via AJAX
* ![rev:72926] #3591: Make Controller::isAjax() more reliable
* ![rev:72854] #3529 - SilverStripeNavigator causes strict XHTML pages to fail in Firefox (michaek)
* ![rev:72852] #3596 - Creating more than one new folder causes infinite loop (hamish)
* ![rev:72819] Only use target="_blank" for files by default
* ![rev:72816] #3645 - CommenterURL missing from CMS
* ![rev:72798] #1450 - Passwords should be obscured when adding a member in a MemberTableField
* ![rev:72760] Make sure "Template to install" retains its value when rechecking requirements
* ![rev:72694] #3590: Allow subclassing of Folder
* ![rev:72693] #3590: Allow subclassing of Folder
* ![rev:72564] Include i18n where necessary. 2nd part of r72563
* ![rev:72563] Updated i18n javascript system so that the i18n javascript needs to be explicitly included, so that it doesn't poke its nose in where it's not wanted.
* ![rev:72557] #3418: Remove jQuery coupling from Email field focus, and only include email focus when validation is enabled
* ![rev:72457] #3644 - _ss_environment.php search creates open_basedir error (ed)
* ![rev:72341] Ensure that $this->class is set on ArrayData objects
* ![rev:72338] Allow SilverStripe to work when asp_tags is on
* ![rev:72252] Memory usage improvements to CsvBulkLoader and Member::onBeforeWrite()
* ![rev:72201] fixed syntax fail in silverstripe navigator
* ![rev:72200] Prevent infinite redirection when the homepage isn't available, when using modules such as subsites.
* ![rev:72190] escaped filename before querying with it - #ajoneil
* ![rev:73283] Using auto-escaped get_by_id() in CommentAdmin and SecurityAdmin (Merged from r73247)
* ![rev:73395] Disallow access of cli-script.php through a browser
* ![rev:72602] restored image panel showing 3 across (#3670)
* ![rev:72254] Fix tabs not being correct size when first loaded
## Other
* ![rev:73285] (Merged from r73250)

View File

@ -0,0 +1,36 @@
# 2.3.10 (2010-12-21)
## Overview
* Security: XSS in controller handling for missing actions
* Security: SQL injection with Translatable extension enabled
* Security: Version number information disclosure
* Security: Weak entropy in tokens for CSRF protection, autologin, "forgot password" emails and password salts
* Security: HTTP referer leakage on Security/changepassword
* Security: CSRF protection bypassed when handling form action requests through controller
* Improved security of PHPSESSID and byPassStaticCache cookies (setting them to 'httpOnly')
## Upgrading Notes
See [2.4.4](2.4.4)
## Changelogs
### Features and Enhancements
* [rev:114501] Added !RandomGenerator for more secure CSRF tokens etc. (from r114497) (from r114499)
### Bugfixes
* [rev:115200] Removing form actions from in !AssetAdmin, CMSMain, !LeftAndMain - handled through Form->httpSubmission() (merged from r115185)
* [rev:115191] Checking for existence of !FormAction in Form->httpSubmission() to avoid bypassing $allowed_actions definitions in controllers containing this form
* [rev:115191] Checking for $allowed_actions in Form class, through Form->httpSubmission() (from r115182)
* [rev:114776] Disallow web access to sapphire/silverstripe_version to avoid information leakage (from r114773)
* [rev:114772] Disallow web access to cms/silverstripe_version to avoid information leakage (from r114770)
* [rev:114763] Avoid potential referer leaking in Security->changepassword() form by storing Member->!AutoLoginHash in session instead of 'h' GET parameter (from r114758)
* [rev:114741] Fixed CSRF warning in image form after selecting a folder. (from r80237)
* [rev:114517] Escaping $locale values in Translatable->augmentSQL() in addition to the i18n::validate_locale() input validation (from r114515) (from r114516)
* [rev:114513] Limiting usage of mcrypt_create_iv() in !RandomGenerator->generateEntropy() to *nix platforms to avoid fatal errors (specically in IIS) (from r114510) (from r114512)
* [rev:114509] Using !RandomGenerator class in Member->logIn(), Member->autoLogin() and Member->generateAutologinHash() for better randomization of tokens. Increased VARCHAR length of '!RememberLoginToken' and '!AutoLoginHash' fields to 1024 characters to support longer token strings. (from r114504) (from r114507)
* [rev:114502] Using !RandomGenerator class in !SecurityToken->generate() for more random tokens (from r114500)
* [rev:114266] Removing quotes from test data in !RestfulServiceTest, it gives different results depending on magic_quotes_gpc setting on PHP configuration (merged from r80132).

View File

@ -0,0 +1,11 @@
# 2.3.11 (2011-02-02)
## Overview
* Bugfix: CMSMain->rollback() fails because of CSRF protection
## Changelog
### Bugfixes
* [rev:115919] #6291 Remove rollback action from CMSMain allowed_actions and rely on form action_rollback instead which is safer

540
docs/en/changelogs/2.3.2.md Normal file
View File

@ -0,0 +1,540 @@
# 2.3.2 (2009-06-18)
## Upgrading
### Feature Changes
#### CMS image alignment changes
Image alignment elements have been changed slightly. There are no longer any `<DIV>` elements created with the images
using the insert image toolbar in the CMS.
All of these selectors in your typography.css are affected:
* div.image.left
* div.image.right
* div.image.leftAlone
* div.image.center
They need to be changed to the following (respectively):
* img.left
* img.right
* img.leftAlone
* img.center
Here's an example of how the default Blackcandy theme was changed:
[http://open.silverstripe.org/changeset/75917/themes/blackcandy/branches/2.3/blackcandy/css/typography.css](http://open.silverstripe.org/changeset/75917/themes/blackcandy/branches/2.3/blackcandy/css/typography.css)
#### Translatable Datamodel
The datamodel for the Translatable extension was changed from multiple language tables to multiple rows for each
translated record in the original table. We've also introduced the concept of "Translation groups", which means not
every translated record has to exist in a "master language". Please review our updated documentation on how to [enable Translatable](/topics/translation).
If you are upgrading an existing database with existing translations, you'll need to run our [Migration Script](/topics/translation#migrating_from_2.1_datamodel) before using the
database.
For in-depth discussion of the schema changes and translation groups, please refer to our developer mailinglist:
[1](http://groups.google.com/group/silverstripe-dev/browse_thread/thread/91e26e1f78d3c1b4/bd276dd5bbc56283?lnk=gst&q=translatable#bd276dd5bbc56283)
and
[2](http://groups.google.com/group/silverstripe-dev/browse_thread/thread/575001296360a1cc/e3268963c6d8cef7?lnk=gst&q=translatable#e3268963c6d8cef7).
#### Translatable property selection
It is no longer possible to exclude certain properties on a DataObject from being translatable. This is a limitation by
our database schema choice. See
[discussion](http://groups.google.com/group/silverstripe-dev/browse_thread/thread/2b3df26361d17119/be8f9f08a797bd43?lnk=gst&q=translatable#be8f9f08a797bd43)
on our mailinglist and ticket [#3722](http://open.silverstripe.com/ticket/3722).
#### Translatable URLs
Every page is now forced to have a unique URL, different languages can't be switched by appending a `?lang=xx`
property any longer. Languages don't have to be set in sessions or cookies, as every request is able to determine the
language for the remaining site by inspecting the URL. Unique URLs are enforced because of SEO concerns, problematic
caching on proxies, browser and framework-level, as well as difficult debugging with session states. See
[discussion](http://groups.google.com/group/silverstripe-dev/browse_thread/thread/17908f7318decfac/0c2b2e2a07ea6955?lnk=gst&q=translatable+url#0c2b2e2a07ea6955)
on our mailinglist.
### API Changes
#### Important, but simple, ModelAdmin change
The configuration statics for ModelAdmin have been changed from protected to public, so that `Object::get_static()`
can access them. In particular the following static variables have been changed.
* `ModelAdmin::$managed_models`
* `ModelAdmin::$collection_controller_class`
* `ModelAdmin::$record_controller_class`
* `ModelAdmin::$model_importers`
* `ModelAdmin::$page_length`
Because of this, you will need to change the static definitions in your ModelAdmin subclasses. For example, you should
change this:
:::php
class MyCatalogAdmin extends ModelAdmin {
protected static $managed_models = array(
'Product',
'Category'
);
...
}
To this:
:::php
class MyCatalogAdmin extends ModelAdmin {
public static $managed_models = array(
'Product',
'Category'
);
...
}
#### Deprecated Translatable::enable()
* Use ''Object::add_extension('SiteTree','Translatable'')'' instead of `Translatable::enable()`
* Use ''Object::remove_extension('SiteTree','Translatable'')'' instead of `Translatable::disable()`
* Use ''Object::has_extension('SiteTree','Translatable'')'' instead of `Translatable::is_enabled()`
#### Deprecated Translatable "lang" methods
## 2.3.2-rc4
### Bugfixes
* ![rev:79278] Fixed TranslatableTest->testSavePageInCMS(), needed admin login to edit ViewersGroups field (Merged via: r79282)
* ![rev:79269] Excluding Access fields on SiteTree from Translatable->updateCMSFields(), as their original values break the javascript logic for showing/hiding the fields (Merged via: r79282)
* ![rev:79266] Passing locale through to TreeSelectorField ajax calls (Merged via: r79282)
* ![rev:79240] Marking new TreeMultiSelectField_Readonly with $readonly flag, otherwise breaks CMS saving with Translable enabled etc. (see #4240)
## 2.3.2-rc3
### Enhancement
* ![rev:78919] DevelopmentAdmin: Changed dev/build to produce nicer formatting when running from sake/dev/build CLI
* ![rev:78618] Add HTMLText#FirstSentence based on new HTMLText#Summary
### API Change
* ![rev:78632] Added increase_memory_limit_to() for increasing but not decreasing memory limit.
* ![rev:78618] Added two arguments to HTMLText#Summary. Minimal impact since previously any usage of this function threw an error.
### Bugfixes
* ![rev:79208] Don't remove translation groups in Translatable->onBeforeDelete() if the decorated record uses Versioned, as other representations of the record might still exist in other tables (e.g. SiteTree_Live) (see #4219) (Merged via: r79211)
* ![rev:79194] Writing Locale in Translatable->onBeforeWrite() regardless of the record ID existing (see #4232). This is more in line with Translatable->requireDefaultRecords() which automatically updates all NULL locale values anyway. (Merged via: r79195)
* ![rev:78920] DevelopmentAdmin: Don't allow dev/reset to be run from CLI, as this could be accidentally run - give a message that the user should run this from their web browser instead
* ![rev:78732] #4119: Fixed encoding of readonly TextareaFields and unicode in TextareaFields.
* ![rev:78729] Fixed Translatable->requireDefaultRecords() for non-SiteTree objects (was assuming Versioned to be present) (Merged via: r79195)
* ![rev:78728] A couple of bugfixes on HTMLText#Summary and HTMLText#FirstSentence so the trickiest tests pass
* ![rev:78618] Replace HTMLText#Summary with one that works.
* ![rev:78542] Don't allow the use of get-var ?isDev=1 when security DB isn't available.
* ![rev:78496] WidgetAreaEditor shouldn't ever call editable segment "NoWidgets" - this is just a placeholder
* ![rev:78471] Fixed readonly version of TreeMultiselectField
* ![rev:78470] Get backtrace rather than crazy context stuff shown in dev error messages
* ![rev:78469] Fix readonly versions of grant fields.
* ![rev:78452] fixed spelling of spam protector
* ![rev:78352] modified convertDataObjectWithoutHeader to handle empty relationships.
* ![rev:78256] Removing operating system limitations for Flash Player checks which determine showing/hiding of upload button (which currently requires exactly FP9 in our version of SWFUpload). See #3679 and #3023 for followup tickets.
* ![rev:78155] Changing from unset record entry to an empty value shouldn't register as a 'level 2' change
* ![rev:78118] Using language dropdown to determine locale for partial tree ajax loads, because we can't rely on a page with a hidden "Locale" field being loaded in the CMS. Fixed bug with wrong spelling of "locale" argument. (see #3995). (Merged via: r78119)
* ![rev:76517] Closing `<link type="alternate">` tags for XHTML compliance on Translatable->MetaTags(). Use ContentNegotiator to transform them back to HTML markup. See #3989 (Merged via: r78167)
## 2.3.2-rc2 Changelog
### API Change
* ![rev:77658] Added DataDifferencer, for comparing DataObjects. Note that it won't be used by the core features until 2.3.3, but is made available here for the cmsworkflow module.
* ![rev:77385] Removed @deprecated 2.3 JS function ingize() from LeftAndMain.js: Please use ss.i18n instead
### Bugfixes
* ![rev:77937] fixed is_array error in TableListField. #4123
* ![rev:77849] Fixed bugs in previous change to DOD
* ![rev:77822] Fix edge-case bug with application of decorators
* ![rev:77766] #4133 Fixed case where ComplexTableField failed to detect a has_many relation from the parent
* ![rev:77737] fixed #4119 by using htmlentities rather then Convert functions
* ![rev:77733] #4113: Fixed bugs with template processing in i18nTextCollectorTask.
* ![rev:77727] #4119 netminds: Fix error page publication for lang to locate replacement.
* ![rev:77726] a redirection with an external link that has more than one query string variables. Do not convert the link to html entities
* ![rev:77662] #2328: Show backtrace for uncaught exceptions (merged from r70444)
* ![rev:77596] fixed clearing issue with IE7
* ![rev:77553] Removed spurious console.log() functions (merged from r77552)
* ![rev:77528] missing unmoderated action in CommentAdmin.php
* ![rev:77461] Ensure that when a page is deleted from stage or live, its descendants are also deleted.
### Minor changes
* ![rev:78083] Reverted r78055, it breaks TableListFieldTest and doesn't actually fix the bug it was supposed to (PHP segfaulting)
* ![rev:78082] Merged from trunk
* ![rev:78081] Merged from trunk
* ![rev:77992] Merged from trunk
* ![rev:77766] Updated tests for ComplexTableField
* ![rev:77595] fixed layout for SelectionGroup file
* ![rev:77554] mergeinfo
* ![rev:77384] Removed cases where GhostPage was being unset from the tests
* ![rev:77381] Removed unused ReportField_Controller URL rule from cms/_config.php
## 2.3.2-rc1 (changes since 2.3.2-beta1)
### API Change
* ![rev:77006] Deprecated Translatable::set_reading_lang(), use Translatable::set_current_locale().
* ![rev:76853] Deprecated Translatable::current_lang(), use Translatable::get_current_locale() (Merged via: r76855)
* ![rev:76839] Deprecated Translatable->getTranslatedLangs(), use getTranslatedLocales()
* ![rev:76723] Added SiteTree::doDeleteFromLive()
* ![rev:76666] Made batch actions pluggable through CMSBatchActionHandler::register()
* ![rev:76207] When there are script tags in the body, put requirements script just before them, instead of at the very top of the body. Since this reduces the cost of the (sometimes necessary) script tags in the body, the notice-level error has been removed.
### Bugfixes
* ![rev:77282] WidgetAreaEditor gets it's related WidgetArea using getComponent(), a more robust way of getting the component
* ![rev:77259] Fixed Debug::friendlyError() to use Translatable::get_current_locale() instead of deprecated Translatable::current_lang()
* ![rev:77256] Fixed undefined variable $langAvail in Translatable
* ![rev:77242] Added a missing default english string to ADDITEM translatable entity in TableField.ss
* ![rev:77140] If CTF doesn't have a parent class (set to false), avoid breakages in ComplexTableField::getFieldsFor()
* ![rev:77111] #4082 - Translatable CMS fields layout broken in IE6
* ![rev:77031] Add JavaScript for HtmlEditorField on every CMS page, to avoid issue where loading form with HtmlEditorField via ajax doesn't work because scripts are stripped out.
* ![rev:77016] TableListField items couldn't be deleted because TableListField_ItemRequest::__construct() didn't call parent::__construct()
* ![rev:76955] Make requirements combiner work with jQuery
* ![rev:76949] #4038 If attempting to set a default locale that doesn't exist, throw a warning in Translatable::set_default_locale()
* ![rev:76948] Fixed case where SiteTree->getCMSFields() is missing a parent page, and thus it results in a non-object
* ![rev:76930] Fixed potential non-object error in LeftAndMain::callPageMethod()
* ![rev:76913] Fixed missing tinymce_template bug in ReportAdmin
* ![rev:76896] Fixed ErrorPage not showing up properly due to a SQL query that was merged from trunk not compatible with 2.3
* ![rev:76890] #4058 Requirements::process_combined_files() fixed small typo in the output
* ![rev:76881] #4068 - Fixed spelling mistake in en_US.php
* ![rev:76875] Fix javascript error in IE caused by Changeset 76845 where reloading a page would trigger a resetChanged before the tinyMCE instance existed
* ![rev:76872] Using Translatable::set_default_lang() for the deprecated i18n::set_default_lang() - this should trigger lang->locale convertion, and fix issues with running a 2.2->2.3 database schema migration (see #4009) (Merged via: r76873)
* ![rev:76870] Fixed CMSMain->LangSelector() default language selection (Merged via: r76871)
* ![rev:76866] Added translation groups for existing entries the first time Translatable is switched on through Translatable->requireDefaultRecords() (see #4051) (Merged via: r76867)
* ![rev:76852] Fix issue with 'clear' button on CMS SiteTree search
* ![rev:76841] Fixed tab layout for add form of model admin (Merged via: r77326)
* ![rev:76765] typo by legacy: ViewersGroup -> ViewerGroups, EditorsGroup -> EditorGroups
* ![rev:76731] Removed obsolete CMSMain->EditingLang(), not used any longer (see #3997) (Merged via: r76733)
* ![rev:76730] Fixed selected image hilighting, when inserting images into WYSIWYG, on IE
* ![rev:76729] Fixed WidgetAreaEditor javascript in IE
* ![rev:76726] Don't show the upload tab on readonly folders.
* ![rev:76702] Made TableListField::export() more memory efficient for large exports.
* ![rev:76655] Limit "show deleted pages" in CMS tree to current language (see #3994) (Merged via: r76656)
* ![rev:76650] Made SideTabs and SideReports work with Translatable by explicitly passing a "locale" GET parameter (see #4014) (Merged via: r76653)
* ![rev:76613] Fixed "Translations" tab display in CMS - no more duplication of original language and translated tab - see #4020 (Merged via: r76614)
* ![rev:76611] Creating a translation of a new page in a new language fails - fixed by adding locale to /createtranslation ajax call (see #4021) (Merged via: r76612)
* ![rev:76608] Fix getsubtree command in CMS tree to work with Translatable (#3995) (Merged via: r76609)
* ![rev:76603] Return NULL in Versioned::get_latest_version() if no record was found (fixes #4015) (Merged via: r76605)
* ![rev:76508] Escaped SiteTree.ID in LinkTracking selection so that show deleted pages would work.
* ![rev:76457] fixed escaping of code in textarea fields
* ![rev:76435] fixed treedropdownfield cropping long names off
* ![rev:76374] Ensure that the return object of File::find() is an instance of Image in HtmlEditorField_readonly::HtmlEditorField_dataValue_processImage()
* ![rev:76268] Fix modeladmin scrollbars in ie7
* ![rev:76258] Fixed scenarios where the page is readonly and the expected ParentType elements don't exist causing a JS error (Merged via: r76260)
* ![rev:76172] Fixed calls to uninherited() that returned no static in some cases, replacing with faster Object::get_static() calls (Merged via: r76205)
* ![rev:75027] Fixed Locale duplication detection for queries in Translatable->augmentSQL() (Merged via: r76593)
* ![rev:70325] Altering parent getCMSFields() results in RedirectorPage instead of starting with an empty FieldSet, as this discards any tabs and fields which are not explicitly mentioned in the implementation like the ability to create a translation. (Merged via: r76515)
* ![rev:70306] Don't require a record to be written (through exists()) when checking Translatable->isTranslation() or Translatable->hasTranslation()
### Enhancement
* ![rev:77266] Added databse name to output of dev/build (merged from r77265)
* ![rev:77265] Added databse name to output of dev/build (Merged via: r77266)
* ![rev:77264] Added option for putting integers into SS_DATABASE_CHOOSE_NAME in _ss_environment.php, so that a parent/grandparent folder name can be used as the database name (merged from r77261).
* ![rev:77261] Added option for putting integers into SS_DATABASE_CHOOSE_NAME in _ss_environment.php, so that a parent/grandparent folder name can be used as the database name. (Merged via: r77264)
* ![rev:76944] Significant speed up for SiteTree Filter
* ![rev:76847] Add SSMacron plugin for inserting macron characters
* ![rev:76845] Use new HtmlEditorConfig API to specify options for CMS HtmlEditorField
* ![rev:76840] Using standard LanguageDropdownField in CMSMain->LangSelector() (Merged via: r76843)
* ![rev:76839] Added $instance parameter to LanguageDropdownField to call instance-specific canTranslate() on it (optionally) (Merged via: r76842)
* ![rev:76779] Correct issue with SiteTree filtering not persisting and add drop down for page type and clear button. Part of a re-work of the search system
* ![rev:76666] Added batch actions for unpublish and delete from published.
* ![rev:76594] Improved TranslatableTest->testCreateTranslationTranslatesUntranslatedParents() to translate two grandchildren - this used to be an issue in branches/2.3 (see #4016) (Merged via: r76597)
* ![rev:70306] Adding link back to original page in CMS editform for translations
### Other
* ![rev:77326] Merged from trunk
* ![rev:77071] the sort
* ![rev:77051] Fix a PHP segfault
* ![rev:76942] API: Allow specifying any callback to setMarkingFunction, not just a function name.
* ![rev:76844] API: Move the TinyMCE configuration from a javascript file to a php system, to allow for site specific and section specific html editor options.
* ![rev:76779] @todo: Tests, speed optimisation, proper connection of filtering with tree control checkboxes
* ![rev:76260] Merged from trunk
* ![rev:76205] Merged from trunk
* ![rev:71917] NOTFORMERGE: Added custom batch actions and a 'show generic/customised' checkbox to the oriwave CMS. When upgrading to 2.3 or 2.4, we should use this code as a use-case for a new API that lets us customise the CMS interface. The JavaScript refactoring work we do might want to bear this in mind, to make such customisations easier. (Merged via: r76666)
## Beta 1 - since 2.3.1
### New Features
* ![rev:75153] Allow Title and Navigation Label to be searched separately
* ![rev:74739] hooks into form field to allow custom error messages. Note does not currently apply to the behaviour / js. Just the PHP validation
* ![rev:74538] make PasswordField and ConfirmedPasswordField able to either readonly or disabled.
* ![rev:74503] make PasswordField and ConfirmedPasswordField able to either readonly or disabled.
* ![rev:74327] added $Var.UpperCase support to DBField
* ![rev:74326] allow you to disable ?m suffixing of requirements
* ![rev:74248] optionally allow sorting toDropdownMap() function. Patched from #3829
* ![rev:73670] added after uploading notify method
* ![rev:70327] Enabled specifying a language through a hidden field in SearchForm which limits the search to pages in this language (incl. unit tests) (Merged via: r74986)
### API Change
* ![rev:75913] Deprecated ModelAsController->get404Page() with using the URLSegment "404" on a normal page type - please use the ErrorPage class instead (Merged via: r75916)
* ![rev:75742] Deprecated Translatable::get_langs_by_id() - use getTranslations()
* ![rev:75328] Deprecated Translatable::get_homepage_urlsegment_by_language(), use get_homepage_urlsegment_by_locale() (Merged via: r75685)
* ![rev:74969] Deprecated DataObjectSet->toDropDownMap() and made it an alias of map(), copying the functionality of toDropDownMap() into map()
* ![rev:74901] add documentation to changeset r74858.
* ![rev:74858] BulkLoader::getImportSpec() call DataObject::fieldLables() with $includerelations as false, so that the relations is separated from column fields
* ![rev:74070] Deprecated Translatable::choose_site_lang(), use choose_site_locale() (Merged via: r74986)
* ![rev:73951] Removed Translatable::creating_from() - doesn't apply any longer
* ![rev:73900] Deprecated Object->extInstance(), use getExtensionInstance() instead
* ![rev:73468] Removed Translatable::get_original() - with the new "translation groups" concept there no longer is an original for a translation
* ![rev:73466] Deprecated Translatable::set_default_lang(), Translatable::default_lang() (Merged via: r74986)
* ![rev:73345] Removed CMSMain->switchlanguage() - createTranslation() is sufficient for new, ajax refreshing of CMS state got way too complicated for switching languages, we now just reload the entire CMS with a different ?lang GET parameter (Merged via: r74988)
* ![rev:73338] Translatable->findOriginalIDs(), Translatable->setOriginalPage(), Translatable->getOriginalPage()
* ![rev:70307] Removed CMSMain->switchlanguage() (Merged via: r74988)
* ![rev:70118] Removed obsolete Translatable::table_exists()
* ![rev:70072] Removed obsolete internal Translatable methods: hasOwnTranslatableFields(), allFieldsInTable()
* ![rev:69959] Removed Translatable::get_one(), Translatable::write()
### Bugfixes
* ![rev:76036] Fixed extraFilter argument for SiteTree::get_by_url() when translatable is enabled
* ![rev:76019] Unblock blocked requirements when opening a poppup - otherwise
* ![rev:75984] Removing ParentType and ParentID fields in Translatable->updateCMSFields() as they are causing js problems when set to readonly. These fields should only be set on the original record anyway (at least as long as we don't have a multi-language capable TreeMultiSelectField). (Merged via: r76035)
* ![rev:75983] Removed URLSegment detection from Translatable->onBeforeWrite() - it was always preceeded by SiteTree->onBeforeWrite() which already alters the URL, so the appending of locale values to disambiguate the URL was pointless (never triggered) (Merged via: r76035)
* ![rev:75936] Resetting default language in TranslatableTest - this was breaking VirtualPageTest before (Merged via: r75937)
* ![rev:75926] Fixed undefined var error in VirtualPage (Merged via: r75937)
* ![rev:75922] Resetting Translatable locale in SearchForm after querying - this was causing side-effects when running TranslatableSearchFormTest in combination with other Translatable tests (Merged via: r75937)
* ![rev:75920] Ensure that when template content is being parsed by Email::parseVariables(), template path comments don't show
* ![rev:75919] Ensure that template path comments don't make it into ViewArchivedEmail
* ![rev:75915] Fixed wrong parameter in ErrorPage::get_static_filepath() (Merged via: r75916)
* ![rev:75914] Fixing assets filepath in Debug::friendlyError() (Merged via: r75916)
* ![rev:75873] Automatically publish virtual pages when their source pages are published
* ![rev:75869] #3970: Make virtual page editing work.
* ![rev:75831] Checking for existing value on TreeDropdownField->performReadonlyTransformation() - this broke the ReadonlyTransformation on Translatable->updateCMSFields() for the new "ParentID" field in SiteTree->getCMSFields()
* ![rev:75826] Removing the appended querying for NULL or empty Locale values in Translatable->augmentSQL() - this should no longer be necessary as we set default locales to all records through Translatable->requireDefaultRecords() (Merged via: r75838)
* ![rev:75791] Fixed ErrorPage::get_filepath_for_errorcode() to work with locale values instead of short language subtags (Merged via: r75838)
* ![rev:75787] Fixed faulty regex that broke rewritten links to be relative to the base href
* ![rev:75785] set when ajax is disabled for commenting that we redirect manually down to the comment form
* ![rev:75782] Unified locale values between i18n::$all_locales and $common_locales - the common locales should be a subset of all locales, without any additional ones as this might cause side-effects with LanguageDropdownField (see #3958) (Merged via: r75783)
* ![rev:75745] Fixed DBLocaleTest (Merged via: r75746)
* ![rev:75743] #3959: Fixed auto-setting has many relations on CTF - works mostly like the many-many relation auto setting.
* ![rev:75733] Allow insertion of object tags (such as youtube vids) into WYSIWYG's HTML view
* ![rev:75705] Fixed right hand image add/edit form panel sizing
* ![rev:75675] Fixed i18n::get_locale_from_lang() to return original parameter if it detects a fully qualified locale that shouldn't be converted (Merged via: r75685)
* ![rev:75654] Fixed PageCommentInterface $this->class being NULL because parent::__construct() wasn't called
* ![rev:75614] Fixed refactoring of getRecord() so that it can handle currentPage() calls properly.
* ![rev:75611] Let CMS users open pages deleted from draft; bug introduced by translatable.
* ![rev:75585] Updated DataObjectSet::map() to use empty string, rather than 0, as the empty value
* ![rev:75328] Updated enabling mechanism in Translatable->alternateGetByUrl()
* ![rev:75270] #3740: Fixd duplicate tab highlight in ModelAdmin, by moving back to old tabstrip.js
* ![rev:75269] #3740: Make tabstrip.js less picky about the URL before the # link
* ![rev:75263] Fixed HTTPRequest::send_file() to actually output the response, whereas before it did nothing
* ![rev:75258] Fixed HTTPRequest::send_file() to send the file properly over SSL with Internet Explorer. Without the pragma header, it won't work
* ![rev:75249] Correctly showing the available languages dropdown in Translatable->getCMSFields() (Merged via: r75685)
* ![rev:75248] Only force DataObject->forceChange() on fields which aren't already marked as changed (Merged via: r75685)
* ![rev:75226] Let users open the root folder in Files and Images section
* ![rev:75223] Disable warning about PastMember cookie if contnet was sent too early.
* ![rev:75182] Make sure tabs resize correctly when they are loaded
* ![rev:75180] Make sure tabs are resized correctly on first load
* ![rev:75161] Disable Geoip if in CLI mode - this fixes the tests from breaking. The geoip command won't be available in CLI context
* ![rev:75156] Setting Classname and RecordClassname properties on internal $record map when constructing a DataObject without passing $record into it. This ensures that getChangedFields() works on ClassName as well, which is required for Translatable->onBeforeWrite() (Merged via: r75685)
* ![rev:75151] #3919: Fix DataObject::dbObject() for decorated fields (Merged from r75150)
* ![rev:75150] #3919: Fix DataObject::dbObject() for decorated fields (Merged via: r75151)
* ![rev:75126] Fixed incorrect spelling of "$this" variable
* ![rev:75125] Fixed CSVParser constructor not passing the arguments to the protected variables delimiter and enclosure
* ![rev:75121] #3681: Added dynamic width style to container div for TinyMCE-inserted images, so if the user resizes, the div width resizes too. Thanks to ajshort for the patch!
* ![rev:75119] Fix DropdownField to select the correct option when using a map with "0" as an array key - useful for boolean searching using DropdownField
* ![rev:75116] Fixed alternative database not being reset back to the normal one after TestRunner is finished
* ![rev:75113] Fixed image editing panel padding in CMS "Insert image" button being squashed
* ![rev:75096] Allow execution of actions (such as Page's search) on ErrorPage; limit the 404 display to the index() action
* ![rev:75095] Use rendered page for 404 pages
* ![rev:75049] Ensure that CheckboxField always returns 1 from the form request data instead of "on" - this was because the value attribute didn't exist on the `<input>` tag
* ![rev:75046] Make sure that CheckboxField sets it's value as either 1 or 0, so that saveInto() saves the proper boolean value
* ![rev:75045] Ensure that CheckboxField setValue() always sets it's value as either 1 or 0, even though the request data can come through as "on"
* ![rev:75039] Fixed case where logging in with a session member ID that didn't exist in the database stopped you from being able to "Log in as someone else"
* ![rev:75038] #3594: Made WYSIWYG editor 50% larger
* ![rev:75034] Select correct default data formatter in restfulserver when there's an apparently useful Accept header that doesn't actually match a data formatter{
* ![rev:75032] Fixed "Log in as someone else" action failure when submitting MemberLoginForm while logged in
* ![rev:75030] when load a new Page (or other type of form in DataAdmin or GenericAdmin), initTabstripe called additional time for every tabstrip on the page
* ![rev:75023] Fixed error if clicking the root of a sitetree in the CMS - affected the AssetAdmin and SecurityAdmin sections
* ![rev:74981] Member::inGroup() returns false instead of an error if group doesn't exist. Ticket #3813 - thanks bgribaudo!
* ![rev:74980] Fixed ajax deletion of Group records properly - the site tree items didn't disappear immediately after deleting
* ![rev:74978] Fixed spelling mistake of "getOrientation" method name on Image
* ![rev:74961] Fixed error if JS/CSS requirements have arguments. Ticket #3860. Thanks simon_w!
* ![rev:74951] Fixed CMSMainTest->testThatGetCMSFieldsWorksOnEveryPageType() - was comparing a string $class with instanceof() instead of comparing the actually created instance (Merged via: r74988)
* ![rev:74942] Fixed TranslatableSearchFormTest->setUp() method (Merged via: r74986)
* ![rev:74927] Clearing Requirements in ScaffoldingComplexTableField, and fixed constructor arguments
* ![rev:74924] Explicitly destroy TinyMCE instances when loading a new page, in an attempt to reduce memory leaks
* ![rev:74920] Moving Requirements for AssetTableField, CommentTableField and MemberTableField from __construct() into FieldHolder() and renderWith(), which means inclusion closer to render time, and less side-effects by a previous Requirements::clear(), e.g. in a CTF popup. See r74919
* ![rev:74919] Moving Requirements for TableField, TableListField, ComplexTableField, ScaffoldComplexTableField and HasManyComplexTableField from __construct() into FieldHolder() and renderWith(), which means inclusion closer to render time, and less side-effects by a previous Requirements::clear(), e.g. in a CTF popup
* ![rev:74904] Removed unnecessary requirements from ComplexTableField_Popup: LeftAndMain.js, LeftAndMain_right.js, TableField.js, ComplexTableField.js - they will be included by the fields if necessary
* ![rev:74902] Making sure all input fields inside a newly added TableField row have unique HTML ids. This was causing problems when javascript logic was acting on those (previously ambiguous fields), e.g. when trying to use a jQuery UI datepicker
* ![rev:74899] If validator doesn't exist on Form, don't attempt to call setForm() on it or you'll get a non-object error
* ![rev:74879] Removed additional $ sign that isn't supposed to be there that broke GroupTest
* ![rev:74725] Fixing CurrencyField serverside and javascript validation to accept numbers with leading or trailing spaces
* ![rev:74721] Fixing NumericField serverside validation to accept numbers with leading or trailing spaces by using trim()
* ![rev:74657] Fixed NumericField javascript validation to not fail on numbers with trailing or leading whitespace
* ![rev:74620] Added missing default english text for "No items found" in TableListField.ss
* ![rev:74489] add more condition before $this->form is used as Caller since $this->form can still not be set yet in a certain circumstance.
* ![rev:74487] A SoapServer will cache the wsdlFile when it is first initialized and never get updated if the constructor is not explicitly passed in 'cache_wsdl' as WSDL_CACHE_NONE.
* ![rev:74477] fixed typos in ResetFormAction
* ![rev:74397] Added missing "Created" and "LastEdited" fields to the MemberTableField export fields
* ![rev:74391] fixed overflow being hidden
* ![rev:74322] Allows DataObjectDecorators and other extensions to specify setters (setFoo) in the same manner as the already working Getters (getFoo).
* ![rev:74303] Allow testing of emails when Email::send_all_emails_to() is set
* ![rev:74272] fixed issue with greyscale GD - patch from camspiers
* ![rev:74098] Fixed javascript error in CommentTableField.js where input elements were not being correctly picked up, due to the form HTML change
* ![rev:74097] Search filter should retain the existing query instead of removing it after each search in MemberTableField and CommentTableField
* ![rev:74092] Fixed issue with StaticPublisher->onAfterWrite() failing because of incorrect arguments to Versioned::get_by_stage()
* ![rev:74071] Fixed Form_EditForm_Locale reference in LeftAndMain_right.js (used to be Form_EditForm_Lang) (Merged via: r74988)
* ![rev:74069] Fixed legacy handling of Translatable::enable(),Translatable::disable() and Translatable::is_enabled() - applying extension to SiteTree instead of Page to avoid datamodel clashes (Merged via: r74986)
* ![rev:74065] Re-added Translatable->isTranslation() for more friendly deprecation (originally removed in r73338) (Merged via: r74986)
* ![rev:73900] Unsetting all cached singletons in Object::remove_extension() to avoid outdated extension_instances
* ![rev:73883] Making $_SINGLETONS a global instead of a static in Core.php so it can be re-used in other places (Merged via: r74986)
* ![rev:73836] Removed version number from `<meta>` generator tag - opt for security by obscurity in this case (originally committed in r70422 and r71172) (Merged via: r73837)
* ![rev:73775] fixed cropping of TreeDropdownField popups and Date popups within complextablefield popups
* ![rev:73758] #3798 ajshort: Let searchcontext be used on sitetree
* ![rev:73608] fixed choppy gradient (or lack thereof) in the tinymce window
* ![rev:73603] updated FormTest with fullstop
* ![rev:73594] Fixed layout of cms rhs area buttons
* ![rev:73593] Simple toolbar alteration to make toolbar fit at 1024x768
* ![rev:73533] Fix call to undefined "_12Hour" function (merged from r73523)
* ![rev:73484] Get installer working with php_short_tags off (Merged r73481-3 from trunk)
* ![rev:73482] #3758: Fixed config-form.html for use with short_open_tag = off (Merged via: r73484)
* ![rev:73472] Fixed translatable test execution by making protected methods public (Merged via: r74986)
* ![rev:73468] Updated MigrateTranslatableTask to new Locale based datamodel (Merged via: r74986)
* ![rev:73465] Fixed Hierarchy->Children() testing in TranslatableTest - with the new datamodel you can't call Children() in a different language regardless of Translatable::set_reading_lang(), the Children() call has to be made from a parent in the same language (Merged via: r74986)
* ![rev:73344] Checking for existence of original before trying to get translation in LeftAndMain->currentPage() (Merged via: r74988)
* ![rev:73343] Changed CSS selector for TranslationTab javascript behaviour to be less specific (Merged via: r74988)
* ![rev:73342] Removed link to "original page" for a translation - no longer valid
* ![rev:73341] Disabled auto-excluding of default language from the "available languages" array in LanguageDropdownField - due to the new "translation groups" its possible to have a translation from another language into the default language (Merged via: r74986)
* ![rev:73339] Disabled "untranslated" CSS class for SiteTree elements - doesn't apply any longer with the new "translation groups" concept (Merged via: r74986)
* ![rev:73338] Removed bypass in Translatable->AllChildrenIncludingDeleted() (Merged via: r74986)
* ![rev:73059] Make object cache testing more robust (Merged via: r74986)
* ![rev:72054] Fixed finding a translated homepage without an explicit URLSegment (e.g. http://mysite.com/?lang=de) - see #3540
* ![rev:71340] Including Hierarchy->children in flushCache() and renamed to _cache_children. This caused problems in TranslatableTest when re-using the same SiteTree->Children() method with different languages on the same object (even with calling flushCache() inbetween the calls) (Merged via: r74986)
* ![rev:71297] Only show the LangSelector dropdown if there's multiple languages available on the site (Merged via: r74988)
* ![rev:71258] Fix translatable being enabled when it shouldn't be (Merged via: r74986)
* ![rev:70324] Making sure that LeftAndMain->CurrentPage() respects language settings - was returning pages in different language from session after switching between languages in cms (Merged via: r74988)
* ![rev:70323] Fixed expanded/unexpanded flags on new tree items - was showing expanded styling (plus icon) with newly created pages
* ![rev:70322] Ensuring that new pages can't be created when in translation mode by disabling the "create..." tree action (Merged via: r74988)
* ![rev:70318] Reverted special cases for Translatable in Versioned->canBeVersioned() (originally committed in r42119) - was checking for existence of underscores in table names as an indication of the "_lang" suffix, which is no longer needed. It was also a flawed assumption which tripped over classes like TranslatableTest_TestPage (Merged via: r74986)
* ![rev:70306] Don't require a record to be written (through exists()) when checking Translatable->isTranslation() or Translatable->hasTranslation()
* ![rev:70214] Falling back to Translatable::current_lang() if no $context object is given, in augmentAllChildrenIncludingDeleted() and AllChildrenIncludingDeleted()
* ![rev:70138] Disabled assumption that SQLQuery->filtersOnID() should only kick in when exactly one WHERE clause is given - this is very fragile and hard to test. It would return TRUE on $where = "SiteTree.ID = 5", but not on $where = array("Lang = 'de'", "SiteTree.ID = 5") (Merged via: r74986)
* ![rev:70080] Fix translatable migration not writing records to Live properly (Merged via: r74986)
* ![rev:69959] Temporarily disabled cookie/session selection in Translatable::choose_site_lang() until we have a good test suite for the side effects.
* ![rev:60171] Improved DataObject::get_one to avoid PHP segfaults (Merged via: r74986)
### Enhancement
* ![rev:75815] Added page location fields in the behaviour tab, as an alternative to drag and drop
* ![rev:75814] Added page location fields in the behaviour tab, as an alternative to drag and drop
* ![rev:75793] Running TestRunner tests suites alphabetically through natcasesort() instead of using the (relatively arbitrary) class ordering from ClassInfo::getSubclassesFor() (Merged via: r75838)
* ![rev:75759] Allow selecting a single field from ComponentSet::getExtraData()
* ![rev:75742] Added DBLocale class for Translatable extension
* ![rev:75737] Added 'show deleted pages' function to CMS, with a restore page option.
* ![rev:75736] Added 'show deleted pages' function to CMS, with a restore page option.
* ![rev:75678] Adapted MigrateTranslatableTask to new Locale datamodel and fixed some inconsistencies with translation groups, duplicate records etc (Merged via: r75685)
* ![rev:75677] Added override flag to Translatable::addTranslationGroups()
* ![rev:75421] Auto-update locale values in Translatable->requireDefaultRecords() with default language when Translatable is first enabled (Merged via: r75685)
* ![rev:75351] Added nl_NL javascript translations for sapphire, see #3896 - thanks Mad_Clog (Merged via: r75685)
* ![rev:75349] Added Translatable->MetaTags() to automatically insert `<link rel="alternate" hreflang="...>` tags into the page template (Merged via: r75685)
* ![rev:75228] #3920: Alllow searching within subfolders in Files and Images section
* ![rev:75226] #3920: Alllow searching within subfolders in Files and Images section
* ![rev:75119] Allow "Yes" and "No" english text to be translated
* ![rev:75037] Added fullscreen button to WYSIWYG toolbar
* ![rev:75036] #3687: Allow the insertion of iframes (such as google maps snippets) into TinyMCEa
* ![rev:74941] Using set_up_once() in TranslatableTest and TranslatableSearchFormTest for better test run performance (Merged via: r74986)
* ![rev:74919] Removed constructor overloading in ScaffoldingComplexTableField, was reconstrcuting its own Requirements (with lots of unnecessary jQuery plugins) which should really be done by the individual form fields and the parent popup class
* ![rev:74489] add the ability that a SimpleImageField could be disabled.
* ![rev:74017] Improved deprecated fallbacks in Translatable by auto-converting short language codes to long locales and vice versa through i18n::get_lang_from_locale()/i18n::get_locale_from_lang() (Merged via: r74986)
* ![rev:73951] Translatable extension is no longer hooked up to SiteTree by default, which should improve performance and memory usage for sites not using Translatable. Please use Object::add_extension('SiteTree','Translatable') in your _config.php instead. Adjusted several classes (Image, ErrorPage, RootURLController) to the new behaviour. (Merged via: r74986)
* ![rev:73900] Unsetting class caches when using Object::add_extension() to avoid problems with defineMethods etc.
* ![rev:73884] Added Extension::get_classname_without_arguments() (Merged via: r74986)
* ![rev:73882] Added DataObjectDecorator->setOwner() (Merged via: r74986)
* ![rev:73473] Added Object::combined_static(), which gets all values of a static property from each class in the hierarchy (Merged via: r74986)
* ![rev:73469] Adjusted CMSMain and LeftAndMain to use locales instead of short lang codes when reading and writing translations. See r73468 for details on the underlying Translatable datamodel change (Merged via: r74988)
* ![rev:73468] Adjusted SearchForm, Debug, ErrorPage, SiteTree to using locales instead of lang codes
* ![rev:73467] Supporting "Locale-English" and "Locale-Native" as listing arguments in LanguageDropdownField (Merged via: r74986)
* ![rev:73466] Added Translatable::get_locale_from_lang(), Translatable::get_common_locales(), $common_locales and $likely_subtags in preparation to switch Translatable from using short "lang" codes to proper long locales
* ![rev:73345] Added CMSMain->IsTranslatableEnabled
* ![rev:73338] Added check for an existing record in Translatable->createTranslation()
* ![rev:73059] Added Object::clearCache() to clear a cache
* ![rev:73036] #3032 ajshort: Use static methods for accessing static data (Merged via: r74986)
* ![rev:72367] Using IETF/HTTP compatible "long" language code in SiteTree->MetaTags(). This means the default `<meta type="content-language...">` value will be "en-US" instead of "en". The locale can be either set through the Translatable content language, or through i18n::set_locale() (Merged via: r74986)
* ![rev:72054] Added RootURLController::get_default_homepage_urlsegment() (Merged via: r74986)
* ![rev:71795] Strip tags before limiting characters when using LimitCharacters() on HTMLText field type
* ![rev:70326] Added ErrorPage::$static_filepath to flexibly set location of static error pages (defaults to /assets) (Merged via: r74986)
* ![rev:70319] Disabled Translatab-e>augmentWrite() - was only needed for the blacklist fields implementation which is inactive for the moment
* ![rev:70308] Removed "Translating mode" status message above edit form - should be clear by the language dropdown above the CMS tree now (Merged via: r74988)
* ![rev:70307] Simplifying creation logic of new languages in CMS by reloading complete interface, rather than refreshing partial interface, language dropdown etc.
* ![rev:70306] Adding link back to original page in CMS editform for translations
* ![rev:70305] Allowing non-default language URLs to be accessed without explicitly specifying the language in GET request (Merged via: r76035)
* ![rev:70118] Made Translatable constructor arguments optional, as by default all database fields are marked translatable
* ![rev:70073] Added basic unit tests to new Translatable API
* ![rev:70072] Added a note about saving a page before creating a translation
* ![rev:69959] Showing clickable links for Translations in Translatable->updateCMSFields()
### Other
* ![rev:76019] HTMLEditorFields won't work
* ![rev:75915] BUGIFX Changed ErrorPage->publish() to doPublish->doPublish() - the publication of static HTML into the /assets directory was lagging one version behind the actual published content
* ![rev:75816] Reverted r69824
* ![rev:75813] Reverted `<div>` being added to images - r69823, r69824
* ![rev:75812] Reverted r69828
* ![rev:75784] ENHANCHEMENT: added ability for a form author to set whether user should be redirected back down the the form rather then just back to the old page
* ![rev:75738] #3927 ENHANCEMENT Added support for many-many auto-setting relations with a standard ComplexTableField
* ![rev:75703] Merged r75696 from cms/trunk
* ![rev:75702] Merged r75697 from sapphire/trunk
* ![rev:75701] Merged r75691 from jsparty/trunk
* ![rev:75700] Merged r75690 from sapphire/trunk
* ![rev:75698] Merged r75689 from jsparty/trunk
* ![rev:75660] Merged from trunk
* ![rev:75267] Reverted r75263 and r75264
* ![rev:74988] Merging refactored Translatable from trunk, and related changes to CMSMain
* ![rev:74986] Merging in refactored Translatable architecture from trunk, including related/required changesets like enhancements to Object static handling (see details below)
* ![rev:74980]
* ![rev:74969]
* ![rev:74900] Reverted r74899
* ![rev:74714] Fix resize being called an additional time for every tabstrip on the page
* ![rev:74501] Undoing changeset committed in r74490
* ![rev:74416] fix the bug in Mingle (SC #234):Users reporting a parse error when trying to open grants. also HD(1571).
* ![rev:74304] Added SiteTree onAfterRevertToLive handler
* ![rev:74092]
* ![rev:73613] Merged r71795 from trunk
* ![rev:73481] Added a syntax checking test that will use short_tags on and off and asp_tags on (Merged via: r73484)
* ![rev:73452] Fixed issue with ModelAdmin tab CSS
* ![rev:71567] 'URLSegment' on line 484 and 494 now escaped (Merged via: r74986)
* ![rev:70033] Add translation migration task (Merged via: r74986)
* ![rev:69959] Merged, debugged and enhanced Translatable patches from branches/translatable at r64523, r64523, 64523, thanks wakeless!
* ![rev:68917] Merged Requirements fix from nestedurls branch (Merged via: r74986)
* ![rev:68915] Fixed bug in Requirements::disable() (Merged via: r74986)
* ![rev:68912] Bugfixes for recent staticpublisher imports (Merged via: r74986)
* ![rev:68911] Bugfix for staticpublisher updates in trunk (Merged via: r74986)
* ![rev:68900] Static caching merges from dnc branch (Merged via: r74986)
* ![rev:61495] Fixed bug that was causing phantom pages on DNC - no need to merge, because trunk already has this (Merged via: r74986)
* ![rev:61493] Fixed bugs with redirector page error message and static publishing - it created blank 'phantom' pages at the top level (Merged via: r74986)
* ![rev:60015] Set default cache behaviour to uncached. This is a good new default behaviour and can be merged. Pages that are cacheable should call HTTP::set_cache_age() in their controller init (Merged via: r74986)
* ![rev:60007] Fixed bug with calling DataObject::flush_and_destory_cache more than once (Merged via: r74986)

View File

@ -0,0 +1,65 @@
# 2.3.3 (2009-08-03)
## Upgrading
### DataObjectDecorator::extraStatics()
DataObjectDecorator::extraStatics() can no longer refer to $this because it's called statically
## Changelog
### API Change
* ![rev:79430] #4255 sharvey: DataObjectDecorator::extraStatics() can no longer refer to $this because it's called staticly (Merged via: r81698)
### Bugfixes
* ![rev:82094] applied patch from #4381. Observable doesnt play nice with jQuery
* ![rev:82035] Fixed double up of `<span>` highlight tags around keywords in Text::ContextSummary()
* ![rev:81942] Fixed bugs in content differencer, and improved styling. BUGFIX: fixed notice when getting title of member which didnt exist. Merged from trunk r77661.
* ![rev:81894] Convert::recursiveXMLToArray() did not always check if the passed in XML is an object before calling get_class() on it
* ![rev:81883] Merged in PHP 5.3 bugfixes from trunk
* ![rev:81822] Deleted duplicate call to curl_exec() in RestfulService (merge error from r69704) (Merged via: r81823)
* ![rev:81698] #4285: Fixed static application bug that appeared in 2.3.2
* ![rev:81693] Fix static application for translatable (Merged via: r81698)
* ![rev:81676] #4285: Fixed application of decorators when add_extension not used. (Merged via: r81698)
* ![rev:81544] Calling parent constructors in ModelViewer
* ![rev:81467] Fixed Hierarchy->markChildren() to only mark nodes as unexpanded if they actually have children. This avoids UI glitches with "plus"-icons beside unexpandable nodes, and prevents batch actions and TreeNode->open() to trigger ajaxExpansion on nodes without children (from r78339) (Merged via: r81971)
* ![rev:81461] Correct behaviour if CMSMain::tellBrowserAboutPublicationChange() isn't passed a status message (Merged via: r81965)
* ![rev:81460] Fixed FileSearch parameter in AssetTableField. Pagination of filtered search results and refresh of the tabular view after saving a popup wasn't working because the search parameter wasn't retained (Merged via: r81962)
* ![rev:81450] If referrer had spaces, they would be encoded as %20, which would cause problems when interpolated into an sprintf pattern. Inject instead.
* ![rev:81262] Relax type checking in RequestHandler::checkAccessAction()
* ![rev:81173] Fixed application of parameterised extensions with Object::add_extension() (Merged via: r81698)
* ![rev:81050] prevented cms from dying when a page has no published children. Added check before stepping into the loop
* ![rev:80863] Fixed invalid HTML in AssetAdmin_uploadiframe.ss which could have an effect on file uploads
* ![rev:80382] Fixed Image_iframe.ss to use X-UA-Compatible IE7 emulation meta tag
* ![rev:80380] Fixed "method is not a string" error in Form::httpSubmission()
* ![rev:80131] Fix behaviour of FILE_TO_URL_MAPPING on Windows. (Merged via: r81883)
* ![rev:79720] Added explicit DataObjectDecorator::load_extra_statics() calls as a workaround for issues with extensions defined directly in-object. (Merged via: r81698)
* ![rev:79599] Allow extraDBFields() on decorators for compatibility, throw a deprecated notice (Merged via: r81698)
* ![rev:79433] Object::add_extension() should only load statics for extensions of DataObject, since it is specific to DataObjectDecorator (Merged via: r81698)
* ![rev:79430] #4255 sharvey: Fix application of extra db fields by DataObjectDecorators.
* ![rev:78628] Added better support for newly created records in DataDifferencer (Merged via: r81475)
* ![rev:78392] Fixed FileSearch parameter in AssetTableField. Pagination of filtered search results and refresh of the tabular view after saving a popup wasn't working because the search parameter wasn't retained (Merged via: r81962)
### Enhancement
* ![rev:81933] Updated Versioned::compareVersions() to use DataDifferencer. Merged from trunk r77660
* ![rev:81544] Checking for GraphViz dependency in ModelViewer (Merged via: r81546)
* ![rev:81475] Improvements to DataDifferencer for cmsworkflow.
* ![rev:80863] Removed JS generated from PHP code in AssetAdmin::UploadForm() and placed it into AssetAdmin_uploadiframe.ss
* ![rev:80340] simpleXML() now catches the error if you try to call it on anything other then xml. MINOR: added test to RESTFul Service
* ![rev:79404] Added better support for using DataDifferencer to look at new records. (Merged via: r81475)
* ![rev:79400] Added better support for using DataDifferencer to look at new records. (Merged via: r81475)
* ![rev:78329] Added API docs and changedFieldNames() method to DataDifferencer (Merged via: r81475)
* ![rev:77787] Allow altering of DataObject:$api_access by decorators. (Merged via: r81698)
### Other
* ![rev:81993] e:
* ![rev:81965] Merged r81461 from trunk
* ![rev:81962] Merged r81460 from trunk

View File

@ -0,0 +1,43 @@
# 2.3.4 (2009-11-27)
## Changelog
### New Features
* [rev:84085] Allow different user groups to have different HtmlEditorConfigs
* [rev:83631] Allow file size/extension limits to apply to the admin user as
### API Change
* [rev:91610] BasicAuth::requireLogin() no longer has an option to automatically log you in. You can call logIn() on the object returned, instead. (from r91603)
* [rev:91130] move SubscribeSumission.ss from cms module to newsletter module, cos it is only used by newsletter module.
* [rev:91034] Added SapphireTest::logInWithPermission() (merged from r89209)
* [rev:88176] Added no-arg option to increase_memory_limit_to() (from r80241)
* [rev:84594] Template codes can no longer be used in emails except when using .ss files.
* [rev:84157] Make Object::uninherited_static() have a separate execution path to Object::get_static(), for more reliable operation. The intention is that for any given static, you either use Object::get_static() or you use Object::uninherited_static() - not both. (from r84151, r84155, r84156)
### Bugfixes
* [rev:93483] fix for multiple EmailField validation on one form. Merged via r78565
* [rev:91660] Made use of new BasicAuth::protect_entire_site() consistent. (from r91658)
* [rev:91611] Don't enable site-wide protection by default (from r91609)
* [rev:89612] Added rewriteHashlinks = 'php' option to SSViewer so that static publisher can handle internal hashlinks properly.
* [rev:89611] Added rewriteHashlinks = 'php' option to SSViewer so that static publisher can handle internal hashlinks properly.
* [rev:88281] Ensure ASSETS_PATH is respected
* [rev:87869] Pass locale rather than language to spellchecker_languages
* [rev:87867] Always choosing translatable default language in CMSMain->init() for TinyMCE spell checking. Always setting ->Locale in order to have it available for the spell checking (from r81716)
* [rev:87458] #4579: Translatable's call to new LanguageDropdownField() broked (from r87456)
* [rev:86573] fixed typo in pagecomment which meant commenter url was not saved. BUGFIX: updated protector to use new format
* [rev:86325] Fixed Links to Moderate Comments from the CMS and front end. MINOR: removed complextable functions which no longer get called, moved logic to the PageComment Class
* [rev:86202] was being passed to foreach without a check to see if it's an array or not.
* [rev:85779] Fixed Member::sendInfo() assumptions that broke with an API change in r84594
* [rev:85632] findByTagAndAttribute is unintentionally expanding any php found in the href/src components its regex extracts. Changed double quotes to single quotes to fix this.
* [rev:84957] Tied rollback action to edit, rather than publish, permission, since it only involves editing the draft site.
* [rev:84380] Fixing the comment's author website url being converted to lowercase: now case is not affected.
* [rev:84332] Added required javascript files (behaviour, prototype, prototype_improvements) to the Field() method of TreeDropdownField.php
* [rev:84320] Added required javascript files (behaviour, prototype, prototype_improvements) to the Field() method of TreeSelectorField.php
* [rev:83587] Object subclasses with a constructor that didn't already will now call parent to respect inheritance
* [rev:83586] CMSMenuItem constructor now calls parent to respect inheritance
* [rev:83579] Fixed FilesystemPublisher::__construct() not calling parent::__construct() and breaking DataObjectDecorator::load_extra_statics()

View File

@ -0,0 +1,15 @@
# 2.3.5 (2010-01-21)
## Changelog
### Bugfixes
* [rev:97221] BUGFIX: add if condition for window.ontabschanged() call
* [rev:97074] BUGFIX Attribute escaping in PageCommentInterface_singlecomment.ss
* [rev:96962] BUGFIX: fixed overlapping buttons in modeladmin.
* [rev:96959] BUGFIX: fixed layout issue when tinymce event handler was not removed before the load request. Removed back button display when no history existed
* [rev:96998] BUGFIX: fixed TaskRunner generating link with 2 slashes
### Minor
* [rev:97004] MINOR: fixed notice level error when ImageSource isnt set

View File

@ -0,0 +1,40 @@
# 2.3.6 (2010-02-08)
## Changelog
### Features and Enhancements
* [rev:98081] Removed dev/reset, instead encouraging the use of dev/tests/startsession for tests.
* [rev:98081] Let people use dev/tests/startsession without a fixture, instead calling requireDefaultRecords
### API Changes
* [rev:98375] HTTP::setGetVar() always returns absolute URLs. Use Director::makeRelative() to make them relative again. (merged from r98373)
* [rev:98375] HTTP::setGetVar() combines any GET parameters in PHP array notation (e.g. "foo[bar]=val") instead of replacing the whole array (merged from r98373)
### Bugfixes
* [rev:98405] #5044 Hierarchy::loadDescendantIDListInto() now uses Object::getExtensionInstance('Hierarchy') instead of going through call(), as PHP 5.3 has issues converting references to values
* [rev:98405] Fixed Hierarchy->loadDescendantIdList() to call setOwner() on the extension instance. This was necessary due to underlying Object/Extension changes in 2.4. (merged from r98403)
* [rev:98375] HTTP::setGetVar() uses parse_url() and http_build_query() to add query parameters to an existing URL, instead of doing its own regex-based parsing. This means existing GET parameters are correctly url encoded. (merged from r98373)
* [rev:98273] Don't force SSL when running from CLI
* [rev:98230] Disabled ?debug_profile=1 on live environment types (merged from r80057)
* [rev:98229] Limiting ?debug_memory parameter to development environments through using Debug::message() instead of a straight echo() (merged from r74067)
### Minor changes
* [rev:98410] Fixed HTTPTest->testSetGetVar() (merged from r98409)
* [rev:98408] Fixed HTTPTest->testSetGetVar() (merged from r98407)
* [rev:98405] Added test case for Hierarchy::getDescendantIDList() which also tests Hierarchy::loadDescendantIDListInto() (merged from r98369)
* [rev:98405] Testing of grand-children items in HierarchyTest::testLoadDescendantIDListIntoArray() and HierarchyTest::testNumChildren() (merged from r98376)
* [rev:98405] Fixed HierarchyTest assertions around including grand children counts (merged from r98403)
* [rev:98384] Fixed HTTPTest when invoked through dev/tests/all or with GET parameters (see r98373) (merged from r98383)
### Other
Created with:
{![](_images/./sscreatechangelog --version 2.3.6 --branch branches/2.3 --stopbranch tags/2.3.5)}

View File

@ -0,0 +1,12 @@
# 2.3.7 (2010-03-18)
## Changelog
### Bugfixes
* [rev:101229] Don't delete index.php after successful installation - in ContentController->deleteinstallfiles(). URL routing might rely on it without mod_rewrite.
* [rev:101229] Require ADMIN permissions for ContentController->deleteinstallfiles() - together with retaining index.php this removed a vulnerability where unauthenticated users can disrupt mod_rewrite-less URL routing. (from r101227)
* [rev:100744] Fixing Member_ProfileForm to validate for existing members via Member_Validator to avoid CMS users to switch to another existing user account by using their email address (from r100704) (from r100717)
Created with:
<code>./sscreatechangelog --version 2.3.7 --branch branches/2.3 --stopbranch tags/2.3.6)</code>

View File

@ -0,0 +1,55 @@
# 2.3.8 (2010-07-23)
No overview noted.
## Upgrading Notes
See API Changes below
### Security: File->setName() and File->Filename handling
See [2.4.1](2.4.1#securityfile-_setname_and_file-_filename_handling)
### Security: Disallow direct execution of *.php files
See [2.4.1](2.4.1#securitydisallow_direct_execution_of_php_files)
## Changelog
### Features and Enhancements
* [rev:108062] Added File::$allowed_extensions (backport from 2.4 to enable File->validate() security fix)
* [rev:103684] Allowing !TestRunner? to skip certain tests through the ?!SkipTests?=... GET paramete (merged from branches/2.3-nzct) (from r80646)
* [rev:103659] do not show comments that need moderation in the comment rss feed
### API Changes
* [rev:108062] Don't reflect changes in File and Folder property setters on filesystem before write() is called, to ensure that validate() applies in all cases. This fixes a problem where File->setName() would circumvent restrictions in File::$allowed_extensions (fixes #5693)
* [rev:108062] Removed File->resetFilename(), use File->updateFilesystem() to update the filesystem, and File->getRelativePath() to just update the "Filename" property without any filesystem changes (emulating the old $renamePhysicalFile method argument in resetFilename())
* [rev:108062] Removed File->autosetFilename(), please set the "Filename" property via File->getRelativePath()
### Bugfixes
* [rev:108045] Don't allow direct access to PHP files in mysite module. (from r108029)
* [rev:108044] Don't allow direct access to PHP files in cms module. (from r108028)
* [rev:108043] Don't allow direct access to PHP files in sapphire module, except for main.php and static-main.php (from r108023)
### Minor changes
* [rev:108062] Added unit tests to !FileTest and !FolderTest (some of them copied from !FileTest, to test Folder behaviour separately)
* [rev:108046] Partially reverted r108045, mistakenly committed !RewriteBase change
* [rev:108040] Added .mergesources.yml
* [rev:103897] Added querystring option to Makefile (from r103884)
* [rev:103895] Added querystring option to Makefile (from r103746)
* [rev:103528] sort page comment table by Created field - show newest entries first
* [rev:103521] Fixed !FileTest execution if the assets/ directory doesn't exist. (from r88353) (from r98086)
* [rev:103447] Fixed js applying to non-tinymce textarea fields in !ModelAdmin.js (fixes #5453)
* [rev:103362] Fixed js applying to non-tinymce textarea fields in !ModelAdmin.js (fixes #5453)
* [rev:103348] added moderation message for non-ajax mode
* [rev:101258] Fixed missing closing <div> in !ContentController->successfullyinstalled() (from r101254)
<code>./sscreatechangelog --version 2.3.8 --branch branches/2.3 --stopbranch tags/2.3.7</code>

View File

@ -0,0 +1,52 @@
# 2.3.9 (2010-11-11)
## Overview
* Fixed a security issue where destructive controller actions are not correctly secured against Cross-Site Request Forgery (CSRF). This affects various CMS interfaces, as well as classes based on TableListField or ComplexTableField.
* Compatibility with PHPUnit 3.5
See [2.4.3](2.4.3)
## 2.3.9 Changelog
### Features and Enhancements
* [rev:113305] Added Form->enableSecurityToken() as a counterpart to the existing disableSecurityToken() (from r113284)
* [rev:113293] Added !SecurityToken to wrap CSRF protection via "SecurityID" request parameter (from r113272)
* [rev:111834] refactored runTests, using the new phpunit wrapper classes.
* [rev:111832] Created a phpunit wrapper class to ensure that Sapphire's test framework is capable of running unit tests, coverage report and retrieve clover-statistics for PHPUnit 3.4 and PHPUnit 3.5
### API Changes
* [rev:113321] Using Controller::join_links() to construct links in !ComplexTableField and !TableListField (partially merged from r88495, r96775)
* [rev:113318] Fixed various controllers to enforce CSRF protection through Form_!SecurityToken on GET actions that are not routed through Form->httpSubmission(): !AssetAdmin, CMSBatchActionHandler, CMSMain, !CommentTableField, !LeftAndMain, !MemberTableField, !PageComment, !PageComment_Controller (from r113282)
* [rev:113297] Added security token to !TableListField->Link() in order to include it in all URL actions automatically. This ensures that field actions bypassing Form->httpSubmission() still get CSRF protection (from r113275)
### Bugfixes
* [rev:113319] Fixed Controller::join_links() handling of fragment identifiers (merged from r104580)
* [rev:113302] Clear static marking caches on Hierarchy->flushCache() (from r113277)
* [rev:113301] Fixed !ComplexTableField and !TableListField GET actions against CSRF attacks (with Form_!SecurityToken->checkRequest()) (from r113276)
* [rev:113294] Using current controller for !MemberTableField constructor in Group->getCMSFields() instead of passing in a wrong instance (Group) (from r113273)
* [rev:113158] Add PHPUnit includes to !SapphireTest class (can be loaded outside of !TestRunner for static calls, in which case the PHPUnit autoloaders/includes aren't in place yet) (merged from r113156)
* [rev:111837] Using mock controller in !RestfulServiceTest to avoid problems with missing require() calls for PHPUnit/Framework.php (performed in recently merged PHPUnitWrapper::init() which is never called for "nested" true HTTP calls within unit tests). Mostly merged from branches/2.4.
* [rev:111836] Renamed PHPUnit wrappers not to use underscores in classnames, as this confuses !ManifestBuilder prior to the 2.4 release
### Minor changes
* [rev:113361] Fixed regression from r113282 for changed !SecurityToken API in CMSMain->publishall() (fixes #6159) (from r113360)
* [rev:113312] Using !SecurityToken in !ViewableData->getSecurityID() (from r113274)
* [rev:113308] Removed unused !SecurityAdmin->!MemberForm() and savemember() (see !MemberTableField) (from r113281)
* [rev:113307] Removed unused !SecurityAdmin->removememberfromgroup() (see !MemberTableField) (from r113279)
* [rev:113303] Reverted commented out code (regression from r113293)
* [rev:113298] Fixed HTTPRequest class usage (regression from r113293)
* [rev:111835] added phpdoc to the new PHPUnitWrapper classes.
### Other
* [rev:111833] API-CHANGE: remove include which is not required.
* [rev:111831] ENHACENEMENT: Change behaviour of the !MenufestBuilder to use spl_autoload_register instead of traditional __autoload.

861
docs/en/changelogs/2.4.0.md Normal file
View File

@ -0,0 +1,861 @@
# 2.4.0 (2010-05-05)
## Overview
* Support for hierarchical URLs
* Support for MSSQL server database abstraction (via a separate module)
* A "SiteConfig" record stores site-wide settings and default permissions and author groups for pages
* "Permission Roles" are a simple way to combine multiple permission codes and assign them to groups in the Security interface. This makes permissions easier to maintain and less repetitive to set up.
* The CMS searches for broken internal links to other pages and broken file references, and highlights them in the WYSIWYG editor
* Dramatically reduced memory usage in CMS tree on larger sites (10,000+)
* Performance improvements around Object and ViewableData property access.
* Improved Shortcode API to allow for custom tag parsing in CMS content
* More fine-grained permission control for translators
* Improved unit test execution speed, increased number of tests cases by 30%
* Better XSS security of the autologin token by using HTTPOnly cookies, more secure brute force login restrictions
* Decreased memory usage in "Files & Images" section
* Support for SQLite and PostgreSQL databases (via separate module)
* Partial caching in templates, to allow for faster load times of certain aspects in dynamic pages.
* Upload controls in the CMS no longer require the Adobe Flash plugin, and work again on Mac OSX.
* File and page dropdown selections support inline searching, to make handling larger tree structures easier.
* Fixed password hashing design flaw, which makes SilverStripe databases more portable between different server architectures.
* Improved reporting API to unify the CMS sidebar reports and full-page reports on their own section. Its easier to add custom filters to reports.
* Batch action handling handles larger tree structures, provides better visual feedback, and respects permissions on individual pages.
* Global site configuration is translatable, meaning titles for your website can be in different languages without any switching in your templates.
* Allow selection of themes through the site configuration interface (in addition to changing the theme via configuration code)
* More fine-grained translation permissions: A group can be limited to only edit a certain language in the CMS.
* Added dropdown to choose from existing anchor links when inserting a link from the CMS sidebar.
* Team members can get permissions to see the draft version of a page in preview mode without requiring CMS access.
* Pages of type "Virtual Page" have improved stability in regards to their permission control, translation and publication.
* Improved broken link detection (''talk to Andy for more info'')
* Removed the jsparty/ toplevel folder, and moved all its dependencies into sapphire/thirdparty and cms/thirdparty
* More than 350 bugfix and enhancement commits, and 200 minor changes.
## Upgrading
In preparation for the pending release of 2.4.0 the following page contains all the information you need to know about
the changes that have been undertaken.
This page **doesn't include new features of 2.4.0** as such, just functionality that has changed or been removed since
2.3.
Before you start upgrading you should always backup your site directory and the database. Once you have a backup made
remove the `cms/`, `sapphire/` and `jsparty/` folders then copy in the new `cms/` and `sapphire/` folders from
your 2.4 download.
### Removed jsparty
The rather unorganised top level `jsparty/` folder has been removed from the core distribution and files separated to `cms/thirdparty` and `sapphire/thirdparty`. If your custom code referred to files in `jsparty` you will have to
update the links to the new location (either `sapphire/thirdparty/` or `cms/thirdparty/`).
Thirdparty files which aren't used in any core features have also been removed such as jquery-validate. If you reference
any files at all from `jsparty` you should double check your paths.
### Removed Classes
As part of our effort to tidy the core product we have removed several classes which we believed didn't warrant
inclusion in the official release. They either were out of date functionality or superseded or just didn't justify
inclusion. Where needed we have moved the files to individual modules. Also note several field types which were due for
deprecating have been kept due to use within the CMS (''UniqueTextField'', `UniqueRestrictedTextField`). These however
are going to be removed for the next major release.
| Class name | | Comment |
| ---------- | | ------- |
| `AjaxFormAction` | | |
| `BankAccountField` | | moved to [formfields_nz](http://open.silverstripe.org/browser/modules/formfields_nz) module |
| `CalendarDateField` | | use `DateField` with ''setConfig('showcalendar', true)'', moved to [legacydatetimefields](http://open.silverstripe.org/browser/modules/legacydatetimefields/trunk) module |
| `CompositeDateField`, `DMYDateField` | | use `DateField` with ''setConfig('dmyfields', true)'', moved to [legacydatetimefields](http://open.silverstripe.org/browser/modules/legacydatetimefields/trunk) module |
| `ConfirmedFormAction` | | |
| `DMYDateField` | | |
| `DropdownTimeField` | | use `TimeField` with ''setConfig('showdropdown', true)'', moved to [legacydatetimefields](http://open.silverstripe.org/browser/modules/legacydatetimefields/trunk) module |
| `Email_Template` | | use `Email` instead |
| `GhostPage` | | |
| `GSTNumberField` | | moved to [formfields_nz](http://open.silverstripe.org/browser/modules/formfields_nz) module |
| `HiddenFieldGroup` | | |
| `PDODatabase` | | |
| `PermissionDropdownField` | | |
| `PopupDateTimeField` | | use `DatetimeField`, moved to [legacydatetimefields](http://open.silverstripe.org/browser/modules/legacydatetimefields/trunk) module |
| `ReportField` | | |
| `TypeDropdown` | | |
Some date/time field implementations were completely refactored, and their old implementations moved to the
[legacydatetimefields](http://open.silverstripe.org/browser/modules/legacydatetimefields/trunk) module:
| Class name | | Comment |
| ---------- | |------- |
| `LegacyDateField` | | old version of `DateField`, renamed to avoid conflicts with new `DateField` |
| `LegacyTimeField` | | old version of `TimeField`, renamed to avoid conflicts with new `TimeField` |
### Removed SWFUpload
SWFUpload has been removed from the core package due to ongoing issues with supporting it. The CMS Content Editors
upload has been rewritten to use jQuery so no 2.3 functionality has been lost but if your module made use of this
library, then you will need to bundle it within your module. Related files which have been removed as a side effect of
this - `Upload.js`, `TinyMCEImageEnhancements.js`, `SWF_Upload.js` and `CMSMain_Upload.js`.
### Renamed Classes
We undertook some major work to reduce classname conflicts. Some classes have been namespaced with 'SS' to reduce
conflicts with other code. A couple notes - even though the classes have been renamed to `SS_`<ClassName>` the class is
still contained within the `ClassName.php'' file (no `SS_` prefix)
| Original class name | | New class name |
| ------------------- | | -------------- |
| `Report` | | `SS_Report` |
| `HTTPRequest` | | `SS_HTTPRequest` |
| `HTTPResponse` | | `SS_HTTPResponse` |
| `HTTPResponse_Exception` | | `SS_HTTPResponse_Exception` |
| `Database` | | `SS_Database` |
| `Query` | | `SS_Query` |
| `SSDateTime` | | `SS_Datetime` |
| `Backtrace` | | `SS_Backtrace` |
| `Cli` | | `SS_Cli` |
| `Log` | | `SS_Log` |
| `LogEmailWriter` | | `SS_LogEmailWriter` |
| `LogErrorEmailFormatter` | | `SS_LogErrorEmailFormatter` |
| `LogErrorFileFormatter` | | `SS_LogErrorFileFormatter` |
| `LogFileWriter` | | `SS_LogFileWriter` |
| `ZendLog` | | `SS_ZendLog` |
| `HTMLValue` | | `SS_HTMLValue` |
### Nested URLs enabled by default
When using our installer, the "nested URLs" feature will be enabled by default by a setting in *mysite/_config.php* (see
[blog
post](http://www.silverstripe.org/preview-of-silverstripe-2-4-hierarchical-urls-a-developer-community-contribution/)).
You can enable it manually for existing websites. Existing URLs will automatically change to the nested format without
republication (your old URLs should redirect automatically).
:::php
SiteTree::enable_nested_urls();
### SiteTree->Link() instead of SiteTree->URLSegment
Relating to the "nested URLs" feature, all *SiteTree* URLs should be accessed via *SiteTree->Link()* instead of using
the property *SiteTree->URLSegment* directly.
### Removed SiteTree::$add_action
`$add_action` on Pages has been removed. If you want to define your own custom title for pages then you use
"`<myclassname>`.TITLE" in the i18n language tables instead or define your add action using `singular_name()`
:::php
// using the lang tables
$lang['en_US']['RedirectorPage']['TITLE'] = "Redirector Page";
// using singular_name()
function singular_name() { return "Redirector Page"; }
### Removed dev/reset
Use `dev/tests/startsession` to create a new temporary database, or custom database tools like phpMyAdmin to
completely drop a database.
### Registering reports through SS_Report::register()
Removed `ReportAdmin->getReportClassNames()` in favour of `SS_Report::register()` to add custom reports to the CMS
(see [r98175](http://open.silverstripe.org/changeset/98175), [r98215](http://open.silverstripe.org/changeset/98215))
:::php
// in your _config file
SS_Report::register("SideReport", "SideReport_NameOfReport");
### Fulltext Search and Indexes disabled by default
As of SilverStripe 2.4.0, no search engine is included by default. If you want to use a search engine, you should
enable it with this command in your _config.php:
:::php
FulltextSearchable::enable();
This will add a *SearchForm()* and *results()* method in your *Page_Controller*, as well as set up common fields
like SiteTree.Content to be indexed.
Note: Results may vary with database drivers other than *MySQLDatabase*.
### Object Extension Instances
When working with extension instances directly on the extended object, please use the new *getExtensionInstances()*
getter. You need to manually call *setOwner($this)* before using the instance.
Base setup:
:::php
class MyExtension extends Extension {
function myExtensionMethod() { // ... }
}
Object::add_extension('MyObject', 'MyExtension');
Wrong:
:::php
class MyObject extends DataObject {
function myExtensionMethod() {
$ext = $this->extension_instances['MyExtension'];
return $ext->myExtensionMethod();
}
}
Right:
:::php
class MyObject extends DataObject {
function myExtensionMethod() {
$ext = $this->getExtensionInstance('MyExtension');
$ext->setOwner($this);
$ext->myExtensionMethod();
}
}
### HTMLEditorField (TinyMCE) stores content as UTF8 instead of HTML Entities
Prior to 2.4.0, the TinyMCE JavaScript library would store a subset of special characters as HTML entities (see [TinyMCE
Configuration](http://wiki.moxiecode.com/index.php/TinyMCE:Configuration/entities)). SilverStripe expects UTF8 for user
input in the CMS, database storage as well as output. We have made this behaviour more consistent by converting the
TinyMCE entities back into UTF8 for database storage.
### MySQL character set to UTF8 on new installations
The MySQL character set for SilverStripe used to be the database default (often "latin1", sometimes "utf8"). While all
textual database columns created by SilverStripe have been storing their content as "utf8" already in earlier releases,
MySQL fulltext search might not return the desired results with special characters (see
[#3582](http://open.silverstripe.org/ticket/3582)).
For new installations with a MySQL database backend, this will be set automatically to "utf8" by the installer in
*mysite/_config.php*. For existing sites built with SilverStripe 2.3, add the following code to your
*mysite/_config.php*.
:::php
MySQLDatabase::set_connection_charset('utf8');
No conversion of existing database schemas or content should be necessary.
### MySQL 5.0+ or newer required
See [server-requirements](/installation/server-requirements).
### BASE_PATH constant
Use `BASE_PATH` and `BASE_URL` instead of data from `$_SERVER` to calculate the base script path.
### Interface Change: "Site Content" tab renamed to "Pages"
The headlines of the left-hand tree panels have been changed accordingly.
### Data Migration: Files and Images
Existing files and images inside the Assets folder may not be displayed when you visit the 'Files & Images' tab in the
CMS. If you get an error message when clicking through the folders in the site tree, this can be resolved by deleting
the content in the 'File' table in the database, and then clicking the 'Look for new files' button.
### Data Migration: User-defined forms
If you get errors in the User-define forms module, check that there is no column called 'CustomParameter' present in
either of the 'EditableFormField', 'EditableFormField_Live' or 'EditableFormField_versions' tables.
You need to login to your database management system (for example phpmyadmin) and delete the 'CustomParameter' column
from the EditableFormField table.
## Changelog
### Features and Enhancements
* [rev:104093] Add dev/build/defaults to call requireDefaultRecords
* [rev:103730] use FileSystem class to create cache directory to unsure the right permissions are set
* [rev:103710] MemberLoginForm::performLogin() now uses the authenticator_class variable set in subclasses of MemberLoginForm, without having to overload performLogin()
* [rev:103708] create cache directory when it does not exist before running the cache build test
* [rev:103581] Added i18n::set_default_locale() to set standard locale (which is different from "current locale" retrieved through i18n::get_locale())
* [rev:103466] make the getTree ajax call more generic so it get local from its containing form, rather than hard-coded "Form_EditForm_Locale" cos the field is not only used in "EditForm"
* [rev:103465] to make the FileIFrameField and TreeSelectionField easy to use in CMS with Translatable on.
* [rev:103328] Automatically checking all "CMS section" checkboxes in PermissionCheckboxSetField.js when "Access to all CMS interfaces" is selected. Saving these permissions individually also resolves certain edge cases like #5438.
* [rev:103250] added tests for checking the change password functionality, including the resulting redirection (from #5420)
* [rev:103229] allow ChangePasswordForm to redirect to BackURL (from #5420)
* [rev:103198] allow onAfterPublish and onBeforePublish handlers directly on Page classes (#5112)
* [rev:103047] allow to check for any changed fields on the DataObject, this is expected behaviour when isChanged function is called without parameters (#5421, patch by walec51)
* [rev:102899] added language (Ticket #5390)
* [rev:101871] Updated automatic regression tests (Salad)
* [rev:101670] RedirectorPage ExternalURL field now defaults to http:// to be consistent with the "Another website" option for HtmlEditorField LinkForm
* [rev:101661] tidied up installer process to streamline process. Moved requirements to top and button to bottom and added visual seperation of the individual steps
* [rev:101381] refactored requirements section to hide successful tests
* [rev:101378] Added links to installation introduction text for sources of help and suggested web hosts
* [rev:101246] Improved wording and styling in installer. Added links to server requirements, themes download, tutorial. Decreased vertical space before the "install" button to make it more obvious.
* [rev:101127] Added 'Dependent pages' tab to CMS, to show virtuals, redirectors, and backlinks that point to this page.
* [rev:101054] Allowing SQLite selection in installer
* [rev:101054] Moved all Javascript containedin install.php and config-form.html to install.js, and using jQuery to simplify logic
* [rev:101054] Allow installer to attach custom form fields based on the install driver (as defined in _register_database.php)
* [rev:100989] If no arguments specified for cli-script.php/sake, then provide a friendly message to the user on where to get help
* [rev:100966] MoneyField currency dropdown can be made from an associate array like array('NZD'=>'New Zealand Dollor', 'USD'=>"United States Dollor') as well
* [rev:100940] Added help text for "locale" setting in installer
* [rev:100937] Redirecting to translated page when original is requested with a 'locale' GET parameter (e.g. 'about-us/?locale=de_DE' will redirect to 'ueber-uns' with a 301 HTTP response). Implemented in ContentController->handleRequest(). (see #5001)
* [rev:100908] Added DatabaseAdapterRegistry::unregister() to remove a database from the registry
* [rev:100902] Added _register_database.php to sapphire which sets the SS provided databases for DatabaseAdapterRegistry
* [rev:100893] Added Hebrew (he_IL) language to sapphire (thanks Oren, Yotam, tzvika, Amir, ohad)
* [rev:100893] Added Lithuanian (lt_LT) language to sapphire (thanks Irmantas, Mindaugas, Donatas, Andrius)
* [rev:100892] Added Hebrew (he_IL) language to cms (thanks Oren, Yotam, tzvika, Amir, ohad)
* [rev:100892] Added Lithuanian (lt_LT) language to cms (thanks Irmantas, Mindaugas, Donatas, Andrius)
* [rev:100884] Using jquery.live instead of livequery for SelectionGroup.js
* [rev:100852] Updated jquery.ondemand.js to sapphire trunk version, to ensure compatibility with jQuery 1.4.2
* [rev:100849] Only defining document.getElementsByClassName() in prototype.js if no native implementation exists (which speeds up the CMS). Ported from 'jquery13' module, thanks Hamish
* [rev:100847] Updated jquery.livequery from v1.0.2 to v1.1.1 (located in sapphire/thirdparty/jquery-livequery/
* [rev:100846] Updated jquery.metadata from ~v.1.0 to v2.1 (located in sapphire/thirdparty/jquery-metadata
* [rev:100845] Updated jQuery.form library from v2.08 to v2.40 (located in sapphire/thirdparty/jquery-form
* [rev:100844] Updated jQuery library from v1.2.6 to v1.4.2 (located in sapphire/thirdparty/jquery/
* [rev:100799] Creating default "Content Authors" group with limited rights if no other groups exist.
* [rev:100776] Better editing of roles through SecurityAdmin instead of a new "Roles" tab. Removed (previously unreleased) PermissionRoleAdmin. (see #4757)
* [rev:100774] Allowing custom popup requirements in ComplexTableField without subclassing through $requirementsForPopupCallback
* [rev:100771] Respecting SecurityAdmin::$hidden_permissions in PermissionRole->getCMSFields()
* [rev:100769] you can now choose your site locale at install time
* [rev:100753] Added 'updateImageForm', 'updateFlashForm', 'updateLinkForm' hooks to HtmlEditorField (the imageform hook was necessary to make the 'pixlr' module work) (see #3938)
* [rev:100696] show all database systems we support, along with messages if the user cannot use them. Also allow 3rd parties to register their own database classes to appear in this list.
* [rev:100536] Stored combined files in assets/_combinedfiles by default
* [rev:100529] Combined files now live in assets/.combinedfiles by default
* [rev:100528] #3387 Requirements now has a new static function called Requirements::set_combined_files_folder() for setting where the combined files should belong
* [rev:100453] #4599 DataObjectSet now uses more array functions instead of performing equivalent tasks - thanks simon_w!
* [rev:100423] Convert JSON functions now use the Services_JSON library where appropriate instead of custom code, and if json_decode() or json_encode() are available these are used
* [rev:100400] #5072 RSSFeed_Entry::rssField() now respects custom getters on the data class
* [rev:100327] allow ordering of page commented to be configurabled
* [rev:100058] AssetAdmin now uses Upload_Validator instead of setting the rules directly on Upload
* [rev:99954] you can now do coverage tests of single/multiple tests, or entire modules
* [rev:99942] fixed forward button underneath result form
* [rev:99929] #4787 Widget now respects updateCMSFields on extension classes so additional fields can be add (or existing ones removed)
* [rev:99845] #4043 Allow setting the from address for debug information in SS_LogEmailWriter - thanks Hamish!
* [rev:99841] #5024 Installer now checks that the user has entered a username and password correctly for the default admin, an additional button for re-checking requirements is now found at the bottom of the admin configuration section
* [rev:99841] Error messages for database AND admin configuration are now in the same place at the top of the installer
* [rev:99737] Allow DataObjectSet to remove duplicates based on any field (#5094, thanks mobiusnz) (from r99736)
* [rev:99692] Disabling/checking permission checkboxes in admin/security when 'ADMIN' permission is selected
* [rev:99690] Saving group relations on SecurityAdmin->EditForm()/RootForm() through TreeMultiselectField instead of hidden 'Group'/'GroupID' values (from r99579)
* [rev:99688] Saving MemberTableField through new 'Groups' field added in Member->getCMSFields(). (from r98882)
* [rev:99679] added new PageCommnet to yml so we have different amounts of moderated/unmodereated
* [rev:99677] Making setting optional in MemberTableField. Field instances without will list all members unfiltered, and remove members from the database rather than the group relation.
* [rev:99677] Allow disabling of 'inline add' formfields in a MemberTableField through setPermissions(array('inlineadd')) (from r98825)
* [rev:99667] Only show 'HTML Editor Config' dropdown in Group->getCMSFields() if more than one option exists
* [rev:99666] Showing checkboxes as disabled for inherited roles in Group->getCMSFields() (from r99597)
* [rev:99664] Added OptionsetField->setDisabledItems() to allow specifically disabling certain checkboxes
* [rev:99664] Added CheckboxSetField->setDefaultItems() to tick specified checkboxes regardless of the value passed (from r99596)
* [rev:99662] Showing (readonly) permissions for a Member record in admin/security popup (from r99586)
* [rev:99660] PermissionCheckboxSetField_Readonly (with all checkboxes disabled)
* [rev:99660] Added 'assigned to...' label to group permissions in PermissionCheckboxSetField - used in Member->getCMSFields() readonly permission view (from r99585)
* [rev:99658] Allowing PermissionCheckboxSetField to inspect multiple group records for existing permissions (from r99584)
* [rev:99648] View and select groups for a specific member via the member popup in admin/security (requires EDIT_PERMISSIONS) (from r98880)
* [rev:99361] Allow locale/dateformat specific reordering of day, month, year input fields in DateField
* [rev:99360] New DatetimeField class (form field wrapper composed of DateField andTimeField)
* [rev:99360] New DateField and TimeField form classes with more consistent API and easier localization
* [rev:99360] Using Zend_Date for DateField and TimeField, with more robust date handling, starting localization support. Set globally via i18n::set_locale(), or for a field instance through setLocale(). Note: Javascript validation is not localized yet.
* [rev:99302] SiteTree::batch_permission_check() populates its own cache (from r97900)
* [rev:99117] set file metadata on upload. (from r97780)
* [rev:99106] set file metadata on upload. (from r97780)
* [rev:99088] Add close link (from r97751)
* [rev:99080] Add Link to silverstripe navigator (from r97407)
* [rev:99069] added PageComment for CommentAdminTest
* [rev:99066] CommentAdmin unitest
* [rev:99047] Make navigator items more overloadable (from r97376)
* [rev:99046] Refactor links in $SilverStripeNavigator so modules can add extras (from r97299)
* [rev:98756] Added help texts for MemberImportForm and GroupImportForm (merged and rewritten from r98750)
* [rev:98737] Allow extension of LeftAndMain->getEditForm() (and subclasses) through a new updateEditForm() hook (see r98736 for additions to AssetAdmin and CMSMain)
* [rev:98736] Import groups from CSV in admin/security through the new GroupImportForm class (and GroupCsvBulkLoader) (merged and rewritten from r98711)
* [rev:98735] Allowing custom 'root forms' when id values '0' or 'root' are passed from the tree selection. (rewritten from r98710)
* [rev:98732] Import members and their group assignments from CSV in admin/security through the new MemberImportForm class (merged from r98708)
* [rev:98715] Added GroupCsvBulkLoader class to facilitate group imports with permission codes and hierarchy (merged from r94252)
* [rev:98714] MemberCsvBulkLoader for easy member import with group associations (merged from r94251)
* [rev:98713] Added BulkLoader->deleteExistingRecords(), removed unnecessary parameters from BulkLoader->load() (merged from r94250)
* [rev:98713] Decreased memory usage in BulkLoader->load() when deleting all records before importing (merged from r94250)
* [rev:98677] Added checkbox to switch off using the environment during install if it's available
* [rev:98659] #3903 Initial changes to installer to support selection of different database drivers
* [rev:98656] you can now pass arbitrary CURL options to the request() method of RestfulService.
* [rev:98469] Add HTMLCleaner abstract class, and Diff::cleanHTML()
* [rev:98428] Allow overriding TableListField_Item on TableListField by setting the property itemClass
* [rev:98268] Moved the log-in validation process from individual authenticators into Member->checkPassword() and canLogIn(), to allow more extensibility and control (trunk, 2.4).
* [rev:98219] roll batch permissions in to a generic function (from r97748)
* [rev:98211] batchactions can now implement confirmationDialog() to provide a custom confirmation dialog to the front end.
* [rev:98180] Allow for custom generation of SSReport::ID() for parameterised reports.
* [rev:98179] Removed broken links reports from sidebar (in anticipation of adding them to the main reporting area) (from r95954)
* [rev:98173] Improved look and feel for report filtering
* [rev:98165] Performance improvement to CMS load time with many pages. (from r95490)
* [rev:98159] added canAddTopLevel permission to SiteConfig to determine which users/groups can add pages to the root of the sitetree. (from r87279)
* [rev:98156] audit trails
* [rev:98156] ability to parameterize SSReport's (from r85903)
* [rev:98132] Allow sort descending as well as ascending. (from r96054)
* [rev:98110] Allow user theme selection through SiteConfig, falling back to SSViewer::set_theme() as a default if there are none selected
* [rev:98104] Improved TableListField header styling. (from r96028)
* [rev:98102] Add a function to give link to Live site (from r95948)
* [rev:98091] ManifestBuilder::get_manifest_info() now uses ManifestBuilder::get_themes() instead of doing it's own retrieval of available themes
* [rev:98080] Removed dev/reset, instead encouraging the use of dev/tests/startsession for tests.
* [rev:98080] Let people use dev/tests/startsession without a fixture, instead calling requireDefaultRecords
* [rev:98041] added support for MySQL data type SET used in MultiEnum FEATURE: added datetime helper functions
* [rev:98025] add 'view site tree as' functionality.
* [rev:97896] 2.4 tickets (#4670) new permission code to view draft w/o CMS access
* [rev:97895] 2.4 tickets (#4670), new permission code to view draft stage w/o CMS access
* [rev:97819] Allow ungrouped retrieval of Permission::get_codes() through new $grouped switch
* [rev:97793] removed the situation, when the user is left with empty search box and empty dropdown.
* [rev:97792] use Validator::get_javascript_validator_handler() to check if the handler is turned on before doing either js or php validation
* [rev:97765] Select the uploaded image after uploading by default. #4962
* [rev:97745] adapt the page dropdown based off the allowedChildren values
* [rev:97606] Added hover states to "Available widgets" boxes in the CMS for usability
* [rev:97602] Added visual elements to aid in the usability of the WidgetAreaEditor
* [rev:97601] CMS Editor Upload panel now loads the root files directly and allows the user to upload to the root assets dir
* [rev:97597] Changed menu title from "Site Content" to "Pages" to be consistent with other menu labels
* [rev:97597] Changed tree root node in CMS to get title from SiteConfig rather than defaulting to "Site Content"
* [rev:97597] Changed tree panel headline in CMS from "Site Content and Structure" to "Page Tree" to stay consistent with new CMS menu title
* [rev:97583] Don't set up the test db if database tests aren't being run. From: Sam Minnee
* [rev:97530] Adjusted "Available Widgets" column to be narrower than "Widgets currently used", allowing more space for configuring widgets
* [rev:97478] Member->requireDefaultRecords() no longer creates a default administrator based on $_REQUEST data. Moved functionality into Installer->install()
* [rev:97436] Updated Member->getMemberFormFields() to use scaffolding and to be in line with Member->getCMSFields(). From: Andrew Short (from r97401)
* [rev:97391] Add partial caching support to SSViewer.
* [rev:97390] Add aggregate calculation to DataObject, allowing (cached) calculation of Max, Min, Count, Avg, etc
* [rev:97389] Add cache factory that provides nice API over top of Zend_Cache
* [rev:97370] Allowing translation of SiteConfig (including toplevel permission groups)
* [rev:97207] Added ContentController->ContentLocale() to allow XHTML/HTML specific lang= attribute settings in custom template code (see #4858). Removed `<meta http-equiv="Content-Language"...>` tag in SiteTree->MetaTags().
* [rev:97207] Updated blackcandy theme to use new $ContentLocale attribute to set the locale of the current page (in Page.ss)
* [rev:97192] Added RestfulService::set_default_proxy() and RestfulService->setProxy() (#4637, thanks hamish)
* [rev:97031] upgrading the search functionality of the TreeDropdownTree with pluggable search function
* [rev:97028] include menu title in default search. PATCH via lubzee #4508
* [rev:97024] added Session::clearAll() functionality. ENHANCEMENT: Added Unit Tests covering Session API. MINOR: Tided up formatting in session class and included doc comments for API level documentation
* [rev:97018] Use tidied HTML in DataDifferencer
* [rev:97017] Try to tidy HTML using external libraries if available
* [rev:97011] Added TabIndex to FormActions. Ticket: #4905. PATCH: via keeny
* [rev:96821] Added applicable pages checks to delete from live, delete from draft, and publish (from r94775)
* [rev:96820] Added 'greyed out' status of batch action checkboxes while applicable pages are being loaded via ajax. (from r94774)
* [rev:96819] Update the checkboxes available to batch-actions to show only the applicable pages for that particular action.
* [rev:96800] Let LeftAndMain subclass canView() methods optionally redirect. (from r90018)
* [rev:96793] Renamed Author column to User in the page version history to better reflect that they might not have been authors, and just iniators of workflow actions. (from r89015)
* [rev:96792] Added new onRenameLinkAsset() handler to static publishing for better link rewriting. (from r89014)
* [rev:96778] Files and images section warns if you are deleting a file that is linked to
* [rev:96752] Recognise HTTP_X_FORWARDED_HOST header and use that in place of HTTP_HOST (from r93148)
* [rev:96668] Change to TreeDropdownField, giving it filtering behaviour as described in ticket http://open.silverstripe.org/ticket/3007 . Its disabled by default for legacy compatibility, but enabled for HtmlEditorField so that link editor is filterable for local links, via an extra boolean parameter on TreeDowndownField.
* [rev:96440] Add onLoad callback handler CMSLoadFunctions
* [rev:96049] Added Date::Rfc3339() for returning an RFC 3339 valid date format (from r96010)
* [rev:95418] added delete all link to page comments. Patch via #4427. Thanks walec51
* [rev:95194] added translatable support to mathspamprotection. PATCH via noini (#4755)
* [rev:94887] added several tests for PermissionCheckboxSetField, PermissionRole and Group
* [rev:94515] Improved layout of altercation message when called via CLI. Patch via simon_w #4373
* [rev:94423] Allow passing in an Exception object to SS_Log::log() in addition to an array describing the error context (line number, file, trace etc)
* [rev:94381] Added FunctionalTest::findAttribute() as a helper for getting an attribute from a SimpleXMLElement object by it's name
* [rev:94297] Added DataObjectSet::emptyItems() to remove all the items from the set - this is useful for when you are augmenting CMS and front end fields via updateCMSFields() and updateFrontEndFields() on a DataObjectDecorator
* [rev:94063] Added MultipleOf and Modulus methods to ViewableData - useful for templating work
* [rev:94062] Loading of tinymce_ssbuttons plugin via relative paths in HtmlEditorConfig rather than using the plugin name as a path spec (see r94060)
* [rev:94060] Added support for loading external plugins (with relative paths) in HtmlEditorConfig. This means relative paths can be separate from the plugin name, and fixes a bug where paths containing dashes were ignored by TinyMCE.init().
* [rev:94060] Changed sapphire/thirdparty/tinymce-advcode to use the original plugin name, and specify its relative path through HtmlEditorConfig instead.
* [rev:93771] Added parameter to DBLocale->Nice()
* [rev:93771] Added DBLocale->getNativeName()
* [rev:92879] Allowing to hide certain permission from showing in SecurityAdmin? through add_hidden_permission() (refactored from r92428) (from r92866)
* [rev:91576] Pluggable password encryption through PasswordEncryptor class (#3665) (merged from r90949)
* [rev:91496] added ability to upload images from site content pane. Merged via r9130, r91347, r91350, r91480
* [rev:91044] Added Session::destroy() as a means to remove the current session using session_destroy()
* [rev:91044] Added optional $sid parameter to Session::start() to start the session using an existing session ID
### API Changes
* [rev:103792] changed the modulus offset to 1 to correctly order sets
* [rev:102012] Changed MySQLFulltextSearchable class to FulltextSearchable (applies to all databases)
* [rev:102003] Disallow methods/actions in RequestHandler->checkAccessAction() which are implemented on parent classes (e.g. ViewableData and Object), unless access is controlled through $allowed_actions. This limits information exposure from getters used in template contexts.
* [rev:101833] Allow cached blocks within control and if blocks, as long as that control or if block is contained within an uncached block, not a cached block
* [rev:101155] Add option for DataObjectDecorator::onAfterSkippedWrite()
* [rev:101137] Partial cache adjustments - now supports nested cache blocks (which are independant of their containing cache block), conditionals to control if a given cache block is active, and includes hash of template code in key (so template changes mean cache is invalidated). Changes template control for cache block to `<% cached %>`, to which the now deprecated `<% cacheblock %>` is aliased, and an additional template control `<% uncached %>` has been added.
* [rev:101127] Added SiteTree::VirtualPages() and SiteTree::DependentPages() accessors.
* [rev:101119] Allow on_db_reset() methods on DataObjects as well as DataObjectDecortators
* [rev:101093] Replaced eval based creation of extension and field objects with Object::create_from_string().
* [rev:101093] Introduced new function Object::create_from_string() to instantiate an object from a string like 'Int(50)'
* [rev:101044] Made MySQL fulltext search optional, activated with MySQLFulltextSearchable::enable()
* [rev:101043] Pass the full extension string as the 2nd argument to DataObjectDecorator::extraStatics()
* [rev:100842] Upgraded jQuery UI from v1.6rc1 (r687) to v1.8rc3. This release prefixes all *.js and *.css files with 'jquery', so ui.core.js is now called jquery.ui.core.js.
* [rev:100842] Upgraded jQuery UI themes from v1.6rc1 to v1.8rc3. Removed 'flora' and 'default' themes, replaced with the 'base' and 'smoothness' themes found in the default distribution
* [rev:100718] Removed "auto-merging" of member records from Member->onBeforeWrite() due to security reasons - please use DataObject->merge() explicitly if this is desired behaviour (from r100705)
* [rev:100651] dbDataType function created
* [rev:100513] Refactored Requirements to use Requirements_Backend at all times - this makes testing far easier. Thanks tobych!
* [rev:100512] TreeDropdownField no longer requires your object to have the Hierarchy extension
* [rev:100503] Removed deprecated Email_Template class, please use Email instead!
* [rev:100498] Removed deprecated Image::loadUploaded() (deprecated from the parent::loadUploaded for which it called), please use Upload directly instead!
* [rev:100495] Removed deprecated File::loadUploaded(), please use Upload directly instead!
* [rev:100493] Removed deprecated function RootURLController::get_homepage_urlsegment(), please use RootURLController::get_homepage_link() instead!
* [rev:100492] Removed deprecated function SiteTree::get_by_url(), please use SiteTree::get_by_link() instead!
* [rev:100490] Removed deprecated methods DataObjectSet::filter_map() and DataObjectSet::map_multiple() - please use map() instead!
* [rev:100057] #5107 Upload now uses Upload_Validator to separate the validation rules from the File loading done in the Upload class
* [rev:99849] SiteTree::validURLSegment extendable (#5907)
* [rev:99360] Date/time parsing in DateField, TimeField and DatetimeField defaults to i18n::get_locale() ('en_US') instead of using en_NZ/en_GB specific parsing. Use i18n::set_locale('en_NZ') in mysite/_config.php to revert to old behaviour.
* [rev:99360] $timeformat constructor parameter in TimeField needs to be in ISO date notation (not PHP's date())
* [rev:99360] TimeField, DateField and related subclasses use Zend_Date for date parsing, meaning they're stricer than the previously used strtotime()
* [rev:99360] Removed DMYCalendarDateField and CalendarDateField, use DateField with setConfig('showcalendar')
* [rev:99360] Removed CompositeDateField, DMYDateField, use DateField with setConfig('dmyfields')
* [rev:99360] Removed DropdownTimeField, use TimeField with setConfig('showdropdown')
* [rev:99360] Removed PopupDateTimeField, use DatetimeField
* [rev:99360] Changed 'date', 'month' and 'year' HTML field names to lowercase in DMYDateField
* [rev:99360] Removed support for ambiguous date formats in DateField, e.g. '06/03/03'. Use DateField->setConfig('dateformat', `<format>`) to revert to this behaviour.
* [rev:99360] Removed $futureOnly flag from DateField, CalendarDateField etc., use DateField->setConfig('min') and DateField->setConfig('max')
* [rev:99119] Refactor Versioned so a single state is kept for stage, archived date, or any module specific reading modes (from r98161)
* [rev:99114] Use the same navigator items in the CMS that are used on the frontend (from r97395)
* [rev:99079] Use the same navigator items in the CMS that are used on the frontend (from r97395)
* [rev:99063] Let sitetree extensions prepopulate permisson cache for their own permissions. (from r98650)
* [rev:99051] Let any DataObjectDecorator define an on_db_reset() method that is called by tests, like in Versioned. (from r97734)
* [rev:98786] Installer now uses a database configuration helper class which isolates the logic of checking the database away from the installer, this interface can be used by other databases like MSSQL and PostgreSQL. The installer now looks for a specific file inside each database module, provided it's configured in install.php MySQL is provided by default, as it lives in sapphire
* [rev:98543] Made ComplexTableField not use Object::create() for item and popup classes to be consistent with TableListField. These can be overridden as itemClass and popupClass are public properties on ComplexTableField
* [rev:98373] HTTP::setGetVar() always returns absolute URLs. Use Director::makeRelative() to make them relative again.
* [rev:98373] HTTP::setGetVar() combines any GET parameters in PHP array notation (e.g. "foo[bar]=val") instead of replacing the whole array
* [rev:98224] Refactor Versioned so a single state is kept for stage, archived date, or any module specific reading modes (from r98161)
* [rev:98215] Introduced new API for SS_Report
* [rev:98191] Added SideReportWrapper to help you tailor report columns for the side reports.
* [rev:98191] Allow use of 'casting' option on side report columns.
* [rev:98191] Make 'title' optional on side report columns. (from r96272)
* [rev:98176] Removed SideReport class, use SSReport as the base-class for them instead.
* [rev:98176] Use SSReport::register(SideReport) to explicitly register reports on the LHS of the content view.
* [rev:98175] Added explicit registration of reports with SSReport::register() (from r95857)
* [rev:98159] Security::permissionFailure(); will no longer tell the client side JS to show the login box if the user is already logged in
* [rev:98101] Allow passing of an explicit map of dropdown items to a TreeDropdownField.
* [rev:98096] Refactored test for whether a SQLQuery can be sorted by a particular column into SQLQuery::canSortBy($fieldName) (from r95850)
* [rev:98056] Decimal now allows setting a default value properly
* [rev:97996] rename the class "Cache" to "SS_Cache" (ref ticket: #4997)
* [rev:97827] Added cancelSchemaUpdate() and doesSchemaNeedUpdating() to the Database class
* [rev:97819] Removed $blankItemText parameter from Permission::get_codes()
* [rev:97818] Removed Member::init_db_fields(), its no longer needed due to the Member.PasswordEncyrption property changing from an ENUM to Varchar.
* [rev:97797] Fixed i18n _t() calls without namespaces in template includes: They now default to setting the include filename as namespace, rather than the including template (#4915, #3400 - thanks Henk_Poley, jwalsoe, walec51)
* [rev:97731] Determine default BASE_PATH/BASE_URL from the __FILE__ content, so that the script that initiated the Sapphire process doesn't matter. This means that index.php doesn't need to manipulate those variables.
* [rev:97582] #4929: Add $class argument to DataObjectDecorator::extraStatics()
* [rev:97489] removed SWFUpload. Refactored Content Editors uploader to use standard uploader.
* [rev:97478] Security::setDefaultAdmin() no longer writes credentials to any Member database records (created through Security::findAnAdministrator(). This prevents outdated credentials when setDefaultAdmin() code changes after creating the database record (see #4271)
* [rev:97478] Security::findAnAdministrator() no longer sets 'Email' and 'Password' properties on newly created members. Removed the $username and $password argments from the method.
* [rev:97475] Moved GSTNumberField from sapphire/forms to new 'formfields_nz' module
* [rev:97474] Moved BankAccountField from sapphire/forms to new 'formfields_nz' module
* [rev:97270] Unique_identifier now accepted as the login requirement, allowing alternatives to 'Email'
* [rev:97207] Deprecated ContentController->LangAttributes(). Use ContentLocale() instead and write attribute names suitable to XHTML/HTML templates directly in the template.
* [rev:96988] #3600 Inconsistency in File::getURL() which returns an absolute URL, when it should be relative - please use getAbsoluteURL() instead for old behaviour
* [rev:96988] #3600 Image no longer has an explicit getURL() method, instead it inherits getURL() from File which returns a relative URL
* [rev:96824] Added capability for batch actions to indicate failure through red checkboxes (from r94868)
* [rev:96823] Added canView() to CMSBatchAction so that you could hide certain batch actions from some users. (from r94846)
* [rev:96821] Added applicablePagesHelper to CMSBatchAction to ease the process of creating new applicable page methods.
* [rev:96819] Allow for an applicablePages($idArray) method to be defined on a CMSBatchAction class. (from r94761)
* [rev:96810] Added FilesystemPublisher::getExistingStaticCacheFiles(), to help build caching logic methods. (from r91354)
* [rev:96809] Added numChildrenMethod argument to LeftAndMain::getSiteTreeFor()
* [rev:96756] Added canDeleteFromLive permission to SiteTree, separate from canPublish (from r93315)
* [rev:96751] Define VirtualPage::isPublishable() so that people know not to even request publication if it's not allowed. (from r93098)
* [rev:96749] Added DataObjectDecorator::cacheKeyComponent() to ensure that the cached behind DataObject::get_one() is appropriately specific (from r93095)
* [rev:96739] Added Hierarchy::numHistoricalChildren() and Versioned::get_including_deleted_query()
* [rev:96739] Added numChildrenMethod arg to getChildrenAsUL, markPartialTree, markChildren, markingFinished
* [rev:96734] Don't generate TestOnly DataObjects in the database immediately; instead let test developers specify them in SapphireTest::$extraDataObjects.
* [rev:96734] Added SapphireTest::resetDBSchema() (from r90054)
* [rev:96727] Renamed SapphireTest::set_up_once/tear_down_once to setUpOnce/tearDownOnce, and made them instance methods.
* [rev:96727] Added SapphireTest::$illegalExtensions and SapphireTest::$requiredExtensions for making tests depending on particular extension sets (from r89958)
* [rev:96725] Moved popupdatetimefields to pop up below the text field instead of next to the icon. (from r89914)
* [rev:94430] Group::addByGroupName() now creates the group if one does not already exist (from r83010)
* [rev:94178] Renamed ViewableData->SecurityID() to getSecurityID() in order to get its value loading through Form->loadDataFrom()
* [rev:94062] Changed cms/javascript/tinymce_ssbuttons plugin name to "ssbuttons" (see r94060)
* [rev:94062] Changed cms/javascript/tinymce_ssmacron plugin name to "ssmacron" (see r94060)
* [rev:93785] removed Director::Link(). Use Controller::join_links() instead
* [rev:93693] removed deprecated RestrictedText fields
* [rev:93687] removed deprecated LeftAndMain::add_menu_item. Use CMSMenu::add_menu_item()
* [rev:93685] removed deprecated extend calls (r93632). API CHANGE: removed fieldExists(). Use hasField() (r93633). API CHANGE removed listOfFields() (r93647). API CHANGE: removed Tag() and URL() from Image. Use getTag() and getURL(). BUGFIX: updated Image.php to use getTag() (r93639, r93646). API CHANGE: removed val(). Use XML_val() (r93650). API CHANGE: removed $add_action. Use singlar_name or lang tables (r93658). API CHANGE: removed ConfirmedFormAction (r93674). API CHANGE: removed ajax_render on CTF (r93679).
* [rev:93660] Removed ComponentSet::removeByFilter() since it's not flexible enough and fixed calls to this from HtmlEditorField::saveInto() to use custom code instead
* [rev:93640] Removed deprecated static function ContentNegotiator::disable() - it's disabled by default
* [rev:92878] Refactored hiding of Permissions added in r92428. Added PermissionCheckboxSetField?->setHiddenPermissions() (from r92865)
* [rev:92428] add the ability to remove some permissions specified by their code in the rendered field html of PermissionChecksetBoxField and full-covered unit tests of this ability.
* [rev:91612] Replaced BasicAuth::enable() with BasicAuth::protect_entire_site()
* [rev:91612] BasicAuth::requireLogin() no longer has an option to automatically log you in. You can call logIn() on the object returned, instead. (from r91603)
* [rev:91576] Deprecated Security::encrypt_passwords() (merged from r90949)
* [rev:91576] Deprecated Security::$useSalt, use custom PasswordEncryptor implementation (merged from r90949)
* [rev:91576] Removed Security::get_encryption_algorithms() (merged from r90949)
* [rev:91576] MySQL-specific encyrption types 'password' and 'old_password' are no longer included by default. Use PasswordEncryptor_MySQLPassword and PasswordEncryptor_MySQLOldPassword
* [rev:91576] Built-in number of hashing algorithms has been reduced to 'none', 'md5', 'sha1'. Use PasswordEncryptor::register() and PasswordEncryptor_PHPHash to re-add others. (merged from r90949)
* [rev:91048] Added Lower and Upper methods to Varchar, Text, and Enum
* [rev:90963] Allow fieldList arguments to Form::loadDataFrom() and Form::saveInto(), for situations where the data passed only applies to a segment of the form. (from r90872)
* [rev:90962] Inserting $HiddenFields into a form template will show the input tags of all the hidden fields. (from r90871)
### Bugfixes
* [rev:104063] ViewableData->castingClass() cuts off last character of a casting definition if it has bracketed arguments (fixes #5536, thanks ajshort)
* [rev:104016] SecurityTest tests would fail on sites which had set a non-default unique identifier field for Members
* [rev:103961] Bypass static caching through static-main.php when GET or POST parameters are set (regression from 2.3 API, fixes #5519, thanks ktauber)
* [rev:103960] Fixed publication of homepage with '/' URL through StaticPublisher (fixes #5514, thanks ktauber)
* [rev:103957] Fixed Database->requireTable() for Mysql 4.1 (fixes #5517, thanks gw0)
* [rev:103936] Fixed double pragma after referer redirection on forms with Form->httpSubmission() (fixes #5509, thanks ktauber)
* [rev:103933] login BackURL wrong when using nested urls (fixes #5520, thanks ktauber)
* [rev:103932] Fixed SS_Report::unregister() parameter naming (fixes #5511, thanks ktauber)
* [rev:103912] Trimming expected output of WebserverRoutingTest (newlines before the "ok" string were causing failures on PHP 5.3)
* [rev:103910] Disabled MemoryLimitTest for environments where memory_limit can't be freely set (e.g. PHP with suhosin patch)
* [rev:103851] table and column names now quoted properly
* [rev:103803] Rebuilding test database for postgresql in SearchFormTest and TranslatableSearchFormTest to avoid stale index information in the database
* [rev:103745] static publisher for a site that resides in a subfolder of webroot
* [rev:103734] Fix linkCount .js in AssetAdmin deleteRecord (ticket #5486)
* [rev:103706] Use correct quoting for BrokenLinksReport (ticket #5474)
* [rev:103674] #5485 PermissionCheckboxSetField javascript would always uncheck all CMS_ACCESS_* permission checkboxes on initialize event
* [rev:103620] Fixed ordering by aggregate columns for DataObject::get() calls with joins.
* [rev:103613] Fixed unlimitedRowCount() for grouped queries
* [rev:103612] Ensure that group by of many-many queries with extraFields is set correctly.
* [rev:103591] ModelAsController test failed for projects which do not support nested urls. This fix stores the original configuration and enables 'nested-urls' at the beginning of the tests and reset the state in tearDown.
* [rev:103588] #5362: Fixed duplicate removal on DataObject:get() with join argument for all databases.
* [rev:103582] Choosing i18n::default_locale() in Member->populateDefaults() instead of "current locale". This fixes a bug where a new member created through admin/security automatically "inherits" the current locale settings of the admin creating it.
* [rev:103552] CSSContentParser now reports better errors by using simplexml_load_string() instead of SimpleXMLElement directly
* [rev:103519] Prevent duplicate HTML IDs in ModelAdmin
* [rev:103518] Fixed redirection in PageCommentInterface to use Link() instead of URLSegment (fixes 4200, thanks ktauber)
* [rev:103461] Renamed Nested URLs are automatically redirected to their new location with 301 HTTP status code in ModelAsController/ContentController (fixes #5393, thanks cbarberis)
* [rev:103451] Fixed CurrencyField->jsValidation() regex escaping (fixes #5462, thanks mobiusnz)
* [rev:103450] DateField with setConfig('dmyfields') now validates TRUE for empty values (fixes #5458)
* [rev:103448] Allow EDIT_SITECONFIG permission selection in admin/security (fixes #5459)
* [rev:103341] Don't show error when adding default SiteConfig records after upgrading a site.
* [rev:103336] Using try/catch in MemberTableField->saveComplexTableField() similiar to parent implementation, which means trying to save a Member duplicate doesn't end up in a fatal error (fixes #5444)
* [rev:103255] static publishing now uses the last non-null theme, OR the value defined in StaticPublisher::static_publisher_theme.
* [rev:103240] r101093 broke casting of values from the failover object. Add lookup to the failover for casting info, and add test
* [rev:103226] made the invalid password message translatable; disallow new blank password (as it makes it impossible to login); Member::checkPassword now returns ValidationResult - handle that properly (#5420, patch submitted by walec51)
* [rev:103214] the decorator was not completely removed, which caused trouble for tests running later in the same batch
* [rev:103183] default sort column now quoted
* [rev:103182] default sort column now quoted
* [rev:103127] realtime publishing now enabled by default
* [rev:103099] Only replace double slashes in SS_HTTPRequest->__construct() for relative- its a failsafe against wrongly formatted URLs like 'admin//assets' instead of 'admin/assets', but breaks absolute URLs with 'http://' prefix
* [rev:103092] disallow numeric actions - numeric array indexes are incorrectly picked up as allowed actions (#5331)
* [rev:103083] make the javascript-producing functions behave in the same way. Now they will return a javascript snippet and the caller is responsible for adding it to a FormResponse. Removes the duplication in AJAX response which happened when FormResponse::add has been used before the call to JS helper functions (#5359)
* [rev:103037] correct mollom field mapping
* [rev:103012] added optional separator for http_build_query in HTTP:setGetVar(). this fixes sorting columns in ModelAdmin (ticket #5325).
* [rev:102730] Fixing RquestHandler->checkAccessAction() on PHP 5.2 - ReflectionMethod->class returns inconsisent results in older PHP versions. (see r102003)
* [rev:102712] Fixed CTF sorting in ModelAdmin results (was failing because of missing 'ResultAssembly' GET parameters
* [rev:102686] Float should always be not null and default 0 in the database
* [rev:102545] Using i18n::get_locale() in ContentController->ContentLocale() to ensure the correct locale can be used in templates withouth Translatable enabled (broken in r97207, thanks DesignCity) (from r102544)
* [rev:102460] #5316 Float and Double should never try to save NULL as the "null" value
* [rev:102436] #5320 ManyManyComplexTableField::getQuery() now uses T-SQL compatible syntax CASE WHEN instead of IF THEN which works in multiple databases as well
* [rev:102386] delete from published site never calls canDeleteFromLive(). (via marcus #5364)
* [rev:102320] fixed invalid HTML output from page comments template
* [rev:102300] SSViewer now allows cli to do a flush on non-dev environments
* [rev:102265] Fix Salad tests
* [rev:102237] exchanged MySQL CONCAT function with ANSI compliant operator
* [rev:102160] allow HTMLEditorFields to save in SiteConfig, fixes #5246
* [rev:102156] fallback to the standard authenticator before throwing user_error as in some cases auth method is not passed back to the login form
* [rev:102094] Fixed bug with SiteTree::onBeforeWrite() that broke subsites.
* [rev:102084] #5343: Call DataObject::onBeforeWrite only once for SiteTree
* [rev:102081] #5337: Allow decoration of DataObject
* [rev:102074] Fixed SiteTree::page_type_classes() to exclude 'SiteTree' even if on array position 0 - slight difference in return values from Postgres to MySQL (fixes #5336)
* [rev:102072] Logging in with an invalid email returns no error message (fixes #5332, thanks ajshort)
* [rev:102038] #5255 LeftAndMain should include the correct editor.css file so typography from user selected theme in SiteConfig is shown in TinyMCE
* [rev:102026] Fixed SiteTree::page_type_classes() removal of base class (was broken if database driver returned classes in arbitrary order, e.g. in Postgres)
* [rev:102004] Prevent handling of controller actions which return $this avoid infinite loops in RequestHandler->handleRequest (thanks Hamish!)
* [rev:101975] Resetting image sidepanel fields when opening the panel instead of inserting an image, to avoid losing focus of TinyMCE in IE. Using getBookmark() in TinyMCE to save the original location. (fixes #5263)
* [rev:101969] Stop IE6/IE7 from redirecting in admin/assets after deleting multiple folders (fixes #5208)
* [rev:101958] Checking for existing redirections in FormResponse::respond (fixes #5208)
* [rev:101956] Fixed "object not found" javascript error in SecurityAdmin_right.js when changing group nodes (fixes #5179)
* [rev:101939] Ensure that DataObject IDs are numbers and no string equivalents of numbers - 3 not '3'
* [rev:101869] Update Salad tests to match behaviour
* [rev:101867] #4188 simon_w: Let require tags in templates be conditional
* [rev:101866] Recover if a manifestClassParse file doesn't have the necessary content.
* [rev:101812] Added allowed_actions to ContentControllerSearchExtension
* [rev:101810] #5295: Update CMS site name in LHS via Ajax after siteconfig save.
* [rev:101807] fixed undefined error in CTFs. BUGFIX: added action class to actions to allow the popup hook to open links
* [rev:101795] keep ModelAdmin from importing data twice
* [rev:101794] avoid call to non-object
* [rev:101793] preserve the port value if given in HTTP::setGetVar (#5280). BUGFIX: allow username only input rather than user:pass combo.
* [rev:101792] disable function re-enabled
* [rev:101791] deprecated split function replaced
* [rev:101758] fix #5320
* [rev:101747] Always including "Locale" field in Translatable->getCMSFields() regardless of "excluded" page types. Necessary to enable form state serialization for fields like TreeSelectorField on a VirtualPage (fixes #5269)
* [rev:101739] Versioned->publish() with $createNewVersion=TRUE now increases version number of in-memory object (fixes #5261)
* [rev:101737] RedirectorPage types shouldn't appear in "Pages with no content" side report in the CMS Pages tab
* [rev:101724] #5277 Sort of default SiteTree records is now explicitly set to avoid strange ordering set by SiteTree::onBeforeWrite for default records
* [rev:101719] Only show "Roles" tab in admin/security if user has APPLY_ROLES permissions (fixes #5258)
* [rev:101711] Don't replace "home/" URLSegment in SiteTree->RelativeLink() if Translatable is enabled and the homepage is not on the root level (nested URLs allows you to have homepages called "en/home" and "ru/home") (fixes #5244)
* [rev:101668] #5259 RedirectorPage and HtmlEditorField TinyMCE integration now prefixes http:// if no prefix is found
* [rev:101657] #5245 Sometimes page records will have a NULL ParentID value, it should be a number even if it's 0 (thanks wrossiter!)
* [rev:101638] #5243 Undefined Convert functions in ViewableData replaced with working versions. Thanks benediktb!
* [rev:101631] test that the class exists before running subclass tests
* [rev:101623] put back into the SSNavigator the archived site link (#5251)
* [rev:101608] Explicitly specify the many_many's join table name in the join's ON match statement in ManyManyComplexTableField
* [rev:101604] remove the unnecessary DOM manipulation, this is legacy code due to SilverStripeNavigator changes (open #5250)
* [rev:101603] the function makes an assumption we are working on Draft site, and breaks if we are not. Rewritten to be stage-independent, as get_version (open #5231)
* [rev:101602] IE does not accept TD element without a table, repacking into DIV (open #5228)
* [rev:101592] get a object inside transaction block will alway exist
* [rev:101554] tables and column quoted properly
* [rev:101493] tables and column quoted properly
* [rev:101492] results sorted alphabetically for consistency
* [rev:101491] results sorted alphabetically for consistency
* [rev:101392] HTTP::setGetVar() returns a relative URL if a relative URL is passed, to make behaviour closer to 2.3
* [rev:101380] disabling unused file list as feature is still buggy.
* [rev:101375] Fixed closing `</div>` which should have been a `</td>` for dragfile in AssetTableField
* [rev:101302] Fixed SiteTree->Content link shortcode parsing introduced in r101093 (#5227)
* [rev:101267] #5222 Fixed TreeDropdownField not working on FileIFrameField/ImageField
* [rev:101266] Fixed Folder writing by overloading validate() (was inheriting File->validate() which does extension checks)
* [rev:101266] Fixed Folder::findOrMake() not to create "new-folder" through File->setName() if using a trailing slash in the path (which causes an empty name). Added FolderTest to verify this.
* [rev:101264] Checking for existence of "ShowInMenus" property in Folder->liveChildren() and stageChildren() (#5190)
* [rev:101227] Don't delete index.php after successful installation - in ContentController->deleteinstallfiles(). URL routing might rely on it without mod_rewrite.
* [rev:101227] Require ADMIN permissions for ContentController->deleteinstallfiles() - together with retaining index.php this removed a vulnerability where unauthenticated users can disrupt mod_rewrite-less URL routing.
* [rev:101220] TeamComment table added to dataobjects list
* [rev:101189] Make SS_ReportWrapper::sourceRecords()' arguments optional
* [rev:101175] Fixed quotes around Folder::hasChildFolders() ParentID column
* [rev:101173] Don't run click() on all inputs, but input:radio only
* [rev:101171] Pass correct class to allowPrimaryKeyEditing in yaml fixture
* [rev:101170] Don't recreate a missing draft page when calling SiteTree::doUnpublish()
* [rev:101167] #5216 Installer has issues with click handlers applied to the entire li, be more specific and apply it to the label and input instead
* [rev:101165] Fixed versioning of pages
* [rev:101155] Prevent failed migrateVersion writes from breaking versioning system in future writes.
* [rev:101155] MAke site tree pages go green when you save a new draft.
* [rev:101154] #5214 ViewableData::obj() was creating a DBField without a fieldname argument and caused problems, one example is the version panel of the CMS
* [rev:101153] Ensure that Versioned works on classes with underscores in the names. (from r100905)
* [rev:101138] Fixed issues with broekn link tracking
* [rev:101131] Allow classes to be referred to with casing that differs from their definition.
* [rev:101129] Fixed FileLinkTrackingTest to cope with the empty alt="" and title="" attributes that are created
* [rev:101127] Improved reliabilty of broken link tracking.
* [rev:101127] Don't mark a page as changed on stage if the only thing that has changed is broken link metadata
* [rev:101116] Flush cache after deleting an item.
* [rev:101116] Fixed databaseFieldsOnly version of DataObject::getChangedFields()
* [rev:101112] Fixed bugs with copying custom fields into Virtual pages, generally made virtual pages more robust and performant.
* [rev:101110] Fixed link rewriting to work on other HTMLText fields (from r99517)
* [rev:101109] Return true if SiteTree:doUnpublish() succeeds. (from r99515)
* [rev:101105] Update Object::parse_class_spec() to handle arrays.
* [rev:101099] call_user_func_array changed to PHP 5.1 compatible notation
* [rev:101087] #5202 Installer now properly populates database configuration inputs from request after user clicks "Re-check requirements"
* [rev:101080] Fixed TableListField->print() - was unsetting $cachedSourceItems instead of null'ing it, which breaks later access to the property
* [rev:101068] #5199 Duplicate file uploads have odd numbering attached to end of file
* [rev:101061] Fixed Upload and checking for size with files that don't have any extension
* [rev:101051] Allow files with no extensions by setting File::$allowed_extensions with an empty string
* [rev:101050] #5188 Upload and Folder don't handle the duplicate naming of files that have no extension
* [rev:101046] Cookies set to a value other than NULL (effectively unsetting the cookie) will now use the httpOnly parameter by default for better XSS protection (from r101045)
* [rev:101034] Fix static caching file lookup to match file generation.
* [rev:101005] Image should pass through the title to Image_Cached so that Image::getTag() can produce a more useful alt attribute instead of just the filename (from r101003)
* [rev:100998] column and table names now quoted properly
* [rev:100986] Disable javascript date validation via DateField->jsValidation() if locale is not 'en_NZ" (which is the only format it validates for).
* [rev:100985] HTMLEditorField->saveInto() can now find images with urlencoded information for resample (e.g. spaces in filenames)
* [rev:100982] Fixed file-write testing issues in requirements combined file generation
* [rev:100980] Remove cache for Hierarchy::AllChildren() and Hierarchy::AllChildrenIncludingDeleted(), since they increase memory usage unnecessarily.
* [rev:100979] Don't make CMS loading slow if the combined javascript files can't be written.
* [rev:100932] SiteTree::getSiteConfig() should always fall back to using a default if an alternate config wasn't found
* [rev:100924] Allow DatabaseAdmin to run dev/build in live mode when not Security::is_database_ready(), and avoid broken login due to broken db queries (selecting unknown columns before dev/build) (see #4957)
* [rev:100921] DataObject::hasValue() is now compatible with parent ViewableData::hasValue() (this also fixes E_STRICT standards in PHP)
* [rev:100919] RequestHandler::handleRequest is now compatible with Controller::handleRequest in that SS_HTTPRequest is the type hint for the $request parameter
* [rev:100918] ManifestBuilder::up_children() should be declared as static as it's called statically
* [rev:100904] Produce XHTML compliant URLs in HTTP::setGetVar() by default (regression from r98373, see #5101)
* [rev:100896] #5138: DataObjectSet::removeDuplicates() removes objects of different classes with the same ID
* [rev:100866] #5176 Javascript error in IE for the installer - use "this" instead of e.target which doesn't work
* [rev:100862] Use "wb" argument in ManifestBuilder fopen() calls for better cross-platform compatibility
* [rev:100861] #5157 If paths are longer than 255 characters, fopen() produces an "Invalid argument" error, shorten the paths by using basename() instead of realpath() on the manifest filename when producing the cache path in ManifestBuilder
* [rev:100858] Fixed notice level error with folder ID
* [rev:100854] fixed file uploading not uploading any files at all
* [rev:100853] Fixed jQuery.ondemand.js script to work with prototype.js (will probably need to be merged back to trunk for legacy purposes)
* [rev:100848] Fixed variable declaration order in tabstrip.js (necessary due to changed jquery.livequery behaviour
* [rev:100825] Added single quote as a valid local-part of an email address as per RFC5322. Other symbols still excluded although in the spec
* [rev:100795] #5157 strftime() %F format parameter does not work on Windows - use %Y-%m-%d instead
* [rev:100767] Date::now() supplies wrong string - it misses leading zeroes on hours
* [rev:100763] added uniqueness id, to prevet multiple VirtuaLage reloads on publish
* [rev:100755] TreeSelectorField doubles up on concating base_url, doesn't include the security ID (#5164, thanks marcus)
* [rev:100747] #5099 FileIFrameField fails when using it with a locale different to the default
* [rev:100727] allow selection of database adpater
* [rev:100726] misspelled variable
* [rev:100724] some sections dont have a tree at all, but they still use LeftAndMain as their base class (eg report admin). Added a guard.
* [rev:100723] Fixed SapphireTest->loginWithPermission() and MemberAuthenticatorTest to use existing Members based on their unique_identifier_field (if existing) to accommodate recent Member->onBeforeWrite() changes (see r100705)
* [rev:100722] reload page if broken link tracking values changed during a save. Ticket #1363
* [rev:100721] Unsetting 'ID' parameter in MemberTableField->addtogroup() to avoid confusion between Group and Member records (regression from r100716) (from r100720)
* [rev:100719] Fixed MemberTableField->addtogroup() to fetch existing Member records by ID or $unique_identifier_field instead of relying on the (now removed) "auto-merging" in Member->onBeforeWrite() (see r100705) (from r100716)
* [rev:100717] Fixing Member_ProfileForm to validate for existing members via Member_Validator to avoid CMS users to switch to another existing user account by using their email address (from r100704)
* [rev:100701] moving the ajaxupdatesort JS response code from php to js to get rid of eval. Also disable the "loading" on the moved element when we are done, in case we are repositioning other than the selected item - otherwise the progress indicator is displayed indefinitely.
* [rev:100699] column names quoted properly
* [rev:100693] column names quoted properly
* [rev:100692] column names quoted properly
* [rev:100691] column names quoted properly
* [rev:100690] column names quoted properly
* [rev:100689] column name capitalised
* [rev:100688] column names quoted properly
* [rev:100687] column names quoted properly
* [rev:100686] the default value for decimals are now cast as (doubles)
* [rev:100657] tables and columns now quoted properly
* [rev:100632] Fixed SiteTree->MetaTags() to either use `<meta name=>` or `<meta http-equiv=>`, and only using the "http-equiv" attribute for valid HTTP headers (see http://www.w3.org/TR/html4/struct/global.html#edef-META) (from r100631)
* [rev:100627] DB::getConnect() should be properly declared as a static function
* [rev:100616] Fixed filemtime() check in Requirements_Backend::process_combined_files() not getting the right path
* [rev:100614] Proper check for combined file path in Requirements_Backend::process_combined_files()
* [rev:100560] #4572 Fixed Windows failure on SS_Cli::supports_colour() because posix functions are not supported
* [rev:100548] If fixture file is NULL don't cause the test framework to break down because of it
* [rev:100527] Set Member default Locale
* [rev:100525] get TreeMultiselectField working with an array of items, rather than a relation.
* [rev:100519] add 'var' to local variable 'constructor' inside of function definition which break IE8 (8.0.6001.18702 +)
* [rev:100508] wrong constructor function name
* [rev:100496] replacing calls to deprecated Upload functions - using validator instead (related to r100057)
* [rev:100466] #5012 BasicAuth should check if there's already a current member logged in before asking for a login/password
* [rev:100438] GD::setQuality() persistence issue because the GD instance is re-created instead of being cloned - thanks Tjofras!
* [rev:100417] #5121 Fixed cache flushing for FieldSet when removing fields - thanks paradigmincarnate!
* [rev:100415] #5136 Ensure $coverage argument to TestRunner::runTests() has a strict check before running coverage tests, as sometimes an SS_HTTPRequest object can be passed into this argument
* [rev:100407] FormAction input tag attributes were being doubly-escaped.
* [rev:100406] Fix mismatch with $all_locales and $common_locales (#5096)
* [rev:100394] #5135 LeftAndMain extra requirements loading for "themedcss" should use Requirements::themedCSS() not Requirements::css() - thanks Hamish!
* [rev:100393] YamlFixture::writeDataObject() - some databases need special allowance to edit the primary key column - do so by using DB::getConn()->allowPrimaryKeyEditing()
* [rev:100375] Sam's fix for "Unknown column Group.SubsiteID" with new subsites
* [rev:100370] use localized prefix to compare group codes rather than hard coded english string. MINOR: updated lang file
* [rev:100367] PHP 5.1 requires an array rather than a string for call_user_func()
* [rev:100359] Show Language dropdown in English (#5098)
* [rev:100335] #5023 AssetAdmin::sync() is now used to sync tasks, as it works when the user only has access to the AssetAdmin controller instead of going to dev/tasks/FilesystemSyncTask which can only be run by administrators or if the site is in dev mode
* [rev:100116] Fix TestRunner coverage pattern to work as documented (Fixes QA scripts too)
* [rev:100053] SQL Error is a member is not part of any groups
* [rev:99993] Setting default $groups in MemberTableField::AddForm() in addition to MemberTableField_Popup::__construct() - this was broken by r99777
* [rev:99960] #2022: Fixed CMS dropdowns in Opera.
* [rev:99952] Fix #2138, allow modification of existing images
* [rev:99951] Fix #2138, notify Image Toolbar on TinyMCE node selection change
* [rev:99942] action buttons always visible (not need to scroll) ticket 5051
* [rev:99942] got rid of double scroll
* [rev:99942] do not show action buttons (delete/save) when showing result list
* [rev:99887] Use underscores in names of combined .js (#3581)
* [rev:99854] Quoting keys in JSONDataFormatter to ensure valid JSON (#5119) (from r99853)
* [rev:99850] Fix #5097, Translatable uses augmentValidURLSegment to check that URLSegment is valid
* [rev:99843] Respect SilverStripe's cache folder
* [rev:99818] Handle filename deduping when uploading of double-barrelled extensions and files ending in numbers better.
* [rev:99816] Fixed the code for the unused file list, although the feature is still disabled.
* [rev:99789] #5073: Fixed CMS version indicator for alpha and beta versions.
* [rev:99779] make siteconfig work again
* [rev:99777] #5087: Show default values in CTF 'add' popups.
* [rev:99745] #3458: Don't show javascript:mctmp(0) URLs in URL editor
* [rev:99739] tree selector base URL calculation wrong when field is nested
* [rev:99738] #4974: Improve accuracy of ManifestBuilder::parse_file() cache, to remove a source of upgrade bugs.
* [rev:99713] Fixed MemberTableField limiting of , wasnt taking children groups into account (regression from r99684) (from r99706)
* [rev:99711] Setting ID explicitly in MemberTableField-> to ensure getCsvQuery() correctly filters (the custom group filter was only implemented in sourceItems() before) (from r99684)
* [rev:99693] Changed sitetree default selection in LeftAndMain.Tree.js to fire on window.load instead of document.ready() through entwine. We need to ensure behaviour.js bindings are available before
* [rev:99693] Automatically selecting root node in CMS trees (necessary because now we actually have forms on the root node, and its a valid click target) (from r99605)
* [rev:99679] really testing deletemarked now.
* [rev:99667] Fixed bogus HTMLEditorConfig instance when get() is called without a valid identifier (due to NULL database columns) (from r99599)
* [rev:99655] Fixed TreeMultiselectField/TreeDropdownField saving with 'unchanged' default values from constructor (from r99581)
* [rev:99647] Fixed TreeMultiselectField->Field() to respect settings, and give them priority over existing relations through getItems(). This is used in MemberTableField to set default groups for 'add member' popups. (from r98879)
* [rev:99640] Fixed DataObject->fieldLabels() to respect flag (from r98748)
* [rev:99638] Folder::findOrMake() will create the assets/ folder if it's missing
* [rev:99613] Fixed bug in r99552
* [rev:99595] Fixed Access tab on SiteConfig
* [rev:99594] Debugged and simplified Access tab javascript
* [rev:99587] Show 'Inherit' option for edit and view all the time (since we now have SiteConfig)
* [rev:99572] Pages that you can't edit should always be grey, even if there are unpublished changes.
* [rev:99553] Remove buttons from display if you load a CMS page that should have no buttons - reverts bug caused by r96551 and fixes the issue it was trying to solve.
* [rev:99552] Fixed behaviour's ID selector matching when the ID is inside another context - eg 'body.className #ID'
* [rev:99522] Image::onBeforeDelete() now calls deleteFormattedImages() so resampled images in the filesystem are cleaned up
* [rev:99506] use the correct method for retrieving the report ID
* [rev:99490] tablename and columns quoted properly
* [rev:99479] Setting ID = -1 on Security/lostpassword to avoid showing toplevel navigation (see #5086)
* [rev:99465] Correct StaticPublisher filenames, now works with nested URLS
* [rev:99443] batch_permission_check returns null rather than empty array when user has no permissions
* [rev:99394] Fixed variable existence checks in setValue() in FormField::__construct() by checking for !== NULL (changed from isset($value) to $value in r99360)
* [rev:99391] Fixed MoneyField constructor - parent (FormField) constructor calls setValue() already, which needs to happen *after* setting certain field instances
* [rev:99342] Enforcing creation of temp database in SapphireTest->setUp() to avoid writing to production databases. This check should only kick in for single test case runs, as the temp database connection should be set in a dev/tests/all run after the first db-related test anyway. (see #5034)
* [rev:99303] Disable some permission caching for now, as it was breaking unit tests (from r98504)
* [rev:99302] SiteTree::batch_permission_check() doesn't recurse with ID=0 calls
* [rev:99128] Fix not being able to print/export reports (from r98684)
* [rev:99125] Fixed cache prepopulation on sitetree load. (from r98651)
* [rev:99124] Make sure navigation links update when urlsegment is changed (from r98649)
* [rev:99116] Fix navigator links not opening in new windows. (from r97510)
* [rev:99115] Fixed bug in r97395 (from r97508)
* [rev:99101] Take into account tablename with custom columns in get_title_sql (from r97003)
* [rev:99100] use proper quotes for sep (from r96401)
* [rev:99089] Only show live link when page has been published (from r97839)
* [rev:99087] Make sure draft/published links go to the right subsite (from r97747)
* [rev:99086] Fix navigator links not opening in new windows. (from r97510)
* [rev:99085] Show a hand icon and better title for the 'share link' piece of the navigator toolbar. (from r97439)
* [rev:99067] Ensure that ModelAsController::init() can trigger redirections. (from r98702)
* [rev:99065] Fixed SiteTree_versions version numbers for published virtual pages. (from r98675)
* [rev:99060] fixed query to get number of unmoderated comments
* [rev:99052] Generate SiteTree_version records for VirtualPages more reliably. (from r98309)
* [rev:99050] fix incorrect link in CMS (from r97408)
* [rev:99049] Make sure CMS link knows when its currently in the CMS (from r97403)
* [rev:99031] Don't show FailedLoginCount field unless Member::$lock_out_after_incorrect_logins is enabled
* [rev:99005] Development server list should be retained when user submits installer form and gets redirected back
* [rev:98957] fix for #5076
* [rev:98946] the ID should be that of untranslated child (it's the middle segment that's from translated version, not the last one)
* [rev:98944] testing framework needs to be reset to a clean state after each test: now also nested urls and redirection state will be reverted
* [rev:98897] Fixed strpos() check in BASE_URL check
* [rev:98895] Installer now opens if mod_rewrite is disabled. Using index.php instead of rewriting the URL didn't quite work with the new BASE_URL, so we need to take this case into account as well
* [rev:98869]

497
docs/en/changelogs/2.4.1.md Normal file
View File

@ -0,0 +1,497 @@
# 2.4.1 (2010-07-23)
## Overview
* Fixed a security issue where logged-in CMS authors were allowed to rename files with harmful extensions in the "Files & Images" section
* Improved installer security by disallowing re-installation when a configuration file is already present.
* Installing in "live mode" instead of "dev mode" by default, and avoid setting certain domains as "dev mode" by default. This fixes an issue where attackers were able to force a site into "dev mode" by spoofing the domain name on certain server configurations.
* Fixed password encryption when saving members through the "Add Member" dialog in the "Security" admin. The saving process was disregarding password encyrption and saving them as plaintext (issue was introduced in 2.4.0)
* Fixed potential information disclosure on misconfigured servers by disallowing direct execution of *.php files in "sapphire", "cms" and "mysite" folders. If PHP was configured to show errors on screen (development setting), attackers could find out server paths and other environment information.
* Allow CMS authors to set their own localized date and time formats, independently from the defaults set through their interface language.
* More useable date picker (jQuery UI) for date form fields (both in the CMS and in website forms)
* Better URL "transliteration" of special characters like Umlauts or Macrons (Example title: "Brötchen für alle!", URL in 2.4.0: "brtchen-fr-alle", URL in 2.4.1: "broetchen-fuer-alle")
* Better batch editing of comments in the admin interface (e.g. marking multiple comments as "spam")
* More sophisticated access control for decorators on page types (tri-state permissions checks: allow, deny, ignore).
## Upgrading
See [API Changes](http://open.silverstripe.org/wiki/ChangeLog/2.4.1-rc1?version=2#APIChanges).
### Security: File->setName() and File->Filename handling
Setting properties on *File* and *Image* are not reflected on the filesystem until *write()* is called. This was a
necessary change to fix a security vulnerability around File->setName() and file extension validation. This
vulnerability requires a user to be logged-in to the CMS (see [#5693](http://open.silverstripe.org/ticket/5693)).
This means that CMS users with access to "Files & Images" can no longer rename uploaded files to invalid extensions in
2.4.1. In SilverStripe 2.3.8, this restriction only applies when *AssetAdmin::$apply_restrictions_to_admin* is set to
TRUE.
### Security: Installation in "live mode" by default
SilverStripe used to allow setting the [environment type](/topics/environment-management) ("dev mode", "test mode" or "live
mode") from within the installer, through *Director::set_dev_servers()*, *Director::set_test_servers()* and
*Director::set_live_servers()*.
On webservers with direct IP to domain mapping (e.g. no *VirtualHost* directives in Apache), it is possible to spoof
domain information in HTTP requests. This can lead to "live" environments being set to "dev" mode, allowing
administrative actions like *dev/build* without access control.
Note: The CMS is still secured through login in "dev mode".
We recommend setting environment types through a [_ss_environment.php](/topics/environment-management) file instead:
:::php
<?php
define('SS_ENVIRONMENT_TYPE', 'dev');
// ...
To put a "live" or "test" environment into "dev mode" temporarily (when logged in as an administrator),
you can append *?isDev=1* to any SilverStripe URL. This should give you more information than the common
"Website Error" that is shown when the website is in "live mode".
IMPORTANT: If you have an existing installation, we advise to remove any *Director::set_dev_servers()* directives from
your *mysite/_config.php*.
### Security: Disallow direct execution of *.php files
The only PHP file that should be executable through the webserver
is *sapphire/main.php*, our main bootstrapper which kicks of URL routing.
All other PHP files in SilverStripe core and modules are included
by this bootstrapper, and don't need direct access through a URL.
On misconfigured webservers, accessing these files directly through URL can lead to
information disclosure through PHP error messages. The production configuration
recommended by [php.net](http://www.php.net/manual/en/errorfunc.configuration.php#ini.display-errors)
will fix this issue:
:::php
display_errors = 0
For additional protection, we now include *.htaccess* files in all SilverStripe core folders
disallowing access to **.php* files. Note: This only applies to webservers that understand
the *.htaccess* format, mainly Apache.
''Important'': Consider copying *mysite/.htaccess* to any other SilverStripe
modules and folders you might have created in your own project.
### Security: New members might be saved without password encryption
Fixed password encryption when saving members through the "Add Member" dialog in the "Security" admin. The saving
process was disregarding password encyrption and saving them as plaintext
([#5772](http://open.silverstripe.org/ticket/5772)). The issue was introduced in 2.4.0 - if you have created any new
members through "Add Member" since then (not the inline member table), please re-encrypt all existing passwords using
this task:
http://localhost/dev/tasks/EncryptAllPasswordsTask
### Date/Time format handling in CMS
Classes like DateField, TimeField and DatetimeField are now aware of member-specific formats which can be set in
*admin/myprofile* (linked on the lower right footer in the CMS interface). See [i18n](/topics/i18n) for more details.
Example: Setting German date formats in *mysite/_config.php*:
:::php
i18n::set_locale('de_DE');
i18n::set_date_format('dd.MM.YYYY');
i18n::set_time_format('HH:mm');
Please note that these form fields use [ISO date
format](http://framework.zend.com/manual/en/zend.date.constants.html#zend.date.constants.selfdefinedformats), not PHP's
built-in [date()](http://nz.php.net/manual/en/function.date.php).
To set the locale and date/time formats for all existing members, use the following SQL (adjust to your preferred
formats):
UPDATE `Member` SET `Locale` = 'de_DE', `DateFormat` = 'dd.MM.YYYY', `TimeFormat` = 'HH:mm';
### Changed permission checks for decorators on DataObject->can*()
Access checks in the SiteTree class can have their access checks extended, for example to influence SiteTree->canEdit().
In 2.4.0, it was only possible to explicitly deny an action by returning FALSE, returning TRUE wouldn't have any effect.
The new behaviour has three states:
* FALSE: Disallow this permission, regardless of what other decorators say
* TRUE: Allow this permission, as long as no other decorators return false
* NULL: Don't affect the outcome
To clarify: Leaving existing decorators unchanged might mean that you allow actions that were previously denied (See
[r104669](http://open.silverstripe.org/changeset/104669)).
// In mysite/_config.php
:::php
Object::add_extension('SiteTree', 'MyDecorator');
// 2.4.0
:::php
class MyDecorator extends DataObjectDecorator {
function canEdit($member) {
if(Permission::checkMember($member, 'MYPERMISSION')) {
return true;
} else {
return false;
}
}
}
// 2.4.1
:::php
class MyDecorator extends DataObjectDecorator {
function canEdit($member) {
if(Permission::checkMember($member, 'MYPERMISSION')) {
return null; // Means the permission check will be ignored, instead of forced to TRUE
} else {
return false;
}
}
}
### Removed image editor sourcecode
This feature was disabled for a while, and has now been removed from the source tree as well. Please please use
thirdparty modules instead, e.g. "[silverstripe-pixlr](http://github.com/nyeholt/silverstripe-pixlr)"
([r104987](http://open.silverstripe.org/changeset/104987)).
### URL Transliteration
Non-ASCII characters like [macrons](http://en.wikipedia.org/wiki/Macron) or
[umlauts](http://en.wikipedia.org/wiki/Germanic_umlaut) URLs are now transliterated. This means that special characters
are replaced with their ASCII equivalents rather than just removed. This does not affect existing URLs, but will impact
existing pages when their title is changed.
Title: "Brötchen für alle!"
URL in 2.4.0: "brtchen-fr-alle"
URL in 2.4.1: "broetchen-fuer-alle"
### Removed Classes
* AutocompleteTextField
## Changelog
### Features and Enhancements
* [rev:108024] Show a warning inside the the CMS if you've neglected to delete install.php
* [rev:108012] added getter to get array back out of an !ArrayData instance. MINOR: updated docblocks in !ArrayData
* [rev:107877] Added Latvian (Latvia) translation to sapphire (thanks Kristaps and Andris!)
* [rev:107875] Added Latvian (Latvia) translation to cms (thanks Kristaps and Andris!)
* [rev:107867] Allowing custom messages and permission codes in !BasicAuth::protect_entire_site()
* [rev:107867] Making $permissionCode argument optional for !BasicAuth::requireLogin(). If not set the logic only checks for a valid account (but no group memberships)
* [rev:107867] Using SS_HTTPResponse_Exception instead of header()/die() in !BasicAuth::requireLogin() to make it more testable
* [rev:107810] Added class to time icon in !TimeField so it can be styled
* [rev:107443] html2raw now properly replace strong tag with asterix #5494
* [rev:107438] Using jQuery UI datepicker in !DateField and !DatetimeField instead of outdated DHTML calendar.js (fixes #5397)
* [rev:107438] Abstracted optional !DateField->setConfig('showcalendar') logic to !DateField_View_JQuery
* [rev:107434] allow adding a new a field to !ArrayData
* [rev:107429] Added documentation and changed static names
* [rev:107426] Added static to set regeneration of default pages (ticket #5633)
* [rev:107415] Added Security::$force_database_is_ready to mock database_is_ready() state
* [rev:107415] Added permission check exception in !TaskRunner and !DatabaseAdmin if !SapphireTest::is_running_test() returns TRUE (necessary for !DevelopmentAdminTest)
* [rev:107380] Use array_combine() instead of custom logic for !ArrayLib::valuekey() (thanks paradigmincarnate!)
* [rev:107365] Member_!DatetimeOptionsetField toggle text is now translatable
* [rev:107334] #5352 Translatable entities for help text in Member_!DatetimeOptionsetField::getFormattingHelpText()
* [rev:107327] #5352 CMS now uses the user's preferred date and time formatting in !DateField and !TimeField
* [rev:107326] #5352 Decouple date display from i18n locales, users now have access to change their date and time formats in Member::getCMSFields() using Member_!DatetimeOptionsetField field
* [rev:107094] abstracted protocol detection out to Director::protocol() #5450
* [rev:107091] in referencing a file in combine_files() it should fall back to standard requirement tags if combining has been disabled eg dev mode
* [rev:107088] throw user error when not passing correctly formatted array rather than simply passing
* [rev:107086] added setDisabled() to set !DropdownField::$disabled
* [rev:106877] Added !TestRunner::$coverage_filter_dirs to exclude certain directories from PHPUnit test coverage reports
* [rev:106705] Calling Image->deleteFormattedImages() in Image->onBeforeWrite() (#5423)
* [rev:106200] added prefix and suffix support to !ContextSummary
* [rev:106194] Prevent image search queries all images in the site initially when the page is loaded
* [rev:106178] Enable switch between legacy image search and new version
* [rev:106118] added setRows() and setColumns() to customize the size of the textarea field outside of the controller
* [rev:105890] Added method for $this->request->latestParam() backwards compatibility with Director::urlParam()
* [rev:105732] Ability to hide form by className or for the whole !ModelAdmin
* [rev:105712] Added !MySQLDatabaseConfigurationHelper::getDatabaseVersion() which abstracts the version number away from the version check the installer requires
* [rev:105275] Preserve sort options in pagination links in !TableListField
* [rev:105271] 'Select all' and 'Select none' checkboxes for !CommentTableField for easier batch handling of comments, improved its styling in !CommentAdmin
* [rev:105269] Showing 20 comments in tabular view for !CommentAdmin (and making the setting configurable via !CommentAdmin::set_comments_per_page())
* [rev:105268] Abbreviating comment text display in !CommentAdmin to first 150 characters
* [rev:105266] Allowing batch checkbox selection of !TableListField rows with !TableListField->Markable and !TableListField->addSelectOptions()
* [rev:105126] Added CSSContentParser->getByXpath()
* [rev:105028] Added variable for the server configuration file so the config-form can display it for the installation
* [rev:104968] Added !PageComment->canView()/canEdit()/canDelete(), and using these permissions in !PageCommentInterface. Caution: canCreate() actions are still determined by !PageCommentInterface::$comments_require_login/$comments_require_permission
* [rev:104935] added Month function for consistency
* [rev:104827] added plugins to i18n to support modules that provide custom translations.
* [rev:104707] Installer now supports requireDatabaseVersion() on each database configuration helper implementation, e.g. !MySQLDatabaseConfigurationHelper. If it's not defined, the test is skipped.
* [rev:104706] Added !MySQLDatabaseConfigurationHelper::requireDatabaseVersion() to check whether the connected instance is using version 5.0+
* [rev:104671] Macrons, umlauts, etc, are now transliterated when inserted into URLS. API CHANGE: Added Transliterator class, which uses iconv() or strtr() to convert characters with diacritical marks to their ASCII equivalents. API CHANGE: Added Extension hook updateURLSegment for !SiteeTree.
* [rev:104515] initial commit
* [rev:104232] Add 'Given I load the fixture file "app/tests/xyz.yml"' step to salad
* [rev:104231] Add dev/tests/sessionloadyml to load a yml fixture into an existing test session
* [rev:104162] Added cs_CZ javascript translations (#5540, thanks Pike)
### API Changes
* [rev:107439] Using !FieldHolder() instead of Field() for subfields in !DatetimeField->!FieldHolder(), in order to get configuraton settings for javascript !DateField
* [rev:107273] Don't reflect changes in File and Folder property setters on filesystem before write() is called, to ensure that validate() applies in all cases. This fixes a problem where File->setName() would circumvent restrictions in File::$allowed_extensions (fixes #5693)
* [rev:107273] Removed File->resetFilename(), use File->updateFilesystem() to update the filesystem, and File->getRelativePath() to just update the "Filename" property without any filesystem changes (emulating the old $renamePhysicalFile method argument in resetFilename())
* [rev:107273] Removed File->autosetFilename(), please set the "Filename" property via File->getRelativePath()
* [rev:107268] Deprecated File->getLinkedURL()
* [rev:107054] Deprecated !AutocompleteTextField, use third-party solutions
* [rev:106217] moved Group::addToGroupByName to $member->addToGroupByCode.
* [rev:105756] refactored methods in session to use coding conventions
* [rev:104987] Removed !ImageEditor functionality, please use thirdparty modules, e.g. "silverstripe-pixlr" (http://github.com/nyeholt/silverstripe-pixlr)
* [rev:104923] Added interface method !DatabaseConfigurationHelper::requireDatabaseVersion(), all database helpers that implement !DatabaseConfigurationHelper must now have this method, which as of now is MySQL, PostgreSQL, SQL Server and SQLite
* [rev:104673] Added !RsyncMultiHostPublisher::set_excluded_folders().
* [rev:104669] Moved site tree permission extension to a 3-state system (true, false, null, where null means "no effect")
### Bugfixes
* [rev:108207] Re-allowing direct execution in sapphire/thirdparty/tinymce/plugins/spellchecker/rpc.php (necessary for cms spellchecker, was disabled by global .htaccess rule)
* [rev:108195] #5837 cache_dir not writable by Zend when accessing the CMS, because of Windows default which should be the sapphire TEMP_FOLDER
* [rev:108193] Bypass !BasicAuth when in CLI mode so unit tests can run (regression from r104962)
* [rev:108099] Fixing default group selection in 'add member' dialog (in !MemberTableField) (fixes #5836)
* [rev:108096] AssetAdmin->doUpload() shows JS alert *before* triggering a page reload, as this seems to mess up TinyMCE in Firefox on subsequent page loads (fixes #5838)
* [rev:108032] Fixed CLI installation.
* [rev:108031] Don't set any dev servers by default, host-based dev-server selection is unreliable.
* [rev:108030] Don't allow reinstalling without first making the user manually delete mysite/_config.php
* [rev:108029] Don't allow direct access to PHP files in mysite module.
* [rev:108028] Don't allow direct access to PHP files in cms module.
* [rev:108027] Don't have any host-based dev servers set by default.
* [rev:108026] Don't allow reinstalling without first making the user manually delete mysite/_config.php
* [rev:108023] Don't allow direct access to PHP files in sapphire module, except for main.php and static-main.php
* [rev:108001] #5833 Duplicate IDs when two similar date formats in Member_!DatetimeOptionsetField containing different delimiters (e.g / and .) replaced to an empty string
* [rev:107940] tests now pass when the locale is set to something other than 'en_US' in the mysite's _config.php file
* [rev:107831] dev/build always reporting index change because of a whitespace in the index column names
* [rev:107812] Styling fixes for !DateField/!TimeField/!DatetimeField in the CMS
* [rev:107811] Added a clearing div after the date and time fields, not the best way of doing it but the only way as the overflow css trick for clearing fields doesn't work with the time dropdown
* [rev:107789] Fixed !DateField->validate() with keyed, but empty array values
* [rev:107786] Using actual date format settings in !DateField/!TimeField->validate() messages
* [rev:107785] Limit 'showcalendar' javascript option to !DateField instances (rather than applying to all available)
* [rev:107585] fixed inclusion of environment file when document root is the web root
* [rev:107539] Case insensitive extension checks in File::validate() (fixes #5781, thanks simon_w)
* [rev:107537] Remove dummy entry created by Versioned if record is first written to Live stage (fixes #5596, thanks muzdowski)
* [rev:107532] Fixed Member->!PasswordEncryption defaults when writing new Member without setting a password. Fixes critical issue with !MemberTableField saving in admin/security, where new members are stored with a cleartext password by default instead of using the default SHA1 (see #5772)
* [rev:107441] Allowing !DatetimeField->saveInto() to save a partial array notation with missing 'time' value
* [rev:107428] Added quotes for postgres
* [rev:107423] Only highlight strings more than 2 characters long. #4949
* [rev:107417] Reverted 107414, wrong patch
* [rev:107415] Allowing dev/build in "live" mode when Security::database_is_ready() returns FALSE (typically happens when an existing !SilverStripe project is upgraded and database columns in Member/Permission/Group have been added) (fixes #4957)
* [rev:107414] TableListField headings i18n translation (ticket #5742)
* [rev:107390] Added Locale hidden field to HTMLEditorField->!LinkForm() in order to show correct context in "page on the site" dropdown (fixes #5743)
* [rev:107369] Fixed spelling error of $databaseConfig in cli-script.php causing database configuration to not load (thanks aimcom!)
* [rev:107116] Undo commit to wrong place
* [rev:107115] Undo incorrect commit
* [rev:107095] check the $removeAll var before removing cache files. PATCH via ajshort (#5672)
* [rev:107090] prevented HTTPRequest->shift() throwing notices when shifting multiple elements. APICHANGE: SS_HTTPRequest->shift($multiple) no longer returns an array of size $multiple spaced with nulls, it returns an array up to the size of $multiple.
* [rev:107089] fixed notice level errors getting through
* [rev:106867] Making status description in Debug::friendlyError() compatible to HTTP 1.1 spec (removing any markup and newlines)
* [rev:106777] Re-enabling theme in !ErrorPage->doPublish() (it's usually disabled in the publication context through !LeftAndMain->init())
* [rev:106755] Stricter checking that a relation exists on !ComplexTableField::saveComplexTableField()
* [rev:106671] Fixed !ImageField->!EditFileForm() to list subclasses of Image in tree dropdown (fixes #5708, thanks keeny)
* [rev:106666] Prevent !DateField->performReadonlyTransformation() from segfaulting on PHP 5.2 due to broken __toString() casting (fixes #5713, thanks charden)
* [rev:106360] re-enable broken link notification using !BackLinkTracking() (this was broken since r101127
* [rev:106351] Apply AJShort's patch to fix !SiteConfig (trac 5671)
* [rev:106225] Checking for the same combined filename in Requirements::combine_files() to avoid irrelevant error messages
* [rev:106205] updated tests for Text
* [rev:106183] fix query error when image search doesn't use legacy search
* [rev:106154] if running in cli do not output html tags when rebuilding the db
* [rev:106122] Fixed caching of homepage.
* [rev:106121] Open help in a new tab.
* [rev:106120] Replaced Versioned's unique index definition with an array syntax.
* [rev:106096] Setting 'ID' field on CMSMain->!RootForm() so it can work with formfields that require it (fixes #5671, thanks ajshort)
* [rev:106086] image search was not honouring the selected folder, so could only search in root folder
* [rev:106082] Fixed !SiteTree::!IsModifiedOnStage() for an edge-case that was identified when deleteFromStage() stopped manipulating the current record.
* [rev:106080] Don't let deleteFromStage() kill the ID of the original record.
* [rev:106079] Add a unique index to !SiteTree_versions.RecordID+Version. Fix saving methods to support this.
* [rev:106078] Throw an exception if you try an delete an unsaved or already-deleted record
* [rev:106071] MySQLDatabaseConfigurationHelper::getVersion() will fallback to trying to get the version using a query if mysql_get_server_info() returns nothing
* [rev:105907] fixed phpunit directive
* [rev:105903] reverted revision 105890 to fix build
* [rev:105889] invalid use of @covers annotation
* [rev:105876] TableListField_Item::!SelectOptionClasses() can not use it parent protected variable.
* [rev:105875] rollback r105858 which introducesa bug
* [rev:105872] updated select options classes to work with the dataobjectset returned by selectoptions rather than the array previously
* [rev:105868] fixed select all link using incorrect function
* [rev:105858] TableListField_Item::!SelectOptionClasses() can use it parent protected variable.
* [rev:105833] fixed incorrect include path
* [rev:105732] validate file in import from CSV form
* [rev:105726] If database version can't be determined, just use the database adapter class
* [rev:105711] Install now supports sending database version if available from the helper
* [rev:105705] ss2stat URL not generated correctly (has NULL values)
* [rev:105668] Moved !SiteTree->ParentID property to Hierarchy extension (fixes #5638)
* [rev:105667] More specific regex in Requirements->includeInHTML() to avoid duplicating information by matching HTML5-style <header> tags instead of <head> (fixes #5640)
* [rev:105665] Can't set width or height on !MemberTableField popup (fixes #5625, thanks smurkas)
* [rev:105514] if moderation on comments is enabled then redirect the user back down to the comment section to view the message rather than trying to direct to selector which doesnt exist
* [rev:105505] avoid adding loading class to TinyMCE add link, image, flash buttons
* [rev:105468] #5349: Use TEMP_FOLDER for Zend's cache temp dir.
* [rev:105337] get_title_sql has string concat hardcoded as ||, fixed for MSSQL which uses +, fix for #5613
* [rev:105278] Stricter object type checks in !ViewableData->hasValue() and !ViewableData->XMLval(). Broke in cases when SS_HTTPResponse is returned which doesn't extend from Object, hence doesn't have an exist() method (fixes #5524, thanks hamish)
* [rev:105264] addFieldToTab segfaulting under PHP 5.2
* [rev:105225] force dateformat to en_NZ if showcalendar is enabled as calendar is compatibile with en_NZ only
* [rev:105030] Fixed correct input ID in install.js due to change in r105029
* [rev:105029] Fixed inconsistent styling of reinstall actions at the bottom of the installer, and if using IIS, warn that this will overwrite the web.config file, not .htaccess
* [rev:104995] Fixed i18nTextCollector when used with i18nEntityProvider - class manifest is now stored lowercase, which means i18n::get_owner_module() didnt work reliably
* [rev:104972] TestSession::submitForm throws proper error if form not found
* [rev:104968] Requiring CMS_ACCESS_!CommentAdmin instead of ADMIN permissions in !PageCommentInterface and !CommentAdmin administrative actions
* [rev:104962] Fixed bug in basicauth failover to session member.
* [rev:104962] Don't use session member for test site protection feature.
* [rev:104847] catch case of plugin not returning translations for the locale
* [rev:104793] Installer now checks the database version AFTER it has determined a connection can be established, which some databases require first
* [rev:104793] Database version check failures are now a warning, so a user can install at their own risk
* [rev:104745] after reset password, the site redirect to non-exisit page (SC #1)
* [rev:104720] Fixed installation problem where version error didn't show
* [rev:104679] Make URLs lowercase
* [rev:104678] Fixed Translatable::canEdit() to suit new permission customisation scheme
* [rev:104675] Prevent !DataDifferencer from creating empty <ins /> and <del /> takes that confuse the browser.
* [rev:104672] Make !RsyncMultiHostPublisher protected; give default value.
* [rev:104670] Director::test() shouldn't break if $_SESSION isn't set.
* [rev:104666] Removed references to php5 binary in Makefile
* [rev:104608] check if a request is present before using it to prevent undefined errors
* [rev:104581] Generate stage/live links using Controller::join_links() instead of string concatenation.
* [rev:104580] Fixed Controller::join_links() handling of fragment identifiers
* [rev:104552] when using custom Member title, the join was failing - it had wrong parameters. Now changed to correctly handle the ansi sql join for all Member columns.
* [rev:104533] Fix !ModelAdmin Import hang (ticket 5569)
* [rev:104468] When finding an old page in the 404 handler, favour existing subpages over historical ones.
* [rev:104463] Fix legacy URL redirection for pre-nestedurls URLs, after it has been enabled.
* [rev:104436] Removed erroneous default config for unused templates module.
* [rev:104403] Wrong HTML syntax in !LeftAndMain.ss (fixes #5552, thanks simon_w)
### Minor changes
* [rev:108246] Removed unncessary end PHP tag from cms/_config.php
* [rev:108208] Disallowing more potentially active file extensions in mysite/.htaccess
* [rev:108207] Disallowing more potentially active file extensions in cms/.htaccess
* [rev:108206] Disallowing more potentially active file extensions in cms/.htaccess
* [rev:108196] Removed debug
* [rev:108049] Added warning about Director::set_dev_servers()
* [rev:108048] Documentation in CSVBulkLoader
* [rev:108025] Added test for #5662 (calling delete twice)
* [rev:108002] Fixed incorrect word "colon" with "dot"
* [rev:107878] Updated translations
* [rev:107876] Updated translations
* [rev:107838] Reverted r107831
* [rev:107789] Fixed !DateField/!TimeField validation message translation (wrong sprintf() nesting)
* [rev:107787] Fixed !TimeField validation _t() entity name
* [rev:107784] Disabled 'showcalendar' option on CMSMain->!SiteTreeFilterDateField() - it causes the CMS to load jQuery UI javascript just for this (rarely used field). To be re-enabled once we work with jQuery UI on a broader scale.
* [rev:107726] Moved class-specific documentation from doc.silverstripe.org back into class-level PHPDoc
* [rev:107725] Moved class-specific documentation from doc.silverstripe.org back into class-level PHPDoc
* [rev:107586] removed whitespace
* [rev:107525] Removed debug code in !MemberTableField
* [rev:107442] Fixed !DatetimeField display in cms
* [rev:107442] Removed obsolete .calendardate styles from cms_right.css
* [rev:107440] Using Google CDN for jQuery dependencies in !FileIFrameField
* [rev:107437] Better error handling in i18n::get_language_name()
* [rev:107430] Fixed Documentation
* [rev:107415] Using Object::create() in !DevelopmentAdmin to make objects mockable
* [rev:107400] Documentation in !DataObjectSet
* [rev:107394] Changed "no_NO" locale for Norwegian into the more commonly used "nb_NO" in i18n class, meaning translations from translate.silverstripe.com can actually be selected now (fixes #5746)
* [rev:107366] Tweaking of installer text to avoid misleading information about "exists" when there's actually an error
* [rev:107307] Reverted r107305
* [rev:107305] Code formatting fix for setting Member locale in !LeftAndMain::init()
* [rev:107276] Checking that Folder::findOrMake() can create an assets/assets/ folder
* [rev:107275] Using Filesystem::makeFolder() instead of mkdir() in Folder for file operations
* [rev:107274] Better presentation of extension error message in File and !UploadValidator
* [rev:107273] Added unit tests to !FileTest and !FolderTest (some of them copied from !FileTest, to test Folder behaviour separately)
* [rev:107272] Changed !ImageTest to use fixture files located in assets/ folder, the filesystem API doesn't support Folder objects with "sapphire/..." paths, which leads to inconsistent results
* [rev:107271] Making !FileTest->setUp()/tearDown() more resilient against in-test file/folder renames
* [rev:107270] More identifiable file naming in !FileTest
* [rev:107269] Using File::get_file_extension() instead of substr() magic in File->setName()
* [rev:107269] Using exceptions instead of user_error() in File->setName()
* [rev:107268] Avoiding duplication by using existing getFullPath() in File->getAbsoluteURL()
* [rev:107267] Made File::get_file_extension() more readable, and added unit test
* [rev:107266] Removed File->setField(), doesn't have any overloaded functionality
* [rev:107265] Documentation in File and Folder class
* [rev:107214] updated generator tag URL
* [rev:107175] force exclusive connection
* [rev:107104] Added initial docs
* [rev:107030] return false rather than error out in case SS_Query:: is not a resource
* [rev:106938] mysql_fetch_row() expects resource, this will fatal if query was e.g. UPDATE when iterating a result because !MySQLQuery::nextRecord() is used by Iterator::valid() and !MySQLQuery:: is bool in this case
* [rev:106876] Making $Email available in Security_passwordsent.ss template (fixes #5737)
* [rev:106805] Added !FileTest->testValidateExtension() (related to #5693)
* [rev:106804] Documentation
* [rev:106777] Reverted r88633, it breaks <base> tag in static HTML for !ErrorPage->doPublish()
* [rev:106694] Removed trailing slash in BackURL, fixed error message sentence structure in !PageCommentInterface.ss (fixes #5520)
* [rev:106687] Fixed hardcoded error message in !PasswordValidator (fixes #5734)
* [rev:106687] Added !PasswordValidatorTest
* [rev:106568] Provide a default message for FIELDISREQUIRED
* [rev:106313] Correct typo in comments
* [rev:106248] Made CMSMainTest more resilient against database ID changes (Postgres doesn't have auto-increment resets across tests at the moment)
* [rev:106190] Fixed memory limit setting in !SapphireTest (regression from r106128)
* [rev:106187] Better checking of safe_mode in !MemoryLimitTest
* [rev:106180] Add comments for !ThumbnailStripField
* [rev:106156] Don't run memory limit tests in safe mode,
* [rev:106128] Preserve memory_limit between tests (for better PHP5.1 behaviour)
* [rev:106119] Added test for Database::hasTable().
* [rev:106090] Fixed test that required a separate Page table.
* [rev:106083] Removed db/build legacy wording in !DevelopmentAdmin (fixes #5676)
* [rev:106081] Added test for #5657
* [rev:105985] add text/plain to the list of accepted mime types
* [rev:105912] Better error handling in Form::__construct() (fixes #5649)
* [rev:105732] Clear DB checkbox unchecked by default
* [rev:105517] Installer should not repeat "Could not determine your database version" twice in slightly varied words
* [rev:105516] Show better message if couldn't find MySQL version in !MySQLDatabaseConfigurationHelper
* [rev:105305] More solid markup testing in !TableListFieldTest through xpath
* [rev:105297] Fixed !TableListFieldTest->testSelectOptionsRendering()
* [rev:105282] Using ASSETS_DIR and THEMES_DIR constant in Image, !ManifestBuilder, Requirements, File (fixes #5619)
* [rev:105281] Using ASSETS_DIR constant in !StaticPublisher (fixes #5619)
* [rev:105277] Translations
* [rev:105276] Translations
* [rev:105274] Reverted r105264, breaks !CompositeFieldTest, !FieldSetTest, !TranslatableTest
* [rev:105273] Updated !TableListField sublcass template to work with new !TableListField->!SelectOptions() setting
* [rev:105272] Fixed _t() call in !PageCommentInterface.ss
* [rev:105270] missing slash / from Requirements::css() parameter
* [rev:105267] Removed jquery.livequery as a Requirement from !LeftAndMain.php, its only necessary in !SecurityAdmin for !MemberImportForm.js now.
* [rev:105198] Fixed fixture location for !DbDatetimeTest
* [rev:105196] Added !DbDatetimeTest cases to sapphire (these were previously in the sqlite3 module, but they actually test core Database functionality)
* [rev:105188] Documentation
* [rev:105139] increased height of the todo text field in the cms
* [rev:105027] Checking for headers_sent() before setting cookies in Versioned::choose_site_stage() to avoid problems with URL parameters like showqueries=1 and !ContentController calling choose_site_stage() (fixes #5557)
* [rev:105011] Documentation
* [rev:105009] Documentation
* [rev:105005] Documentation
* [rev:104996] Documentation
* [rev:104993] Language master file
* [rev:104992] Removed duplicated code in i18nTextCollector, more defensive checks for get_owner_module()
* [rev:104980] Added translations for !BrokenLinksReport, !ReportAdminForm.ss, !AssetTableField.ss (fixes #5527, thanks Martimiz)
* [rev:104978] Allowing translation of "save" button in !SiteConfig->getCMSActions()
* [rev:104970] Translations in !PageCommentInterface.ss (fixes #5598, thanks Pike)
* [rev:104924] Reverted r104923, as current database releases of mssql and sqlite3 modules don't support this yet
* [rev:104883] Fixed hidden mbstring reliance in !SiteTree->generateURLSegment() (broken in r104679)
* [rev:104835] Save and restore lang state in test
* [rev:104798] Fixed !SiteTreeTest and !SiteTreePermissionsTest to work alongside subsites module (!SiteTreeSubsites changes the canEdit() behaviour)
* [rev:104796] Fixed !SiteConfigTest to work alongsite subsites module (!SiteTreeSubsites changes the canEdit() behaviour)
* [rev:104795] Documentation
* [rev:104769] Documentation
* [rev:104767] Documentation
* [rev:104733] fixed umlauts
* [rev:104711] Added !DirectorTest->testURLParam() and !DirectorTest->testURLParams()
* [rev:104710] Installing screen now has a page title called "Installing !SilverStripe..." instead of "PHP 5 is required"
* [rev:104709] Removed double returns in installer (redundant code)
* [rev:104708] Renamed checkdatabase method to checkDatabase to be consistent
* [rev:104705] Show install MySQL version at 5.0+ as 4.1 does not work properly with !SilverStripe
* [rev:104704] Tweaks to positioning of help text in installer
* [rev:104682] fixed api doc
* [rev:104636] added illustrator formats to the allowed extensions.
* [rev:104610] Documentation
* [rev:104598] Fixed wrong _t() notation in !ChangePasswordForm (broken in r103226 and r104596)
* [rev:104596] Making strings in !ContentControllerSearchExtension translatable
* [rev:104594] Defensive coding in !MigrateSiteTreeLinkingTask
* [rev:104490] Removed !ForumAdmin.js which shouldn't belong in the CMS module
* [rev:104483] Documentation
* [rev:104404] Documentation
* [rev:104402] Documentation
* [rev:104158] Documentation migrated from doc.ss.org
* [rev:104157] Migrated various API-style documentation from doc.ss.org
### Other
* [rev:105057] MINOT Translation in !SiteTree (#5603, thanks Pike)
* [rev:104674] ENHANCMENT: !RsyncMultiHostPublisher also rsyncs sapphire/static-main.php.
* [rev:104668] Sake fix: look for php binary before php5, to prevent errors on CentOS and Cygwin.
* [rev:104667] Added explicit bash handler to sake
* [rev:104442] Multi-use redemption page created
<code>./sscreatechangelog --version 2.4.1 --branch branches/2.4 --stopbranch tags/2.4.0</code>

159
docs/en/changelogs/2.4.2.md Normal file
View File

@ -0,0 +1,159 @@
# 2.4.2 (2010-09-22)
* Fixed a security issue where pages in draft mode might be visible to unauthenticated users
* Fixed a security issue where users with access to admin/security (but limited privileges) can take over a known administrator account by changing its password
* Allow Apache webserver to customized error pages in HTML, rather than Apache default styling
* Testing harness improvements: More verbose testing output, fixed coverage report generation
* Fixed installer logic for SQLite database drivers
* All unit tests pass on Windows OS/SQL Server
* Over 100 other improvements and bugfixes
## Changelogs
### Features and Enhancements
* [110757] added the ability to toggle the use draft site setting
* [110467] #5977 Added optional argument to !ClassInfo::getValidSubClasses() and removed harcoded !SiteTree
* [110211] disable basic auth by default, tests run on the assumption it is disabled.
* [109104] Added -v / --verbose option to dev/tests/*, to make it output every single test name before it starts that test.
* [109101] Session::set_cookie_path() and Session::set_cookie_domain() are now possible. This is useful for sharing cookies across all subdomains, for example.
* [108942] make !RestfulService support PUT method.
* [108663] ErrorDocument in default .htaccess so Apache serves default 404 and 500 server error pages
* [108644] #3828 500 server error page is created by default on dev/build
* [108499] New Member records are populated with the currently set default through i18n::set_locale()
* [108437] Restful service returns cached response on http and curl errors
* [108428] #2856 Limiting of relative URLs for Director::forceSSL() using a map of PCRE regular expressions
* [108418] Added argument to SQLQuery->leftJoin()/innerJoin() (#5802, thanks stojg)
* [108417] Full-text search with double quotes returns too many results. ticket #5733. Thanks ktauber.
### API Changes
* [110856] Member->canEdit() returns false if the editing member has lower permissions than the edited member, for example if a member with CMS_ACCESS_!SecurityAdmin permissions tries to edit an ADMIN (fixes #5651)
* [109156] #5873 !DataObjectSet::shift() now performs a proper shift instead of unshift (wrong). Please use !DataObjectSet::unshift($item) if unshifting was intended!
* [109156] Added !DataObjectSet::pop()
* [109103] Member::set_session_regenerate_id() can now be used to disable Member::session_regenerate_id() which can break setting session cookies across all subdomains of a site
### Bugfixes
* [110944] Fixed column names that were not quoted that broke PostgreSQL
* [110914] Fixed double quotes around column names in Versioned::augmentDatabase()
* [110901] delete orphaned records from versioned tables when updating. #5936
* [110894] Protect !MemberTest from side effects caused by auth_openid and forum modules
* [110889] Respecting field specific locale settings in !DatetimeField and !DateField when validating and saving values (fixes #5931, thanks Tjofras)
* [110859] Disallow addition of members to groups with !MemberTableField->addtogroup() when the editing member doesn't have permissions on the added member
* [110858] Don't suggest members in !SecurityAdmin->autocomplete() that the current user doesn't have rights to edit (fixes #5651)
* [110857] Enforcing canEdit() checks in !ComplexTableField_Popup - making form readonly if the current user can't edit
* [110838] Case insensitive !DateField value navigation (fixes #5990, thanks gw0(
* [110835] Passing $name in !MoneyField->!FieldCurrency() (fixes #5982, thanks andersw)
* [110809] Removing "typography" class from HTMLEditorField container (should just apply to the contained <iframe>) (fixes #5949)
* [110808] Allowing $extraClass on !CheckboxField !FieldHolder (fixes #5939, thanks mobiusnz)
* [110759] ensure that pages can only be requested from staging and live
* [110463] Fixed boundary PHP notice case in !RequiredFields::php() where a field name may not be defined in the $data array when a Form is submitted
* [110439] #5811 Fixed default selection of root node when CMS first opened (no currentPage set in session)
* [110262] fix !TranslatableSearchFormText by supporting fulltext search for MSSQL and using extendedSQL function call that augments queries properly (previously it was using DB::query which does not augment). Added wait to !TranslatableSearchFormText so the test actually passes.
* [110197] MigrateSiteTreeLinkingTask now takes a direct map when querying the page tracked links instead of looping through the direct result set. This fixes SQL Server failing when MARS (Multiple Active Result Sets) is disabled
* [110165] Fixed missing "Save" action input label on !ComplexTableField popup form
* [110130] force the test to wait until indexing completes. Do not use stop words ('me')
* [109834] BasicAuthTests fail when Member's unique_identifier_field is anything except the default of Email
* [109714] disable basic auth for the restful controller test
* [109712] makeRelative would return "false" for the root path, empty string is expected - fix that
* [109712] change the check in forceSSL to work on Windows - it sets the $_SERVER['https'] to off, instead of null
* [109591] getItem didn't consider the PostgreSQL SQL syntax. Columns with Capital letters must be quoted. Added quotes to the where clause in getItem. I didn't added quotes to the baseTable because it causes PostgreSQL errors (tables can not be double quoted, just single quoted).
* [109168] $val is now cast as an int to prevent strings always returning true (YES)
* [109155] Validator::requiredField() should check the required field submitted value is an array before check strlen(). Some fields submitted as an array, e.g. !MoneyField
* [109128] Remove () that was breaking coverage report
* [109106] sort order of widgets is now fixed.
* [109102] Themed permissionFailure messages
* [109083] Group::getCMSFields() should use Tab instances with a fixed name instead of translated one, leaving the translation for the tab title instead
* [109082] SiteTree decorated canView() checks not being passed through to !SiteTree::canView()
* [109081] StringField::setNullifyEmpty() should assign the given value boolean, not evaluate whether it's true or not
* [109079] Count() call on a non-object in File::!BackLinkTrackingCount()
* [109063] Fixed File::getAbsoluteURL() absolute generation
* [109062] File::getAbsoluteURL() should return a URL, not a filesystem path
* [108887] CSVBulkLoader import method now no longer requires files to end in '.csv'. Some projects want to import files in CSV format, but not of csv file type.
* [108811] Added specific border case for array form data in !RequiredFields::php()
* [108792] Fixed validation to accept arrays (!FileField case)
* [108633] NumericField javascript does not accept negatives, make use of isNaN built-in javascript function instead of custom regex
* [108515] #5627 Clear session on logout
* [108513] EMAIL_BOUNCEHANDLER_KEY cannot be defined
* [108512] Validator/!RequiredFields should not regard "0" as an empty value
* [108509] SapphireTest::create_temp_db() should restore the SS error handler from the PHPUnit one temporarily in case there's any errors building
* [108492] Undefined variable destURL in Director::forceWWW() (regression from r107094)
* [108436] Checking for existence of $('!SwitchView') (fixes #5282)
* [108432] Database password input in installer should be password, so that the password is obfuscated when input
* [108427] Take note of output format when building Location header for !RestfulServer
* [108422] CurrencyField doesn't accept negative value (#5769, thanks simon_w)
* [108421] Fixed !ContentNegotiator to handle HTML and XHTML base tags properly when converting, regression from r108413
* [108413] #5855 SSViewer::get_base_tag() should produce a properly closed base tag for XHTML (thanks smorris!)
* [108409] #5862 JSON output of JSONDataFormatter now uses quotes for keys to be safer
* [108408] Member_!ProfileForm should fallback to english text for save button if no translation defined for current language
* [108407] #5852 Missing translation for !SecurityAdmin save button causes it to have no text, should default to english "Save"
* [108400] Undefined variable when calling !DataObject::many_many_extraFields() and relation name couldn't be found for the component
* [108399] DataObjects without the Versioned decorator cannot have a "Version" field. ticket #5775. Thanks ajshort
* [108397] Added condition to avoid error creating "!PastMember" cookie on dev/build (ticket #5780) Thanks simon_w
* [108396] Applied/edited paradigmincarnate's patch to quote plaintext email with htmlEmail (#5120)
### Minor changes
* [110847] Documentation
* [110837] Check in !TableListField->!HighlightClasses() (fixes #5993, thanks lx)
* [110836] Avoid using ASP-style tags in SSViewer comments, it confuses PHP with asp_tags=ON (fixes #5976, thanks ezero)
* [110440] Warning about install.php existing for root site tree node as well (!SiteConfig form)
* [110435] German translations for cms javascript (#5921, thanks bartlomiej)
* [110243] added missing closing tag
* [110205] Make dev/build not constantly show a changed index because of whitespace between VersionID and Version in the index spec
* [110200] Removed removeDuplicates() call on linked pages !DataObjectSet in !MigrateSiteTreeLinkingTask which is no longer required, as the duplicate results were fixed in !DataObject directly
* [110190] only call next() in iterator validation on initialisation or after reset NOT if current value is invalid
* [109788] repair installer for sqlite
* [109787] repair installer for sqlite
* [109405] neatly quote identifiers
* [109382] return a fail instead of an error
* [109334] Remove whitespace if Surname field set on Member, but not !FirstName
* [109333] Tests for Member::getName() and Member::setName()
* [109330] trim space off end of firstname if surname is not set. #5925
* [109274] CSSContentParser::__construct() now gives a better error if the content could not be parsed. This will mostly happen if tidy isn't present.
* [109165] phpDoc updates for SS_!LogFileWriter and SS_!LogEmailWriter
* [109156] Unit tests for !DataObjectSet::shift(), !DataObjectSet::unshift() and !DataObjectSet::pop()
* [109152] Doc update for Director::forceSSL()
* [109127] Applied patch from walec51 for <% control %> on empty set (#5579) Also added unit tests by ischommer
* [109105] Fix links etc, and remove www. from SS urls
* [109100] Clear out the test database in between each salad scenario.
* [109066] Added tests for File::getURL() and File::getAbsoluteURL()
* [108961] remove SQL table alias keyword AS
* [108666] Fixed tests not working on the web side as redirection to https would occur
* [108665] Fixed !DirectorTest to restore it's REQUEST_URI state to the original one after each test method is run
* [108640] allow $icon to be overridden on !ErrorPages. PATCH via martljn (#5875).
* [108571] Changed unknown web server text
* [108570] Allow checking for a specific IIS version (parameter to !InstallRequirements::isIIS())
* [108569] Removed double up of similar logic in !InstallRequirements
* [108568] Simplified discovery of webserver during install
* [108561] Removed unncessary isset() check
* [108559] Add some documentation to !LeftAndMain_right.js
* [108546] Removed command line functionality from installer which is no longer used
* [108518] Fixed failing test as session being set before logging out and losing BackURL
* [108500] Fixed failing tests because of locale not being set to the default in !SapphireTest::setUp()
* [108442] Translations in CMSMain_left.ss
* [108441] Making "todo" tab title translatable
* [108435] Fixed Director::forceSSL() breaking unit tests because headers were already sent
* [108434] Reverted r108433
* [108433] DirectorTest should not extend from !FunctionalTest (regression from r108428)
* [108376] Add trailing slash to image tag (thanks to mattclegg)
* [108375] Cross-referencing some documentation
### Other
* [110241] #5870 Block web requests to silverstripe-cache directory via htaccess !RedirectMatch rule or web.config hiddenSegments functionality if using IIS 7.x
* [109177] Revert "MINOR: Applied patch from walec51 for <% control %> on empty set (#5579) Also added unit tests by ischommer"
* [109177] This was not supposed to be pushed out yet.
* [109177]
* [109177] This reverts commit 9c2aafa414948314236674e31fd756797d695139.
* [109163] Revert "BUGFIX: sort order of widgets is now fixed."
* [109163]
* [109163] This reverts commit 1e7781ba2b8ac30333a20d9a1b0bcb9b4ba5b0b0.
* [109099] Added dev/tests/emptydb to clear out test session databases.
* [108417] Using htmlentities($keywords,ENT_NOQUOTES) instead of proposed solution

350
docs/en/changelogs/2.4.3.md Normal file
View File

@ -0,0 +1,350 @@
# 2.4.3 (2010-11-11)
## Overview
* Fixed a security issue where destructive controller actions are not correctly secured against Cross-Site Request Forgery (CSRF). This affects various CMS interfaces, as well as classes based on TableListField or ComplexTableField.
* Enhance the protection of the assets/ directory in both IIS and Apache by including a file type whitelist.
* Compatibility with PHPUnit 3.5
* Allow direct test execution through the "phpunit" binary, in addition to the existing "sake" executable and TestRunner class.
* Misc. fixes to validation in date-based form fields, as well as better formatting of dates in non-default locales.
## Upgrading Notes
### Important: If you are running PHP as FastCGI with Apache
Your development environment, or production web host may be running PHP as FastCGI with Apache. If this is the case,
there is a regression in 2.4.3 which will break your site. There are two ways to resolve this problem:
- Don't upgrade to 2.4.3 for now, until 2.4.4 is released
- Patch the assets/.htaccess file like this: http://open.silverstripe.org/changeset/113809
This does **NOT** affect IIS, or other web servers that don't understand .htaccess files.
If you're not sure whether PHP is running as FastCGI in your server environment, please check the output of phpinfo().
The easiest way to do this is to open mysite/_config.php and add phpinfo() to the bottom of the file, then browse to
your site to see the environment information.
Forum references of where the community have had issues:
* http://silverstripe.org/installing-silverstripe/show/14878
* http://www.silverstripe.org/general-questions/show/14861
### Important: Add manual request forgery protection to destructive controller actions
Cross Site Request Forgery (CSRF) allows an attacker to initiate unauthorized actions against a victim with a valid
login to a target site in the same browser session, e.g. a login to SilverStripe CMS ([read more about
CSRF](http://shiflett.org/articles/cross-site-request-forgeries)).
While SilverStripe protects form submissions from CSRF automatically, destructive GET and POST actions in subclasses of
*Controller* are vulnerable without manual checks.
**You will need to review any custom subclasses of *RequestHandler* and *Controller* (including subclasses of
*FormField*), and add manual checks.** Best practice is to return a "400 Bad Request" HTTP error when the CSRF check
fails.
Also review the method signatures of any form actions - these are only protected automatically with the correct count of
parameters (//$data, $form// instead of *$request*).
:::php
// Form field actions
class MyFormField extends FormField {
// Form fields always have a reference to their form.
// Use the form-specific token instance.
function delete($request) {
$token = $this->getForm()->getSecurityToken();
if(!$token->checkRequest($request)) return $this->httpError(400);
// valid form field delete action
}
}
// Controller actions (GET and POST) without form
class MyController extends Controller {
// Manually adds token to link
function DeleteLink() {
$token = SecurityToken::inst();
$link = Controller::join_links($this->Link(), 'delete');
// will add "?SecurityID=`<random value>`"
$link = $token->addToUrl($link);
return $link;
}
// Controller actions pass through the request object,
// not called through a form.
// Use a global token instance.
function delete(SS_HTTPRequest $request) {
$token = SecurityToken::inst();
if(!$token->checkRequest($request)) return $this->httpError(400);
// valid controller delete action
}
}
// Controller actions (GET and POST) with form
class MyController extends Controller {
// Forms have CSRF protection turned on by default,
// will add a HiddenField instance called "SecurityID"
function Form() {
return new Form(
$this, 'Form', new FieldSet(), new FieldSet(new FormAction('submit'))
);
}
// Form->httpSubmission() checks for CSRF automatically,
// but you need to include both parameters in the method signature.
function submit($data, Form $form) {
// valid submit action
}
}
Note: It is regarded as good practice in HTTP to only have destructive actions in POST submissions rather than GET
links.
If you have overwritten any CMS templates (based on LeftAndMain), you will need to update them to include "SecurityID"
parameter in all manually created forms.
Affected classes and methods:
* AssetAdmin->addfolder()
* AssetAdmin->deletefolder()
* AssetAdmin->deleteunusedthumbnails()
* AssetAdmin->removefile()
* AssetTableField
* CMSMain->addpage()
* CMSMain->buildbrokenlinks()
* CMSMain->createtranslation()
* CMSMain->duplicate()
* CMSMain->duplicatewithchildren()
* CMSMain->publishall()
* CMSMain->restore()
* CMSMain->rollback()
* CMSMain->unpublish()
* CommentTableField
* ComplexTableField
* LeftAndMain->ajaxupdateparent()
* LeftAndMain->ajaxupdatesort()
* LeftAndMain->deleteitems()
* MemberTableField
* MemberTableField->addtogroup()
* MemberTableField->delete()
* MemberTableField_ItemRequest->delete()
* PageComment
* PageComment_Controller
* SecurityAdmin->addgroup()
* SecurityAdmin->addmember()
* SecurityAdmin->MemberForm()
* SecurityAdmin->removememberfromgroup()
* SecurityAdmin->savemember()
* TableListField
### Usage of Controller::join_links() to concatenate links now mandatory
The `[api:Controller::join_links()]` method
to create links within SilverStripe controllers is now mandatory. This method ensures that links with existing GET
parameters don't break through string concatenation.
:::php
// bad
$link = $this->Link() . 'export?csv=1';
// good
$link = Controller::join_links($this->Link(), 'export', '?csv=1');
Full controller example:
:::php
class MyController extends Controller {
function export($request) {
// ...
}
function Link($action = null) {
return Controller::join_links('MyController', $action);
}
function ExportLink() {
return Controller::join_links($this->Link('export'), '?csv=1');
}
}
Using this method is particularly important for any custom
`[api:TableListField]` or
`[api:ComplexTableField]` subclasses and any
`[api:LeftAndMain]` subclass for the CMS UI. These classes in
particular were refactored to secure destructive links against Cross Site Request Forgery (CSRF). This is achieved via a
mandatory "SecurityID" GET parameter appended to the base link.
### Auto-disabled "SecurityID" field in FunctionalTest
"SecurityID" tokens are now disabled by default in unit tests, to make form submissions easier.
You can manually enable security tokens, either globally or for a specific form.
:::php
class MyTest extends SapphireTest {
// option 1: enable for all forms created through this test
function setUp() {
parent::setUp();
SecurityToken::enable();
}
// option 2: enable for one specific form
function testMyForm() {
$form = new MyForm();
$form->enableSecurityToken();
}
}
## 2.4.3 Changelog
### Features and Enhancements
* [rev:113420] Validation for uploaded files
* [rev:113284] Added Form->enableSecurityToken() as a counterpart to the existing disableSecurityToken()
* [rev:113272] Added !SecurityToken to wrap CSRF protection via "SecurityID" request parameter
* [rev:112272] MySQLDatabase::renameField() no longer checks that the field exists in fieldList(). alterField() does no such check, so it should be consistent. Removing this should provide a small performance improvement as well
* [rev:111915] Added localisation for batch actions in javascript + translations
* [rev:111891] #4903 !MemberLoginForm field for "You are logged in as %s" message customisation (thanks walec51!)
* [rev:111887] #3775 Added getter to GD so you can retrieve the internal GD resource being used. Made setGD public so you can override the GD yourself as well
* [rev:111873] Show "Database Configuration" section of installer requirements for reference (collapsed by default)
* [rev:111868] MySQLDatabase::getVersion() now uses mysql_get_server_info() which has been supported since PHP 4. This gives us a better version than say "5.1", instead we now get something like "5.1.51"
* [rev:111850] Make use of mysql_get_server_info() when calling MSSQLDatabase::getVersion(), if there's a problem getting info this way, falls back to using query for VERSION() details
* [rev:111828] 6017 - Configurable help link
* [rev:111495] Making "sake" script more portable by using "/usr/bin/env" shebang instead of "/bin/bash" (fixes #6045, thanks sychan)
* [rev:111489] Added "module=" argument to !FullTestSuite (to support comma-separated module lists)
* [rev:111449] allow !PageCommentForm to store all users data, rather than hardcoding the fields
* [rev:111443] simple extend hook for !PageCommentForms. Temporary measure till #6053 is implemented
* [rev:111086] #6023 Shorten SSViewer cached template path for readability of the filenames, and also so Windows doesn't break on long paths
* [rev:111050] Added custom test listener for PHPUnit in order to call setUpOnce() and tearDownOnce() on !SapphireTest
* [rev:111048] Allowing to run single tests via phpunit through new test bootstrap XML file (e.g. "phpunit sapphire/tests/api/!RestfulServerTest.php" or "phpunit sapphire/tests/api")
* [rev:111045] Added !FullTestSuite.php, so that you can test by running "phpunit sapphire/tests/!FullTestSuite".
* [rev:111041] refactored runTests, using the new phpunit wrapper classes.
* [rev:111039] Created a phpunit wrapper class to ensure that Sapphire's test framework is capable of running unit tests, coverage report and retrieve clover-statistics for PHPUnit 3.4 and PHPUnit 3.5
### API Changes
* [rev:113282] Fixed various controllers to enforce CSRF protection through Form_!SecurityToken on GET actions that are not routed through Form->httpSubmission(): !AssetAdmin, CMSBatchActionHandler, CMSMain, !CommentTableField, !LeftAndMain, !MemberTableField, !PageComment, !PageComment_Controller
* [rev:113275] Added security token to !TableListField->Link() in order to include it in all URL actions automatically. This ensures that field actions bypassing Form->httpSubmission() still get CSRF protection
### Bugfixes
* [rev:113590] ErrorPage::requireDefaultRecords() case where no assets directory causes an fopen() error. Ensure assets directory is created before attempting to write error page files
* [rev:113419] Better checking of file validity (#6093) Thanks Pigeon
* [rev:113295] Ensure that !SearchForm searchEngine() call properly escapes the Relevance field for ANSI compliance
* [rev:113277] Clear static marking caches on Hierarchy->flushCache()
* [rev:113276] Fixed !ComplexTableField and !TableListField GET actions against CSRF attacks (with Form_!SecurityToken->checkRequest())
* [rev:113273] Using current controller for !MemberTableField constructor in Group->getCMSFields() instead of passing in a wrong instance (Group)
* [rev:113249] ModelViewer doesn't work due to minor bug introduced by making $_CLASS_MANIFEST keys lowercase (fixes #6144, thanks daniel.lindkvist)
* [rev:113247] Fixed month conversion in !DateField_View_JQuery::convert_iso_to_jquery_format() (fixes #6124, thanks mbren and natmchugh)
* [rev:113193] removed taiwans province of china
* [rev:113157] Add PHPUnit includes to !SapphireTest? class (can be loaded outside of !TestRunner? for static calls, in which case the PHPUnit autoloaders/includes aren't in place yet) (merged from r113156)
* [rev:113107] Use correct language code for jquery-ui date picker for en_US
* [rev:112961] Don't include web.config in the assets tracked in the File table.
* [rev:112288] Renamed !MySQLQuery::__destroy() renamed to __destruct() so that it is called properly after the object is destroyed
* [rev:112258] one more requirement switched to SSL
* [rev:111949] Ensure that \r carriage return characters get stripped out before setting content in HTMLValue::setContent(). DOMDocument will transform these into &#13 entities, which is apparently XML spec, but not necessary for us as we're using HTML
* [rev:111932] #6089 Avoid javascript error when "Allow drag & drop reordering" enabled, and attempt to drag a file from one folder to another is performed
* [rev:111914] #6096 RSSFeed::feedContent() restores previous state of SSViewer::get_source_file_comments() after temporarily disabling it (thanks paradigmincarnate!)
* [rev:111898] Filesystem::removeFolder() did not remove files that ended with a "." when this is a valid file. Remove the regex and replace with specific case for "." and ".."
* [rev:111890] #6066 Form::__construct() should respect hasMethod on passed in Controller instance if it's available (thanks paradigmincarnate!)
* [rev:111889] #3910 Setting timezone parameter to !MySQLDatabase::__construct() should use $this->query() to be consistent
* [rev:111878] Ensure that windows-style newlines ("\r\n") don't get converted to their XML entity representation through DOMDocument in SS_HTMLValue->setContent()
* [rev:111843] More common defaults for en_US.xml used by Zend_!DateFormat (and !DateField/!DatetimeField), with less error prone numerical format replacing the Zend default of shortened month names (fixes #6071, thanks dalesaurus)
* [rev:111843] Correct locale mapping in !DateField_View_JQuery for "en_US" and "en_NZ"
* [rev:111842] #6055 !ErrorPage should always create static error page files when dev/build is called if they don't exist
* [rev:111841] RFC 2822 compliant validation of email adresses in !EmailField->jsValidation() and !EmailField->validate() (fixes #6067, thanks paradigmincarnate)
* [rev:111772] DB::connect() should not rely on $_SESSION existing, so we check isset() to supress any warnings of undefined indexes
* [rev:111494] Changing File->Filename property from arbitrary limitation on VARCHAR (255 characters) to TEXT (65k characters) to ensure the framework can handle deeply nested filesystem trees (fixes #6015, thanks muzdowski)
* [rev:111493] Moving folder after executing Folder::findOrMake will not set the Filenames properly. Invoking updateFilesystem() in File->onAfterWrite() instead of onBeforeWrite(), and avoid caching in FIle->getRelativePath() (fixes #5994 and #5937, thanks muzdowski)
* [rev:111492] Removing overloaded !TableField->sourceItems() method, which enables features of the underlying !TableListField implementation, such as pagination and source item caching (fixed #5965, thanks martijn)
* [rev:111464] Search didn't respect searchableClasses passed to !FulltextSearchable::enable()
* [rev:111452] added validation to the page comment form
* [rev:111255] ContentController::!SiteConfig() should look to the !SiteTree record so an alternate !SiteConfig is considered, if this method doesn't exist on the data record then fall back to the default !SiteConfig
* [rev:111202] Fixed quoting and GROUP BY statement in !ManyManyComplexTableField->getQuery() for Postgres compatibility
* [rev:111176] Force tidy to avoid wrapping long lines in CSSContentParser, it breaks our !FunctionalTest string assertions
* [rev:111126] TarballArchive::extractTo() uses an incorrectly spelled argument
* [rev:111097] Fixed !PhpSyntaxTest not to rely on relative folder references (broken due to chdir() changes in cli-script.php and bootstrap.php)
* [rev:111092] Fixed regression where coverage report request did not get passed through to runTests() in !TestRunner::all()
* [rev:111091] Fixed regression of dev/tests/all running a coverage report instead of just unit tests
* [rev:111049] Unset $default_session when using Session::clear_all()
* [rev:111044] Allow execution of a test without a current controller.
* [rev:111043] Don't require a current controller for Session::get/set/etc to work.
### Minor changes
* [rev:113450] Fixed output spelling mistake and formatting in !SapphireTest::delete_all_temp_dbs()
* [rev:113430] Fixed RSSFeedTest which should put test configuration code into setUp() and tearDown() methods. If the test fails halfway through, these will get called to clean up the state
* [rev:113360] Fixed regression from r113282 for changed !SecurityToken API in CMSMain->publishall() (fixes #6159)
* [rev:113281] Removed unused !SecurityAdmin->!MemberForm() and savemember() (see !MemberTableField)
* [rev:113280] Removed unused Security->addmember() (see !MemberTableField and !SecurityAdmin->addtogroup())
* [rev:113279] Removed unused !SecurityAdmin->removememberfromgroup() (see !MemberTableField)
* [rev:113278] Removed unused !MemberList templates (see !MemberTableField)
* [rev:113274] Using !SecurityToken in !ViewableData->getSecurityID()
* [rev:113248] Javascript translations in CMSMain_right.js (fixes #6142)
* [rev:113241] Documentation
* [rev:112982] updated typo in comment for Cache.
* [rev:112962] Fix to !SapphireInfo for git-svn checkouts.
* [rev:112961] Add documentation to File::$allowed_extensions explaining that there are config files to edit in assets/
* [rev:112321] Removed "In line of " text in CLI test reporter which did not work. Details are in the backtrace below anyway, so it's not required
* [rev:112278] Reverted regression in r112272
* [rev:112254] change the requirement's link to use current protocol (we don't want messages from browsers saying the page has unsecured content, when accessing the CMS over SSL)
* [rev:111950] Comment about HTMLValue::setContent() stripping out of carriage returns
* [rev:111903] #6083 !FileTest doesn't remove test folders and files created during test
* [rev:111899] Use Filesystem::removeFolder() in !FilesystemPublisherTest::tearDown() instead of specific code to handle this
* [rev:111898] Code syntax formatting of Filesystem::removeFolder()
* [rev:111888] Moved GD::set_default_quality() function to the top of the file to align with conventions
* [rev:111883] #6090 !FilesystemPublisherTest now stores temporary files in assets, which is writable, instead of the webroot which almost never has write permissions
* [rev:111875] Enable non-default language for tinyMCE, setting language in _config.php didn't work. Thanks for @christian
* [rev:111852] Revert r111850 to !MySQLDatabase::getVersion as version comparisons need to happen, and this will strip out non-numeric characters e.g. "ubuntu1" or "lenny4" which are prefixed on some Linux distros
* [rev:111851] dev/build now shows database name and version next to "Building database ..." text
* [rev:111844] Fixed regression from r111843 (i18nText, !MemberDatetimeFieldTest, !MemberTest)
* [rev:111843] Fixed form validation message in !DateField to include actual date format, rather than a hardcoded value
* [rev:111821] Change matchesRoughly threshold slightly in !DbDatetimeTest to allow for slower database server connections
* [rev:111789] Added !FulltextSearchable::get_searchable_classes() in order to introspect currently searchable classes, added !FulltextSearchableTest, added documentation
* [rev:111788] Fixed documentation in !CheckboxSetField (fixes #6068, thanks paradigmincarnate)
* [rev:111787] Fixed documentation in Datetime (fixes #6062, thanks nicolaas)
* [rev:111786] Fixed SS_Datetime references in !BrokenLinksReport and !CommentAdmin (fixes #6063, thanks nicolaas)
* [rev:111772] Code formatting tidy of DB::connect() function
* [rev:111748] CoreTest::testGetTempPathInProject() will try to create a temp dirs when running. !CoreTest::tearDown() will now remove these temp dirs when the test finishes
* [rev:111676] #5943 Debug::text() boolean values are amended with (bool) so they don't get confused with "true" or "false" which could be strings (thanks Pigeon!)
* [rev:111669] Unit test breaks if another module or project extends Folder
* [rev:111597] Updated language master file
* [rev:111497] Fixed indentation in !PageCommentInterface.js
* [rev:111496] Fixed SQL quoting bug in !FolderTest (caused by r111493)
* [rev:111454] removed debug
* [rev:111450] removed debug
* [rev:111262] Add translation correction for Czech and add Slovakian translation in cms and sapphire (js). Thanks to @Pike
* [rev:111224] Ensuring !SiteTreeAccess.js is properly minified in live mode
* [rev:111133] Code formatting in !FullTestSuite
* [rev:111123] Spelling corrections to Director comments
* [rev:111116] PHPUnit annotations for !PhpSyntaxTest
* [rev:111053] Removing !MemberImportFormTest, breaks PHPUnit test run, and doesnt have any assertions
* [rev:111052] Documentation for constants in Core.php
* [rev:111051] Don't use chdir(), it confuses the hell out of phpunit (e.g. directory_exists() and realpath() no longer work as expected)
* [rev:111047] Fixed SSViewerTest to initialize controller properly
* [rev:111046] Remove all session data in !TestSession that might've been set by the test harness (necessary for test runs through the phpunit binary)
* [rev:111042] added phpdoc to the new PHPUnitWrapper classes.
### Other
* [rev:111880] #4029 On the fly form validation works in Opera as well
* [rev:111879] Added doc for static help_link
* [rev:111452] Fixes #2782
* [rev:111040] API-CHANGE: remove include which is not required.
* [rev:111038] ENHACENEMENT: Change behaviour of the !MenufestBuilder to use spl_autoload_register instead of traditional __autoload.
<code>sscreatechangelog --version 2.4.3 --branch branches/2.4 --stopbranch tags/2.4.2</code>

364
docs/en/changelogs/2.4.4.md Normal file
View File

@ -0,0 +1,364 @@
# 2.4.4 (2010-12-21)
## Overview
* Security: SQL information disclosure in MySQLDatabase
* Security: XSS in controller handling for missing actions
* Security: SQL injection with Translatable extension enabled
* Security: Version number information disclosure
* Security: Weak entropy in tokens for CSRF protection, autologin, "forgot password" emails and password salts
* Security: HTTP referer leakage on Security/changepassword
* Security: CSRF protection bypassed when handling form action requests through controller
* Improved security of PHPSESSID and byPassStaticCache cookies (setting them to 'httpOnly')
## Upgrading Notes
### If you're using open_basedir in PHP:
There is a bug in 2.4.4 which breaks open_basedir restriction.
The issue has been fixed in the development 2.4 branch, but you'll need to patch your existing copy of SilverStripe
2.4.4 if this affects you. The error usually occurs when you try logging into the CMS.
It can be fixed by patching your working copy with this change: http://open.silverstripe.org/changeset/115314
### Security: SQL information disclosure in MySQLDatabase
#### Description
The 'showqueries' GET parameter shows all performed SQL queries in the page output.
This is intended functionality, but should be limited websites not being in "live mode"
(set through Director::set_environment_type(), checked through Director::isLive()).
By adding an 'ajax' GET parameter you can circumvent this live check.
See Secunia Advisory: http://secunia.com/advisories/42346/
#### Solution
Don't circumvent Director::isLive() check in MySQLDatabase
#### Impact
Information disclosure of potentially sensitive information through SQL query strings.
#### Reported by
Andrew Lord, Nathaniel McHugh
#### Patches
* trunk: http://open.silverstripe.org/changeset/114782
* 2.4: http://open.silverstripe.org/changeset/114783
### Security: XSS in controller handling for missing actions
#### Description
Controller routing in SilverStripe core doesn't encode
error messages for missing URL actions before returning
them to the user (see Controller->handleAction()).
This can be reproduced with any URL that doesn't
have custom error handling defined through RequestHandler::$url_handlers,
which includes all core controllers.
Reproduce with the following URL:
`http://`<your-host>`/Security/%3Cvideo%20src=1%20onerror=%22alert%281%29%22%3E;;`
See Secunia Advisory: http://secunia.com/advisories/42346/
#### Solution
Force Content-Type: text/plain upon output.
#### Impact
Attackers can craft URLs to change the displayed website behaviour
as well as gain access to authenticated cookie information.
In case the victim has a permanent login cookie ("Remember me" checkbox),
this can lead to CMS access for attackers.
#### Reported by
Tim Suter, Andrew Horton (http://security-assessment.com)
#### Patches
* trunk: http://open.silverstripe.org/changeset/114444
* 2.4: http://open.silverstripe.org/changeset/114751
### Security: SQL injection with Translatable extension enabled
#### Description
Locale setter methods on i18n and Translatable classes are not sanitizing or whitelisting input,
which can lead to SQL injection based on "locale" GET parameters. This behaviour
is limited to websites having the (built-in) Translatable extension activated.
#### Solution
Sanitize locale values in Translatable->augmentSQL() and whitelist
locale values in i18n setters.
#### Impact
High
#### Affected Versions
* SilverStripe trunk
* SilverStripe 2.4.3 or older
* SilverStripe 2.3.9 or older
#### Provided by
Pavol Ondras
#### Patches
* trunk: http://open.silverstripe.org/changeset/114515
* 2.4: http://open.silverstripe.org/changeset/114516
* 2.3: http://open.silverstripe.org/changeset/114517
### Security: Version number information disclosure
SilverStripe exposes version information through
static files located in the webroot. As these files
have no extension, they are served without processing
by most webserver default configurations.
The files are:
sapphire/silverstripe_version
cms/silverstripe_version
See http://open.silverstripe.org/ticket/5031
See http://secunia.com/advisories/42346/
#### Solution
Reject web requests to version information through .htaccess for Apache, and web.config for IIS.
#### Impact
Version Information about the product can be used to craft attacks more specifically.
#### Reported by
Robert Mac Neil
#### Patches
* trunk: http://open.silverstripe.org/changeset/114774 http://open.silverstripe.org/changeset/114770
* 2.4: http://open.silverstripe.org/changeset/114774 http://open.silverstripe.org/changeset/114771
* 2.3: http://open.silverstripe.org/changeset/114776 http://open.silverstripe.org/changeset/114772
### Security: Weak entropy in tokens for CSRF protection, autologin, "forgot password" emails and password salts
SilverStripe uses rand(), mt_rand() in combination with
uniqid(), substr() and time() to create pseudo-random tokens.
Due to the nature of these implementations, the entropy
of tokens is low, potentially exposing them to brute force attacks.
Affected functionality:
* CSRF form protection
* Member Autologin
* "Forgot Password" emails
* Autogenerated salt values for hashed passwords in the Member table
#### Solution
Use the best available PRNG implementation on the current platform
and PHP version (favouring MCRYPT_DEV_URANDOM and openssl_random_pseudo_bytes()).
#### Impact
Weak entropy can be used for more successful brute force attacks.
#### Reported by
Andrew Horton (http://security-assessment.com)
#### Patches
* trunk: http://open.silverstripe.org/changeset/114497 http://open.silverstripe.org/changeset/114498
http://open.silverstripe.org/changeset/114503 http://open.silverstripe.org/changeset/114504
http://open.silverstripe.org/changeset/114505
* 2.4: http://open.silverstripe.org/changeset/114499 http://open.silverstripe.org/changeset/114500
http://open.silverstripe.org/changeset/114506 http://open.silverstripe.org/changeset/114507
* 2.3: http://open.silverstripe.org/changeset/114501 http://open.silverstripe.org/changeset/114502
http://open.silverstripe.org/changeset/114509
### Security: HTTP referer leakage on Security/changepassword
#### Description
The Security/changepassword URL action can be invoked with a temporary
token stored against the member record ("AutoLoginHash"). This token is set
when a member requests a new password by email through Security/lostpassword,
and cleared upon successful password change.
The token is passed as a GET parameter, which can expose it to HTTP referer
leakage, in case the member decides to navigate away from the "change password" form
before submitting the form (which would invalidate the token).
If the clicked link is an external page, the (still valid) GET parameter will appear
in the external site's HTTP referer logs, enabling third parties to take over
user accounts.
Note: This is only a problem when Security/changepassword is used without being logged-in.
#### Solution
Redirect from Security/changepassword/?h=XXX to Security/changepassword
and store the token in session instead.
#### Impact
Takeover of user accounts by third parties with access to HTTP referer logs.
#### Provided By
Andrew Lord
#### Patches
* trunk: http://open.silverstripe.org/changeset/114758
* 2.4: http://open.silverstripe.org/changeset/114760
* 2.3: http://open.silverstripe.org/changeset/114763
### Security: CSRF protection bypassed when handling form action requests through controller
#### Description
The built-in CSRF protection on forms in SilverStripe can be bypassed
by routing the action through the controller instead of the form.
Protected: mycontroller/MyForm/?action_doSubmit=1
Unprotected: mycontroller/action_doSubmit
Note: Does not apply to manual CSRF protection in controller actions
through SecurityToken->check().
#### Solution
Developers are encouraged to use Controller::$allowed_actions to limit the
actions accessible through URL routing. Methods that need automatic CSRF
protection (most form actions) should NOT be included in $allowed_actions,
their protection is handled through request handling in the form class itself.
See [security](/topics/security#limiting_url-access_to_controller_methods) documentation for more details.
#### Impact
Exposes various administrative actions (creating a new page, reverting to draft)
to CSRF attacks, in case attackers know the URL a victim has a valid CMS login for.
#### Provided By
Ingo Schommer
#### Patches
* trunk: http://open.silverstripe.org/changeset/115182 http://open.silverstripe.org/changeset/115185
* 2.4: http://open.silverstripe.org/changeset/115189 http://open.silverstripe.org/changeset/115188
* 2.3: http://open.silverstripe.org/changeset/115200 http://open.silverstripe.org/changeset/115191
## Changelog
### Features and Enhancements
* [rev:114901] Allow setting secure session cookies when using SSL. Recent change r114567 made this impossible. (thanks simon_w!) (from r114900)
* [rev:114572] 'bypassStaticCache' cookie set in Versioned is limited to httpOnly flag (no access by JS) to improve clientside security (from r114568)
* [rev:114571] Session::start() forces PHPSESSID cookies to be httpOnly (no access by JS) to improve clientside security (from r114567)
* [rev:114499] Added !RandomGenerator for more secure CRSF tokens etc. (from r114497)
* [rev:114467] PHP requirements in installer now check for date.timezone correctly being set for PHP 5.3.0+. This option is *required* to be set starting with 5.3.0 and will cause an error during installation if not
* [rev:114083] Added SS_HTTPResponse->setStatusDescription() as equivalent to setStatusCode(). Added documentation.
* [rev:113963] Split temp directory check and writability into two checks
* [rev:113961] #6206 Installer additional checks for module existence by checking _config.php exists, in addition to the directory
* [rev:113919] Allowing i18nTextCollector to discover entities in templates stored in themes/ directory (thanks nlou) (from r113918)
* [rev:113871] Update Asset's left and right panels with filders and files after 'Look for new files' was triggered (open #5543)
### API Changes
* [rev:114474] Using i18n::validate_locale() in various Translatable methods to ensure the locale exists (as defined through i18n::$allowed_locales) (from r114470)
### Bugfixes
* [rev:115189] Removing form actions from $allowed_actions in !AssetAdmin, CMSMain, !LeftAndMain - handled through Form->httpSubmission() (from r115185)
* [rev:115188] Checking for existence of !FormAction in Form->httpSubmission() to avoid bypassing $allowed_actions definitions in controllers containing this form
* [rev:115188] Checking for $allowed_actions in Form class, through Form->httpSubmission() (from r115182)
* [rev:115169] Fixed conflicting check of mysite directory with recommendation of removal of _config.php in installer
* [rev:114941] #6162 CMSMain::publishall() fails when over 30 pages (thanks natmchugh!) (from r114940)
* [rev:114922] #6219 Director::direct() validation fails for doubly nested file fields (thanks ajshort!) (from r114921)
* [rev:114823] Installer should check asp_tags is disabled, as it can cause issues with !SilverStripe
* [rev:114783] Removed switch in !MySQLDatabase->query() to directly echo queries with 'showqueries' parameter when request is called via ajax (from r114782)
* [rev:114774] Disallow web access to sapphire/silverstripe_version to avoid information leakage (from r114773)
* [rev:114771] Disallow web access to cms/silverstripe_version to avoid information leakage (from r114770)
* [rev:114760] Avoid potential referer leaking in Security->changepassword() form by storing Member->!AutoLoginHash in session instead of 'h' GET parameter (from r114758)
* [rev:114719] Fallback text for "Password" in !ConfirmedPasswordField when no translation found
* [rev:114683] Populates the page with fake data in order to pass subsequent unit tests
* [rev:114654] Test if form is the right class (if a class decorates the content controller, this test would break ie sphinx)
* [rev:114516] Escaping $locale values in Translatable->augmentSQL() in addition to the i18n::validate_locale() input validation (from r114515)
* [rev:114512] Limiting usage of mcrypt_create_iv() in !RandomGenerator->generateEntropy() to *nix platforms to avoid fatal errors (specically in IIS) (from r114510)
* [rev:114507] Using !RandomGenerator class in Member->logIn(), Member->autoLogin() and Member->generateAutologinHash() for better randomization of tokens. Increased VARCHAR length of '!RememberLoginToken' and '!AutoLoginHash' fields to 1024 characters to support longer token strings. (from r114504)
* [rev:114506] Using !RandomGenerator class in !PasswordEncryptor->salt() (from r114503)
* [rev:114500] Using !RandomGenerator class in !SecurityToken->generate() for more random tokens
* [rev:114473] Check for valid locale in i18n::set_locale()/set_default_locale()/include_locale_file()/include_by_locale() (as defined in i18n::$allowed_locales). Implicitly sanitizes the data for usage in controllers. (from r114469)
* [rev:114445] Don't allow HTML formatting in !RequestHandler->httpError() by sending "Content-Type: text/plain" response headers. (from r114444)
* [rev:114208] Including template /lang folders in i18n::include_by_locale() (implementation started in r113919)
* [rev:114195] Added !SecurityToken to !PageCommentInterface->!DeleteAllLink() (fixes #6223, thanks Pigeon)
* [rev:114083] Strip newlines and carriage returns from SS_HTTPResponse->getStatusDescription() (fixes #6222, thanks mattclegg) (from r114082)
* [rev:114081] Removed double quoting of $where parameter in Translatable::get_existing_content_languages() (fixes #6203, thanks cloph) (from r114080)
* [rev:114036] Fixed case where !AssetAdmin would throw an error if $links was not an object in !AssetAdmin::getCustomFieldsFor()
* [rev:113976] #6201 Use of set_include_path() did not always include sapphire paths in some environments
* [rev:113962] Installer now checks temporary directory is writable, in addition to it being available.
* [rev:113809] #6197 simon_w: Fixed Internal Server Error when accessing assets on Apache without mod_php.
* [rev:113692] Avoid reloading CMS form twice after certain saving actions (fixes #5451, thanks muzdowski)
### Minor changes
* [rev:114916] Ensure php5-required.html template shows correct minimum and recommended PHP versions (thanks mattcleg!) (from r114915)
* [rev:114751] Setting Content-Type to text/plain in various error responses for !RestfulServer (from r114750)
* [rev:114749] Reverting Member "!AutoLoginHash", "!RememberLoginToken" and "Salt" to their original VARCHAR length to avoid problems with invalidated hashes due to shorter field length (from r114748)
* [rev:114745] Partially reverted r114744
* [rev:114744] Reduced VARCHAR length from 1024 to 40 bytes, which fits the sha1 hashes created by !RandomGenerator. 1024 bytes caused problems with index lengths on MySQL (from r114743)
* [rev:114720] Code formatting change in !ConfirmedPasswordField::__construct()
* [rev:114454] Added exception handling if !ClassName is null in search results
* [rev:114334] Checking for class_exists() before !SapphireTest::is_running_tests() to avoid including the whole testing framework, and triggering PHPUnit to run a performance-intensive directory traversal for coverage file blacklists (from r114332)
* [rev:114079] Reverted r108515
* [rev:114078] Documentation for Aggregate caching (from r114077)
* [rev:114062] fixed visual glitch in CMS access tab for IE
* [rev:114036] Defined $backlinks as an array before adding entries to it
* [rev:114016] Fixed php tag in !SecurityTokenTest, should be "<?php" not "<?"
* [rev:113984] Installer now writes "!SetEnv HTTP_MOD_REWRITE On" in .htaccess to be consistent with the original .htaccess file that comes with the phpinstaller project
* [rev:113968] Fixed PHP strict standard where non-variables cannot be passed by reference
* [rev:113967] Fixed undefined variable $groupList
* [rev:113964] Re-use variable instead of check temp folder again
* [rev:113956] Make sure that Translatable creates a translated parent of !SiteTree only when the parent is not translated (from r113955)
* [rev:113937] don't trigger notice but Debug::show it
* [rev:113936] don't trigger notice but Debug::show it
* [rev:113933] test doesn't fail anymore due to time differences between db and php. The test now issues notices, warnings and errors depending on the severity of the offset
* [rev:113924] Fixed spaces with tabs in Core
* [rev:113923] Fixed spaces with tabs for Core::getTempFolder()
* [rev:113696] call jquery-ui from thirdparty folder instead google api (see ticket 5915) (from r113656)
* [rev:113695] Typo in !AssetAdmin (fixes #6191, thanks Juanitou)
* [rev:113690] Updated cs_CZ and sk_SK translations in sapphire/javascript (fixes #6085, thanks Pike)
* [rev:113689] Making some !JavaScript strings in cms/javascript translatable, and updated their cs_CZ and sk_SK translations (fixes #6085, thanks Pike)
### Other
* [rev:114464] FIX: Revert last commit
* [rev:114463] FIX: Revert last commit

View File

@ -0,0 +1,41 @@
# 2.4.5 (2011-02-02)
## Overview
* Enhancement: File->canEdit() and File->canCreate() now use extendedCan()
* Enhancement: Installer check for magic_quotes_gpc (PHP option) and issues a warning if enabled
* Bugfix: CMSMain->rollback() fails because of CSRF protection
* Bugfix: Valid file uploads with uppercase extensions blocked from being web accessible
* Bugfix: Page comments saving onto wrong page
* Bugfix: Incorrect call to weekday function in Date class
* Bugfix: SilverStripeNavigator error in case where page is not published, viewing archived site
## Changelog
### Features and Enhancements
* [rev:115416] Changed canEdit and canCreate extend to extendedCan
* [rev:115265] Installer now checks for magic_quotes_gpc being turned off. This option turned on can cause issues with serialized data in cookies when unserializing (from r115264)
### Bugfixes
* [rev:115816] #6321 Whitelisted file extensions with uppercase extensions blocked by case sensitive FilesMatch directive in assets/.htaccess (does not affect IIS 7.x which uses web.config)
* [rev:115720] transaction function names fixed
* [rev:115460] DateField wrong datepicker-%s.js path (fixes #6296, thanks martijn)
* [rev:115443] Incorrect call to weekday function in Date class (thanks webbower!)
* [rev:115442] Checking for existence of draft and live records in SilverStripeNavigatorItem_ArchiveLink->getHTML() (from r115130)
* [rev:115440] #6291 Remove rollback action from CMSMain allowed_actions and rely on form action_rollback instead which is safer
* [rev:115437] Fixed edge case bug where SilverStripeNavigatorItem would fail if a page was not published, and the navigator archive link was generated
* [rev:115399] #6304 PageCommentInterface::PostCommentForm() loads inappropriate data from cookie, including wrong values for ParentID
* [rev:115379] #6299 TableListField::Link() includes $action value twice (thanks ajshort!)
* [rev:115314] #6287 open_basedir restriction breaks RandomGenerator when trying to read dev/urandom
* [rev:115313] Allowing CMSMain->rollback() outside of form contexts, temporariliy disabling CSRF protection. Necessary in order to get rollback actions working from admin/getversion (regression from 2.4.4 release, see #6291)
### Minor changes
* [rev:115854] #6397 CoreTest should use test specific paths, otherwise conflicts can occur in certain environments
* [rev:115461] Fixed en_US spelling (fixes #6316, thanks sonetseo)
### Other
* [rev:115723] Reverted to revision 101592

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -0,0 +1,385 @@
# 2.4.0-alpha1 (2009-11-11)
## Changelog
### Overview
* Support for hierarchical URLs
* Support for MSSQL server database abstraction (via a separate module)
* A "SiteConfig" record stores site-wide settings and default permissions and author groups for pages
* "Permission Roles" are a simple way to combine multiple permission codes and assign them to groups in the Security interface. This makes permissions easier to maintain and less repetitive to set up.
* The CMS searches for broken internal links to other pages and broken file references, and highlights them in the WYSIWYG editor
* Dramatically reduced memory usage in CMS tree on larger sites (10,000+)
* Performance improvements around Object and ViewableData property access.
* Improved Shortcode API to allow for custom tag parsing in CMS content
* More fine-grained permission control for translators
* Improved unit test execution speed, increased number of tests cases by 30%
* Better XSS security of the autologin token by using HTTPOnly cookies, more secure brute force login restrictions
* Decreased memory usage in "Files & Images" section
### New Features
* [rev:91044] Added Session::destroy() as a means to remove the current session using session_destroy()
* [rev:90036] Allow Text/Varchar fields to be configured to differentiate between NULL and empty string. (#4178, petebd)
* [rev:89827] If there is no Name set, but there is an author, use the author's name (from r89650)
* [rev:89221] batch actions for setting/resetting embargo/expiry (from r85397)
* [rev:89194] SiteConfig (from r85339)
* [rev:89193] Add a simple interface for administrating permission roles. (from r85297)
* [rev:89190] SiteConfig (from r85339)
* [rev:89189] Add a simple interface for administrating permission roles. (from r85297)
* [rev:89176] Add another permission code that allows users to edit siteconfig without having admin priveleges (from r87261)
* [rev:89157] Virtual pages now copy allowed children from the page they are
* [rev:88992] Added MigrateSiteTreeLinkingTask to allow plain HTML links to be migrated into shortcode links. From: Andrew Short
* [rev:88516] Added a SideReport to display all pages with broken page or file links. From: Andrew Short
* [rev:88510] Re-instated broken link highlighting by manually checking all shortcodes in HtmlEditorField->Field(), and adding a class to broken ones. From: Andrew Short
* [rev:88508] Added RequestHandler->allowedActions() to return a unified representation (including extensions) of all allowed actions on a controller.
* [rev:88505] Added RequestHandler->hasAction() and Controller->hasAction() to check if a specific action is defined on a controller.
* [rev:88503] Updated SiteTree::get_by_link() to integrate with translatable, and allow it to work across languages by implementing Translatable->alternateGetByLink().
* [rev:88496] Refactored RootURLController to allow nested home pages.
* [rev:88492] Updated HtmlEditorField to use DOMDocument to more reliably parse image tracking and shortcode link tracking data. From: Andrew Short
* [rev:88484] Added SiteTree::get_by_link() to fetch the SiteTree object associated with a nested link.
* [rev:88483] Allow you to access nested pages by falling over to a child page in ContentController if one is available. From: Andrew Short
* [rev:88481] Allow you to link to SiteTree? objects in HTMLText or HTMLVarchar fields by using a "[sitetree_link id=n]" shortcode. From: Andrew Short
* [rev:88474] Refactored ViewableData. The main changes are:
* [rev:88472] Added the Shortcode API (ShortcodeParser) to allow you to replace simple BBCode-like tags in a string with the results of a callback. From: Andrew Short
* [rev:88468] Added utility methods to enable and disable nested URLs to SiteTree. From: Andrew Short
* [rev:88104] added extend() call to enable FieldHolder() html to be customized via extensions.
* [rev:85789] Added Widget_Controller class to enable nested forms within Wiget class.
### API Change
* [rev:91048] Added Lower and Upper methods to Varchar, Text, and Enum
* [rev:90963] Allow fieldList arguments to Form::loadDataFrom() and Form::saveInto(), for situations where the data passed only applies to a segment of the form. (from r90872)
* [rev:90962] Inserting $HiddenFields into a form template will show the input tags of all the hidden fields. (from r90871)
* [rev:90097] replaced Database::alteration_message() with DB::alteration_message()
* [rev:90076] Renamed conflicting classes to have an "SS_" namespace, and renamed existing "SS" namespace to "SS_". The affected classes are: HTTPRequest, HTTPResponse, Query, Database, SSBacktrace, SSCli, SSDatetime, SSDatetimeTest, SSLog, SSLogTest, SSLogEmailWriter, SSLogErrorEmailFormatter, SSLogErrorFileFormatter, SSLogFileWriter and SSZendLog.
* [rev:90075] Renamed conflicting classes to have an "SS_" namespace, and renamed existing "SS" namespace to "SS_". The affected classes are: HTTPRequest, HTTPResponse, Query, Database, SSBacktrace, SSCli, SSDatetime, SSDatetimeTest, SSLog, SSLogTest, SSLogEmailWriter, SSLogErrorEmailFormatter, SSLogErrorFileFormatter, SSLogFileWriter and SSZendLog.
* [rev:90059] Added dev/tests/build, which runs everything, meaning that dev/tests/all doesn't need to run PhpSyntaxTes
* [rev:89988] Add extra classes to WidgetHolder (#3855, patch from jshipman)
* [rev:89841] Fixed change in r89716 to be more semantic with FileIFrameField
* [rev:89726] TableListField customQuery and customCsvQuery won't automatically include ID, ClassName, and RecordClassName fields (from r87354)
* [rev:89708] Change the way that Database::requireField() gets field type information from the underlying database driver. (from r82793)
* [rev:89209] Added SapphireTest::logInWithPermission() (from r89012)
* [rev:89205] Don't automatically set a default action on complex table fiels. It leads to too many accidental clicks when trying to click a non-default action. Still allow for people to explicitly select a default action. (from r88961)
* [rev:89187] Added PermissionRole and PermissionRoleCode, along with relevant tests for the permission system. (from r85173)
* [rev:88991] Updated Form->FormAction() to use Controller::join_links() rather than relying on the action parameter (to preserve b/c). From: Andrew Short
* [rev:88797] HTTPRequest and HTTPResponse no longer inherit from Object, since they should not be extended. From: Andrew Short
* [rev:88700] SSViewer and SQLQuery no longer inherit from Object, since they should not be extended. From: Andrew Short
* [rev:88632] Added Debug::$friendly_error_header and Debug::$friendly_error_detail for customising the friendly error message. (from r69855)
* [rev:88507] Decoupled ErrorPage::response_for() from the request and updated it so it will only return a response if an appropriate error page can be found.
* [rev:88503] Moved lang_filter enabling & disabling into static methods on Translatable, and renamed to locale_filter.
* [rev:88495] #3724: Unified the Link() method to accept an action parameter. From: Andrew Short
* [rev:88296] support for advanced database options now included
* [rev:88295] The advancedOptions variable now passed to the database connection
* [rev:88294] $database_extensions static variable now supported
* [rev:88293] The advancedOptions variable now passed to the database connection
* [rev:88123] Requiring TRANSLATE_ALL or TRANSLATE_`<locale>` permission for authors without administrative access to edit translations
* [rev:87894] array brackets removed for generation of field types
* [rev:87893] Transaction stubs created
* [rev:87568] array data type now supported
* [rev:87567] array data type now supported
* [rev:87566] array data type now supported
* [rev:87565] array data type now supported
* [rev:87564] array data type now supported
* [rev:87563] array data type now supported
* [rev:87562] array data type now supported
* [rev:87561] array data type now supported
* [rev:87560] array data type now supported
* [rev:87559] array data type now supported
* [rev:87558] array data type now supported
* [rev:87557] array data type now supported
* [rev:87555] array data types now supported by dev/build
* [rev:87087] Added name argument to DB::getConn() and DB::setConn(), so that you can store multiple named connections.
* [rev:86006] Removed Permission->listcodes(), use custom code
* [rev:86002] Don't exempt 'index' controller actions from $allowed_actions check - they might still contain sensitive information (for example ImageEditor). This action has to explicitly allowed on controllers with $allowed_actions defined now.
* [rev:85789] Removed unnecessary WidgetFormProxy class and Widget->FormObjectLink(), broken functionality since the RequestHandler restructuring in 2.3. Use Widget_Controller instead.
* [rev:85073] Added DataObjectSet assertions to SapphireTest
* [rev:85028] Added comparison argument to SSLog::add_writer()
* [rev:84828] Added SSLogFileWriter to replace Debug::log_errors_to() and Debug::log_error_if_necessary() - the existing formatting for the Debug deprecation functions is now wrapped into SSLogErrorFileFormatter
* [rev:84774] Debug::send_errors_to() and Debug::send_warnings_to() are deprecated in favour of SSLog. See class documentation for SSLog on configuration of error email notifications
* [rev:84570] added onAfterSave in LeftAndMain
* [rev:84523] Refactor CMSMenu internals to not generate the menu item list until its actually needed, rather than from a CMSMenu::populate_menu() call in cms/_config.php. This lets an app/_config.php file actually manipulate the menu.
* [rev:84521] If you can't create a given dataobject type, then don't show an import form in modeladmin
* [rev:84161] Deprecated DataObject::databaseFields() in favour of the static DataObject::database_fields()
* [rev:84160] Extension no longer inherits from Object.
* [rev:84151] Make Object::uninherited_static() have a separate execution path to Object::get_static(), for more reliable operation. The intention is that for any given static, you either use Object::get_static() or you use Object::uninherited_static() - not both.
* [rev:84061] Database and Query no longer inherit from Object, since they shouldn't be extended with Extensions.
### Bugfixes
* [rev:91209] Return correct error when 404 page doesn't exist and page is not found.
* [rev:91203] Fix concurrent editing message always being displayed on page version history.
* [rev:91156] Returning TRUE on Translatable->hasTranslation() if called on a record that is in the current locale (merged from r91032)
* [rev:91047] Don't failover to standard value in ViewableData_Customised if the customised value is defined but isn't set. $obj->customise(array('Content'=>'')) should set Content to ''
* [rev:91045] Session::destroy() should make use of setcookie() to remove the cookie from the user, unsetting the superglobal doesn't unset from the browser
* [rev:91036] Added setup/teardown methods to SiteTreeBrokenLinksTest? to make it work with Translatable enabled (merged from r91033)
* [rev:90964] use second argument only if its an array (from r90927)
* [rev:90936] Fixed pages not being manipulated properly in the CMS because of a PHP error in CMSBatchAction
* [rev:90934] MSSQL does not support double, using float instead (from r90928)
* [rev:90876] Added ContentController->successfullyinstalled() to $allowed_actions
* [rev:90857] applied patch from #4381. Observable doesnt play nice with jQuery (from r82094)
* [rev:90855] Added rewriteHashlinks = 'php' option to SSViewer so that static publisher can handle internal hashlinks properly. (from r89612)
* [rev:90854] Pass locale rather than language to spellchecker_languages (from r87869)
* [rev:90853] Fixed Links to Moderate Comments from the CMS and front end. MINOR: removed complextable functions which no longer get called, moved logic to the PageComment Class (from r86325)
* [rev:90852] Tied rollback action to edit, rather than publish, permission, since it only involves editing the draft site. (from r84957)
* [rev:90851] Fix Form.FieldMap, used when constructing forms that have the HTML explicitly specified.
* [rev:90850] Allow null default on MultiEnum fields
* [rev:90849] Fixing the comment's author website url being converted to lowercase: now case is not affected. (from r84380)
* [rev:90848] CMSMenuItem constructor now calls parent to respect inheritance (from r83586)
* [rev:90845] Fixed bugs in content differencer, and improved styling. BUGFIX: fixed notice when getting title of member which didnt exist. Merged from trunk r77661. (from r81942)
* [rev:90842] Added rewriteHashlinks = 'php' option to SSViewer so that static publisher can handle internal hashlinks properly. (from r89611)
* [rev:90834] was being passed to foreach without a check to see if it's an array or not. (from r86202)
* [rev:90833] Added required javascript files (behaviour, prototype, prototype_improvements) to the Field() method of TreeSelectorField.php (from r84320)
* [rev:90831] WidgetArea now works. Can have multiple areas on a page, and has unit tests
* [rev:90747] Fixed Text::scaffoldFormField() showing a "Is Null" checkbox, even if nullifyEmpty is true
* [rev:90644] Fixed "Class not found CMSBatchAction_Unpublish ..." in BatchActionHandler.php, since this class was removed in r90489
* [rev:90632] Make DataObject::dbObject('ClassName') work.
* [rev:90595] When deleting a WidgetArea, delete all the widgets it contains.
* [rev:90554] #4609: Fixed portoguese locales in common locales list.
* [rev:90553] #4617: Make delete formatted images case-insensitive.
* [rev:90552] #4642: Fixed creation of folders in non-english languages.
* [rev:90551] Fixed glitch in permission code formats.
* [rev:90550] Fixed glitch in permission code formats.
* [rev:90548] #2476: Rename lowercase tables to correct casing if they have been transferred from a windows box.
* [rev:90547] #4063: Corrected base tag for IE6
* [rev:90196] fixed typo
* [rev:90082] Don't skip flushCache() extension if $cache_get_one is empty on DataObject->flushCache()
* [rev:90056] UTF-8 byte order mark gets propagated from template files (#4357)
* [rev:90051] Remove blockquote from tinymce default plugin list - blockquote isnt a plugin in tinymce3.
* [rev:90047] Some places want tableList() to have lower case, some want native case - return both!
* [rev:90023] Security::$default_login_dest isn't used (#4179, simon_w)
* [rev:90020] Reenable setting size on HasManyComplexTableField popups (#3921, rjmackay)
* [rev:89911] Fixing regression in TranslatableTest due to outdated singleton caching.
* [rev:89893] Moved SINGLETON resetting for test runs from SiteTreeTest/ObjectTest into SapphireTest - there should be no caching between all test invocations to avoid side effects
* [rev:89881] Reset $_SINGLETONS cache in SiteTreeTest::tear_down() to avoid stale Translatable information. This broke SiteTreePermissionTest and SiteTreeTest when running in parallel with Translatable enabled.
* [rev:89864] Added setup/teardown methods to CMSMainTest to fix test breakages when used alongside cmsworkflow module (which unsets the public batch action)
* [rev:89863] Added setup/teardown methods to SiteTreeBacklinksTest to make it work with Translatable enabled
* [rev:89825] Fix comment feed on SQLServer (from r89641)
* [rev:89823] Made dragndropping possible for folders in ajax-expanded tree. Also fixed glitch in r82534 that made page drag and drop impossible (from r82571)
* [rev:89821] repaired dragndropping files into nested directories - now code refers to the updated object which is initially hidden and zero sized (from r82534)
* [rev:89812] If image does not exist in the file system, don't show a non-object error when viewing the Image/File record in AssetTableField (from r82390)
* [rev:89811] Paging of search results now works for AssetTableField by overloading the TableListField link methods (from r81190, r82188)
* [rev:89798] Removed double up of classes in TestRunner::coverage() (from r88463)
* [rev:89731] Fixed ModelAdmin_CollectionController->Link() return value
* [rev:89719] Folder::syncChildren() now uses far less memory - we do this by destroying the child object memory after use (from r82780)
* [rev:89718] Fixed array to string conversion error in Date::setValue() (from r82749)
* [rev:89716] disabling user ability to upload images into the CMS from their local computer (from r82573)
* [rev:89715] Ensure that FileIFrameField gets the proper class, this could be a subclass of File instead
* [rev:89714] Ensure that before creating default 404 error page, we don't have one already that exists with a record ID (from r81991)
* [rev:89460] Hard code the migration task to use Content instead of the no-longer-used FieldName. This should probably be improved to iterate over all HTMLText fields on the model.
* [rev:89444] Removed SiteTree::rewriteLink() method that is no longer necessary due to the use of shortcodes.
* [rev:89338] Respecting SiteTree->canDelete() in SiteTree->getCMSActions()
* [rev:89333] Removed 'name' attribute from HeaderField markup - its invalid HTML to put in `<h*>` elements (#4623)
* [rev:89328] Fixed CMSSiteTreeFilter
* [rev:89236] Fixed SiteTree->validURLSegment() to perform a DataObject::get_one() instead of raw SQL, in order for decorated filtering (e.g. by the subsites module) to apply correctly.
* [rev:89215] Detect a brokenh link on an incompletely specified redirector page. (from r89043)
* [rev:89213] Fixed link generation in CTF default action (from r89026)
* [rev:89208] Fixed image link rewriting and added a test. (from r89011)
* [rev:89206] Fixed diabled image references for edit and delete links in CTF (from r88967)
* [rev:89204] If a CTF without a show action is made readonly, don't add the show action back. (from r88960)
* [rev:89203] Fixed resolution of amibiguous has_many foreign keys in ComplexTableField to use the same logic as DataObject (from r88945)
* [rev:89200] Fixed inversion of condition created in r88869 (from r88905)
* [rev:89199] AuthorID field for page version history wasn't being set. (from r88894)
* [rev:89183] Fixed generation of static cache files in subdirectories. (from r88569)
* [rev:89177] Fix image tracking not working cross subsite (from r88008)
* [rev:89175] Fix broken link tracking of linked files (from r87252)
* [rev:89172] Fix error when adding roles tab (from r86997)
* [rev:89170] Fix image tracking to take resized images into account (from r86198)
* [rev:89169] Fix items not deleting on tablefields (from r86099)
* [rev:89163] Fixed RequestHandler->allowedActions() lowercasing of actions - was applying the logic, but not writing it back to the $actions array.
* [rev:89161] Don't return empty value from ViewableData->XML_val() if the actual value is an uncasted 0 integeter (or anything else evaluating to untyped boolean false)
* [rev:89003] Added PageComments to ContentController::$allowed_actions so commenting works. From: Andrew Short
* [rev:88989] Reset broken file & link flags in HtmlEditorField->saveInto() before determining if a record contains broken links. From: Andrew Short
* [rev:88957] Fixed missing default english text for "Clear" and "Search" buttons in template CMSMain_left.ss
* [rev:88956] #4605 DataObject::newClassInstance() should repopulate it's defaults after changing to an instance of a different class, otherwise databases will complain of NULL values being written to columns that don't accept NULL values.
* [rev:88799] Updated ModelAsController->findOldPage() query to be cross-database compatible. From: Andrew Short
* [rev:88774] Stopped HtmlEditorField->saveInto() from dying when encountering a link that cannot be made relative. From: Andrew Short
* [rev:88773] Suppressed errors in SS_HTMLValue->setContent() so it can handle malformed HTML.
* [rev:88752] error messages suppressed as a temporary fix
* [rev:88664] Fixed bugs in ViewableData casting system. From: Sam Minnee
* [rev:88639] Set publication base_url on every URL, just in case it gets re-set by some rogue script (from r73510)
* [rev:88523] Fix regression in r88521 that prevented the index action from being explictly disabled by setting the * key in allowed_actions
* [rev:88522] Improved reliability of PhpSyntaxTest on build slave.
* [rev:88521] Ensure that the index action works even if allowed_actions is set.
* [rev:88513] #3858: Updated StaticExporter to handle nested pages. From: Andrew Short
* [rev:88512] #3724: Updated Link() methods to accept an action parameter. From: Andrew Short
* [rev:88508] Updated Controller->hasAction() to use RequestHandler->allowedActions() so that extension actions are recognised. From: Andrew Short
* [rev:88503] Fixed viewing a translatable page by URL without explicitly setting a Locale in ContentController->handleRequest(). From: Andrew Short
* [rev:88494] Fixed Controller::join_links() to properly handle multiple consecutive slashes. From: Andrew Short
* [rev:88493] Use Link() on the controller to generate to form action path. From: Andrew Short
* [rev:88473] #3862: Explicitly defined browsing and viewing actions on CodeViewer. From: Andrew Short
* [rev:88471] #2133: Removed UniqueTextField JavaScript that was causing URLSegments to be incorrectly rewritten if they had a number at the end. From: Andrew Short
* [rev:88469] Updated HTTP::findByTagAndAttribute() to be more versatile, especially when dealing with attributes containing special characters. From: Andrew Short
* [rev:88218] #3685: Fixed setting of character set by default when no content negotiator is used.
* [rev:88145] Added setup/teardown routines to SiteTreeActionsTest to avoid breaking with Translatable enabled on recent canTranslate()/canEdit() extensions
* [rev:88143] Added setup/teardown routines to SiteTreeTest and SiteTreePermissionsTest to avoid breaking with Translatable enabled on recent canTranslate()/canEdit() extensions
* [rev:88139] Changed CMSMain->LangSelector() to always return a DropdownField, which ensures the 'Locale' parameter is always available to be passed along with ajax queries
* [rev:88138] Filter both 'available' and 'new' languages in LanguageDropdownField for canTranslate() permissions
* [rev:88124] Added required permissions to TranslatableSearchFormTest
* [rev:88003] Fixed CSVBulkLoaderTest not to assume ID ordering in the assertions, which breaks with databases not ordering by PK automatically (e.g. Postgres)
* [rev:88000] Fixed SearchContextTest capitalization of string assertions
* [rev:87926] Fixed SearchFilterApplyRelationTest not to assume ID ordering in the assertions, which breaks with databases not ordering by PK automatically (e.g. Postgres)
* [rev:87925] Fixed SoapModelAccessTest not to assume ID ordering in the assertions, which breaks with databases not ordering by PK automatically (e.g. Postgres)
* [rev:87922] Fixed RestfulServerTest not to assume ID ordering in the assertions, which breaks with databases not ordering by PK automatically (e.g. Postgres)
* [rev:87913] Fixed ID associations in TableListFieldTest (was assuming numerically ascending IDs, which isnt necessarily true in Postgres)
* [rev:87897] tests which aren't supported by Postgres temporarily disabled
* [rev:87456] #4579: Translatable's call to new LanguageDropdownField() broked
* [rev:87234] Fix MemoryLimitTest not to fail on machines with <1G of memory and later versions of PHP 5.2.x that check available memory before setting memory_limit setting.
* [rev:87228] Fixed bug in recent changes to Hierarchy::liveChildren() to do with Translatable
* [rev:87210] Fixed Hierarchy::liveChildren() to work on PostgreSQL
* [rev:87131] Don't throw a notice-level error in DB::getConn() if connection hasn't been set yet, to mimic previous behaviour.
* [rev:86876] Fixed content-type for SapphireSoapServer->wsdl() (#4570, thanks Cristian)
* [rev:86556] missplaced quotes were ruining unit tests
* [rev:86532] $params variable removed
* [rev:86414] Fixed SearchFilterApplyRelationTest to match new SearchContext->addFilter() API: Needs the full name including relation instead of the ambiguous stripped name. This matches DataObject->scaffoldSearchFields() and getDefaultSearchContext()
* [rev:86218] Initializing controllers through init() in WidgetArea->WidgetControllers()
* [rev:86217] Return FALSE in SapphireTest->assertDOSEquals() if no valid DataObjectSet is passed in
* [rev:86170] ID column in delete function now quoted properly
* [rev:86085] Don't lowercase permission codes contained in $allowed_actions in RequestHandler->checkAccessAction(). Permission checks are case sensitive.
* [rev:86060] Made SecurityAdminTest more resilient against changes to localized strings, by inspecting the CSV line-by-line instead
* [rev:86008] Consistently returning from a Security::permissionFailure() to avoid ambiguous situations when controllers are in ajax mode
* [rev:85817] Fixed WidgetControllerTest by adding missing url routing to ContentController (see r85789)
* [rev:85758] Detecting DataObjectSet for readonly transformations in CheckboxSetField (thanks martijn, #4527)
* [rev:85713] moved $versionAuthor variable invocation into a check for the existence of the $record variable on which it depends (Ticket #4458)
* [rev:85696] Ticket #4220 - Copying of uploaded files from temp to assets folder fails on IIS installs; simple patch fixes it
* [rev:85514] More robust URL handling in SecurityTest to avoid failing on custom /admin redirects
* [rev:85513] More robust URL handling in CMSMainTest to avoid failing on custom /admin redirects
* [rev:85336] Fixed SiteTree::can_edit_multiple() and canEdit() to collect permissions from different Versioned tables, which fixes querying a SiteTree record which has been deleted from stage for its permissions (e.g. in SiteTreeActionsTest)
* [rev:85330] Disabled PHPUnit backup of global variables, which caused i18n::_t() calls in subsequent test cases to fail because of a cached empty global
* [rev:85310] Limiting i18n::include_by_locale() to scan directories only
* [rev:85281] Implementing TestOnly interface in ModelAdminTest to avoid having it included automatically in CMSMenu and hence breaking other tests like LeftAndMainTest.
* [rev:85157] #4423: Don't allow page duplication if canCreate is false.
* [rev:85136] #3713 Escape HTTP request URL properly in DebugView::writeError() using htmlentities()
* [rev:85130] merge r 85079 from branches/iss to fix Payment Validation of php side when submit a OrderForm
* [rev:85120] Fix the bug in buildSQL() by trying to join an table with non-exsiting composite db field like "Money"
* [rev:85086] #4463: Set AuthorID and PublisherID correctly
* [rev:85085] Use default File classname in Folder::syncChildren()
* [rev:85076] #3228 Fixed undefined offset error in Text::BigSummary() if trying to summarise text that is smaller than the requested word limit
* [rev:85039] SelectionGroup.js typo, prevAl()l change to nextAll()
* [rev:84980] Fixed issues with recent CMSMenu refactoring.
* [rev:84976] SelectionGroup should include jQuery and jQuery livequery plugin when it's used or it will fail
* [rev:84971] Fixed code for regenerating cached test manifest.
* [rev:84843] #4486 Make use of DataObject::get_by_id() in File::getRelativePath() instead of building ID query manually in a get_one()
* [rev:84796] Fixed querying of composite fields (broken due to inappropriate optimisation of hasField)
* [rev:84789] Reverted some changes from r84163 because they broke cases where you have two fields of the same name on different subclasses.
* [rev:84167] Performance improvement to Member::currentUserID()
* [rev:84166] Performance imporvement to i18n::include_by_locale
* [rev:84164] Removed deprecated (and slower) eregi_replace
* [rev:84162] Removed some code that needed Extension to extend from Object.
* [rev:84156] Ameneded r84151 so that the application order of extensions is the same as it was previously.
* [rev:84155] Ameneded r84151 so that the application order of extensions is the same as it was previously.
* [rev:84147] Added static resetting methods for more reliable test execution.
* [rev:84093] Fixed SQLQuery::filtersOnID() for cases where a ClassName filter is inserted before the ID filter.
* [rev:84092] Fixed filtering by archive date
* [rev:84086] an time field input between 12:00pm to 12:59pm can't save back to database or always save as 00:00:00.
* [rev:84079] VirtualPages won't call SiteTree_Controller anymore.
* [rev:84068] Restored SiteTree::canView() functionality.
* [rev:84066] Fixed some bugs in the performance fixes on Permission
* [rev:84065] Fixed manifest builder tests to not have fake data, and to test that classes can be in files with different names
* [rev:84064] Removed Requirements::combine_files() reference to non-existent cms/javascript/FilterSiteTree.js
* [rev:84063] Don't make the Director completely fail if there was output prior to session_start() being called.
* [rev:84000] prevent a nasty permissions situation where no one but an admin can edit a new page
* [rev:83999] prevent a nasty permissions situation where no one but an admin can edit a new page
* [rev:83970] Using standard SQL and SSDatetime::now() in SideReport_RecentlyEdited (see #4052)
* [rev:83969] Fixed SiteTreeActionsTest to use unconditional class defintion - was failing due to recent changes in ClassInfo and class_exists()
### Enhancement
* [rev:91044] Added optional $sid parameter to Session::start() to start the session using an existing session ID
* [rev:90084] Changed Hierarchy->numChildren() caching to be instance specific and respect flushCache(). This increases the amount of queries on large sets, but decreases the time for a single instance call (implemented in r89999)
* [rev:89999] Only run a single query per class for Hierarchy::numChildren()
* [rev:89883] Improved CMSSiteTreeFilter API to make it easier to create custom filter.s (from r89071, from r88465)
* [rev:89820] Current search and current page of asset section are persistent. Fixes the open source ticket #4470 and also a part of #4256 (from r84091)
* [rev:89815] FilesystemSyncTask: If folderID GET parameter is available, only synchronise that folder ID - useful for only synchronising a specific folder and it's children (from r82841)
* [rev:89813] Return the results of the FilesystemSyncTask to the status message in the CMS instead of a generic success message (from r82618)
* [rev:89724] Filesystem::sync() now accepts a folderID argument, meaning you can specifically target a folder and it's children to sychronise, instead of everything (from r82840)
* [rev:89717] Filesystem::sync() will now return the number of added and deleted files and folders instead of null (from r82616, 82617 and 82724)
* [rev:89182] Fixed sapphire execution if you run the uninstalled sake from a foreigh directory. (from r88533)
* [rev:88635] Added Member::set_login_marker_cookie(), to let developers bypass static caching for logged-in users (from r73803)
* [rev:88633] Make base tag in 404 page dynamic (from r72282)
* [rev:88570] Improved performance of ViewableData casting by removing an object::get_static call From: Sam Minnee
* [rev:88518] #3729: Updated the link inserter to insert a shortcode rather than a plain HTML link. From: Andrew Short
* [rev:88505] Updated ContentController->handleRequest() to use Controller->hasAction() to check whether to fall over to a child page, rather than relying on an error response from Controller->handleRequest(). From: Andrew Short
* [rev:88504] Cached the value for RootURLController::get_homepage_link() between calls. From: ajshort
* [rev:88502] Updated the SiteTree URLSegment conflict resolver to work with nested URLs.
* [rev:88501] Updated SiteTree CMS fields to be in line with nested URL changes. From: Andrew Short
* [rev:88499] Refactored ModelAsController to only grab the first page of a request, then pass control on to it. From: Andrew Short
* [rev:88491] #3279: Updated the link inserter to insert a shortcode rather than a plain HTML link. From: Andrew Short
* [rev:88489] Updated the SiteTree link and section code to derive data from the current page, rather than relying on its own cache.
* [rev:88488] Added Hierachy->getAncestors() to return all the parent objects of the class in a DataObjectSet. From: Andrew Short
* [rev:88487] Update ContentController to manually set the current Director page in handleRequest().
* [rev:88482] Refactored TreeDropdownField to generate and manage the tree using Hierachy's ParentID data, rather than relying on the client. From: Andrew Short
* [rev:88480] Added ErrorPage::response_for() to get a response for a HTTP error code and request.
* [rev:88479] Added ModelAsController::controller_for() to link a SiteTree object to its controller. From: Andrew Short
* [rev:88478] Added HTTPRequest->isMedia() to check if a request is for a common media type. From: Andrew Short
* [rev:88477] Added Controller->hasActionTemplate() to check if a template exists for a specific action. From: Andrew Short
* [rev:88476] Updated SiteTree linking methods to generate nested URLs.
* [rev:88474] Added template and value methods to database fields.
* [rev:88139] Passing sitetree instance to CMSMain->LangSelector() in order to trigger canTranslate() filtering
* [rev:88125] Added Translatable->getAllowedLocalesForMember()
* [rev:88123] Added Translatable->providePermissions()
* [rev:87777] Added ComponentSet->getComponentInfo() (#4587, thanks rorschach)
* [rev:86506] Database specific version of RANDOM() created
* [rev:86402] Added SearchContext->getFullName() to preserve the original fieldname including the relationship
* [rev:86338] Added TableListField->paginationBaseLink
* [rev:86216] Supporting full parameter signature in Versioned->Versions(), allVersions()
* [rev:86027] Limiting "alc_enc" cookie (remember login token) to httpOnly to reduce risk of information exposure through XSS
* [rev:86026] Added full parameter signature of PHP's set_cookie() to Cookie::set(), including the new $httpOnly flag
* [rev:86021] Avoid information disclosure in Security/lostpassword form by returning the same message regardless wether a matching email address was found in the database.
* [rev:86017] Added Member->FailedLoginCount property to allow Member->registerFailedLogin() to persist across sessions by writing them to the database, and be less vulnerable to brute force attacks. This means failed logins will persist longer than before, but are still reset after a valid login.
* [rev:85823] Allowing Widget->Content() to render with any templates found in ancestry instead of requiring a template for the specific subclass
* [rev:85789] Added handleWidgets() to ContentController to support new Widget_Controller class
* [rev:85736] added tinymce valid element to allow style, ids and classes on any element to allow for styling hooks. Ticket: #4455
* [rev:85731] hide unmoderated page comments from the page comment RSS feed. Ticket #4477
* [rev:85716] Ticket #3910 - MySQL Time Zone support (alternative time zone to that of the website to which the server is set to)
* [rev:85709] added option to truncate (clear) database table before importing a new CSV file with CSVBulkerLoader and ModelAdmin.
* [rev:85700] Ticket #4297 - Use Director::baseFolder instead of relative links in sapphire/core/Image.php
* [rev:85281] Filtering out TestOnly classes in CMSMenu::get_cms_classes()
* [rev:84860] convert SelectionGroup.js from prototype version to jQuery version
* [rev:84816] Updated SSLogErrorEmailFormatter to support NOTICE priority level logging
* [rev:84774] Added SSLog, SSLogEmailWriter and SSLogErrorEmailFormatter for silverstripe message reporting
* [rev:84165] Improved performance of DataObject::hasField()
* [rev:84160] Object::__construct() performance improved slightly.
* [rev:84159] Improved performance of Object::uninherited_static()
* [rev:84158] Improved performance of Object::allMethodNames() and Object::addMethodsFrom()
* [rev:84149] add more assertion in SearchFilterAapplyRelationTest to test more cases for many_many relation.
* [rev:84117] add more assertion in SearchFilterAapplyRelationTest to test more cases for many_many relation.
* [rev:84113] add "InnerJoin" clause for an has_many component's ancestry classes for SearchFilter::applyRelation() so that an searchfliter could filter on that component's ancestry's field. add unit tests for this enhancement and r83500
* [rev:84073] added new permission, SITETREE_REORGANISE
* [rev:83798] #3638: There is no longer any need to have the class name match the PHP filename
* [rev:83789] Added ClassInfo::is_subclass_of() for better performance
* [rev:83674] sitetree filters now show up in a dropdown, and you can add your own by extending CMSSiteTreeFilter
### Other
* [rev:90071] Merge branch 'master' of :sminnee/sapphire From: Sam Minnee
* [rev:89715] (from r82175)
* [rev:89702] Merge branch 'master' of :sminnee/silverstripe-cms From: Sam Minnee
* [rev:89224] slightly later, so FormResponses can be overridden if necessary. (from r85614)
* [rev:89220] ENHANCMENT side reports can now have parameters (from r85329)
* [rev:89207] ENHANCMENT improved reporting around broken links/files (from r88993)
* [rev:89186] #108 - Subsite Virtual Page ordering (from r84848)
* [rev:89178] as they are confusing. (from r88019)
* [rev:89174] #148 - Stable against restructures (from r87251)
* [rev:89157] pointing at. (from r85197)
* [rev:89155] #63 - Stable against restructures (from r84861)
* [rev:88638] Add support for configuring multiple static publisher on a single site (from r70203)
* [rev:88637] Basic authentication now (back) in configurefromenv.php (from r82551)
* [rev:88527] Added readme for github From: Sam Minnee
* [rev:88525] Added readme for GitHub copy of SilverStripe. From: Sam Minnee
* [rev:88474] * Removed ViewableData_ObjectCustomised - now just uses ViewableData_Customised.
* [rev:87896] Transaction test created
* [rev:86684] Merged in Requirements::combine_files() fix from branches/2.3 - r83048
* [rev:86679] Merged in Member::sendInfo() bug fixes from branches/2.3 - r85779
* [rev:86678] Merged in Email template codes change from branches/2.3 - r84594
* [rev:86676] Merged in parent::__construct() additions from branches/2.3 - r83580 and r83587
* [rev:86669] Merged Text::ContextSummary() changes from branches/2.3 - r82035 and r82036
* [rev:86655] Patched to allow id|class|style|title attributes in all elements and allow empty td cells (will pad with non-breaking space) in line with #4332 and 4497 in 2.3.x changes to cms/LeftAndMain.php
* [rev:84981] Ensure that DataObject->ClassName is set on object instantiation
* [rev:84970] Made timing code for test runner more accurate (includes initial db build):
* [rev:84814] ENHANCMENT: get svn merged revision 84806:84808 from branches/iss
* [rev:84163] ENHANCMENT: Low-level performance improvements in database access.

View File

@ -0,0 +1,732 @@
# 2.4.0-beta1 (2010-01-29)
## Changelog
### Overview
* Support for SQLite and PostgreSQL databases (via separate module)
* Partial caching in templates, to allow for faster load times of certain aspects in dynamic pages.
* Upload controls in the CMS no longer require the Adobe Flash plugin, and work again on Mac OSX.
* File and page dropdown selections support inline searching, to make handling larger tree structures easier.
* Fixed password hashing design flaw, which makes SilverStripe databases more portable between different server architectures.
* Improved reporting API to unify the CMS sidebar reports and full-page reports on their own section. Its easier to add custom filters to reports.
* Batch action handling handles larger tree structures, provides better visual feedback, and respects permissions on individual pages.
* Global site configuration is translatable, meaning titles for your website can be in different languages without any switching in your templates.
* Allow selection of themes through the site configuration interface (in addition to changing the theme via configuration code)
* More fine-grained translation permissions: A group can be limited to only edit a certain language in the CMS.
* Added dropdown to choose from existing anchor links when inserting a link from the CMS sidebar.
* Team members can get permissions to see the draft version of a page in preview mode without requiring CMS access.
* Pages of type "Virtual Page" have improved stability in regards to their permission control, translation and publication.
* Improved broken link detection (''talk to Andy for more info'')
* Removed the jsparty/ toplevel folder, and moved all its dependencies into sapphire/thirdparty and cms/thirdparty
* More than 350 bugfix and enhancement commits, and 200 minor changes.
### Features and Enhancements
* [rev:98268] Moved the log-in validation process from individual authenticators into Member->checkPassword() and canLogIn(), to allow more extensibility and control (trunk, 2.4).
* [rev:98219] roll batch permissions in to a generic function (from r97748)
* [rev:98211] batchactions can now implement confirmationDialog() to provide a custom confirmation dialog to the front end.
* [rev:98180] Allow for custom generation of SSReport::ID() for parameterised reports.
* [rev:98179] Removed broken links reports from sidebar (in anticipation of adding them to the main reporting area) (from r95954)
* [rev:98173] Improved look and feel for report filtering
* [rev:98165] Performance improvement to CMS load time with many pages. (from r95490)
* [rev:98159] added canAddTopLevel permission to SiteConfig to determine which users/groups can add pages to the root of the sitetree. (from r87279)
* [rev:98156] audit trails
* [rev:98156] ability to parameterize SSReport's (from r85903)
* [rev:98132] Allow sort descending as well as ascending. (from r96054)
* [rev:98110] Allow user theme selection through SiteConfig, falling back to SSViewer::set_theme() as a default if there are none selected
* [rev:98104] Improved TableListField header styling. (from r96028)
* [rev:98102] Add a function to give link to Live site (from r95948)
* [rev:98091] ManifestBuilder::get_manifest_info() now uses ManifestBuilder::get_themes() instead of doing it's own retrieval of available themes
* [rev:98080] Removed dev/reset, instead encouraging the use of dev/tests/startsession for tests.
* [rev:98080] Let people use dev/tests/startsession without a fixture, instead calling requireDefaultRecords
* [rev:98041] added support for MySQL data type SET used in MultiEnum FEATURE: added datetime helper functions
* [rev:98025] add 'view site tree as' functionality.
* [rev:97896] 2.4 tickets (#4670) new permission code to view draft w/o CMS access
* [rev:97895] 2.4 tickets (#4670), new permission code to view draft stage w/o CMS access
* [rev:97819] Allow ungrouped retrieval of Permission::get_codes() through new $grouped switch
* [rev:97793] removed the situation, when the user is left with empty search box and empty dropdown.
* [rev:97792] use Validator::get_javascript_validator_handler() to check if the handler is turned on before doing either js or php validation
* [rev:97765] Select the uploaded image after uploading by default. #4962
* [rev:97745] adapt the page dropdown based off the allowedChildren values
* [rev:97606] Added hover states to "Available widgets" boxes in the CMS for usability
* [rev:97602] Added visual elements to aid in the usability of the WidgetAreaEditor
* [rev:97601] CMS Editor Upload panel now loads the root files directly and allows the user to upload to the root assets dir
* [rev:97597] Changed menu title from "Site Content" to "Pages" to be consistent with other menu labels
* [rev:97597] Changed tree root node in CMS to get title from SiteConfig rather than defaulting to "Site Content"
* [rev:97597] Changed tree panel headline in CMS from "Site Content and Structure" to "Page Tree" to stay consistent with new CMS menu title
* [rev:97583] Don't set up the test db if database tests aren't being run. From: Sam Minnee
* [rev:97530] Adjusted "Available Widgets" column to be narrower than "Widgets currently used", allowing more space for configuring widgets
* [rev:97478] Member->requireDefaultRecords() no longer creates a default administrator based on $_REQUEST data. Moved functionality into Installer->install()
* [rev:97436] Updated Member->getMemberFormFields() to use scaffolding and to be in line with Member->getCMSFields(). From: Andrew Short (from r97401)
* [rev:97391] Add partial caching support to SSViewer.
* [rev:97390] Add aggregate calculation to DataObject, allowing (cached) calculation of Max, Min, Count, Avg, etc
* [rev:97389] Add cache factory that provides nice API over top of Zend_Cache
* [rev:97370] Allowing translation of SiteConfig (including toplevel permission groups)
* [rev:97207] Added ContentController->ContentLocale() to allow XHTML/HTML specific lang= attribute settings in custom template code (see #4858). Removed `<meta http-equiv="Content-Language"...>` tag in SiteTree->MetaTags().
* [rev:97207] Updated blackcandy theme to use new $ContentLocale attribute to set the locale of the current page (in Page.ss)
* [rev:97192] Added RestfulService::set_default_proxy() and RestfulService->setProxy() (#4637, thanks hamish)
* [rev:97031] upgrading the search functionality of the TreeDropdownTree with pluggable search function
* [rev:97028] include menu title in default search. PATCH via lubzee #4508
* [rev:97024] added Session::clearAll() functionality. ENHANCEMENT: Added Unit Tests covering Session API. MINOR: Tided up formatting in session class and included doc comments for API level documentation
* [rev:97018] Use tidied HTML in DataDifferencer
* [rev:97017] Try to tidy HTML using external libraries if available
* [rev:97011] Added TabIndex to FormActions. Ticket: #4905. PATCH: via keeny
* [rev:96821] Added applicable pages checks to delete from live, delete from draft, and publish (from r94775)
* [rev:96820] Added 'greyed out' status of batch action checkboxes while applicable pages are being loaded via ajax. (from r94774)
* [rev:96819] Update the checkboxes available to batch-actions to show only the applicable pages for that particular action.
* [rev:96800] Let LeftAndMain subclass canView() methods optionally redirect. (from r90018)
* [rev:96793] Renamed Author column to User in the page version history to better reflect that they might not have been authors, and just iniators of workflow actions. (from r89015)
* [rev:96792] Added new onRenameLinkAsset() handler to static publishing for better link rewriting. (from r89014)
* [rev:96778] Files and images section warns if you are deleting a file that is linked to
* [rev:96752] Recognise HTTP_X_FORWARDED_HOST header and use that in place of HTTP_HOST (from r93148)
* [rev:96668] Change to TreeDropdownField, giving it filtering behaviour as described in ticket http://open.silverstripe.org/ticket/3007 . Its disabled by default for legacy compatibility, but enabled for HtmlEditorField so that link editor is filterable for local links, via an extra boolean parameter on TreeDowndownField.
* [rev:96440] Add onLoad callback handler CMSLoadFunctions
* [rev:96049] Added Date::Rfc3339() for returning an RFC 3339 valid date format (from r96010)
* [rev:95418] added delete all link to page comments. Patch via #4427. Thanks walec51
* [rev:95194] added translatable support to mathspamprotection. PATCH via noini (#4755)
* [rev:94887] added several tests for PermissionCheckboxSetField, PermissionRole and Group
* [rev:94515] Improved layout of altercation message when called via CLI. Patch via simon_w #4373
* [rev:94423] Allow passing in an Exception object to SS_Log::log() in addition to an array describing the error context (line number, file, trace etc)
* [rev:94381] Added FunctionalTest::findAttribute() as a helper for getting an attribute from a SimpleXMLElement object by it's name
* [rev:94297] Added DataObjectSet::emptyItems() to remove all the items from the set - this is useful for when you are augmenting CMS and front end fields via updateCMSFields() and updateFrontEndFields() on a DataObjectDecorator
* [rev:94063] Added MultipleOf and Modulus methods to ViewableData - useful for templating work
* [rev:94062] Loading of tinymce_ssbuttons plugin via relative paths in HtmlEditorConfig rather than using the plugin name as a path spec (see r94060)
* [rev:94060] Added support for loading external plugins (with relative paths) in HtmlEditorConfig. This means relative paths can be separate from the plugin name, and fixes a bug where paths containing dashes were ignored by TinyMCE.init().
* [rev:94060] Changed sapphire/thirdparty/tinymce-advcode to use the original plugin name, and specify its relative path through HtmlEditorConfig instead.
* [rev:93771] Added parameter to DBLocale->Nice()
* [rev:93771] Added DBLocale->getNativeName()
* [rev:92879] Allowing to hide certain permission from showing in SecurityAdmin? through add_hidden_permission() (refactored from r92428) (from r92866)
* [rev:91576] Pluggable password encryption through PasswordEncryptor class (#3665) (merged from r90949)
* [rev:91496] added ability to upload images from site content pane. Merged via r9130, r91347, r91350, r91480
### API Changes
* [rev:98373] HTTP::setGetVar() always returns absolute URLs. Use Director::makeRelative() to make them relative again.
* [rev:98373] HTTP::setGetVar() combines any GET parameters in PHP array notation (e.g. "foo[bar]=val") instead of replacing the whole array
* [rev:98224] Refactor Versioned so a single state is kept for stage, archived date, or any module specific reading modes (from r98161)
* [rev:98215] Introduced new API for SS_Report
* [rev:98191] Added SideReportWrapper to help you tailor report columns for the side reports.
* [rev:98191] Allow use of 'casting' option on side report columns.
* [rev:98191] Make 'title' optional on side report columns. (from r96272)
* [rev:98176] Removed SideReport class, use SSReport as the base-class for them instead.
* [rev:98176] Use SSReport::register(SideReport) to explicitly register reports on the LHS of the content view.
* [rev:98175] Added explicit registration of reports with SSReport::register() (from r95857)
* [rev:98159] Security::permissionFailure(); will no longer tell the client side JS to show the login box if the user is already logged in
* [rev:98101] Allow passing of an explicit map of dropdown items to a TreeDropdownField.
* [rev:98096] Refactored test for whether a SQLQuery can be sorted by a particular column into SQLQuery::canSortBy($fieldName) (from r95850)
* [rev:98056] Decimal now allows setting a default value properly
* [rev:97996] rename the class "Cache" to "SS_Cache" (ref ticket: #4997)
* [rev:97827] Added cancelSchemaUpdate() and doesSchemaNeedUpdating() to the Database class
* [rev:97819] Removed $blankItemText parameter from Permission::get_codes()
* [rev:97818] Removed Member::init_db_fields(), its no longer needed due to the Member.PasswordEncyrption property changing from an ENUM to Varchar.
* [rev:97797] Fixed i18n _t() calls without namespaces in template includes: They now default to setting the include filename as namespace, rather than the including template (#4915, #3400 - thanks Henk_Poley, jwalsoe, walec51)
* [rev:97731] Determine default BASE_PATH/BASE_URL from the __FILE__ content, so that the script that initiated the Sapphire process doesn't matter. This means that index.php doesn't need to manipulate those variables.
* [rev:97582] #4929: Add $class argument to DataObjectDecorator::extraStatics()
* [rev:97489] removed SWFUpload. Refactored Content Editors uploader to use standard uploader.
* [rev:97478] Security::setDefaultAdmin() no longer writes credentials to any Member database records (created through Security::findAnAdministrator(). This prevents outdated credentials when setDefaultAdmin() code changes after creating the database record (see #4271)
* [rev:97478] Security::findAnAdministrator() no longer sets 'Email' and 'Password' properties on newly created members. Removed the $username and $password argments from the method.
* [rev:97475] Moved GSTNumberField from sapphire/forms to new 'formfields_nz' module
* [rev:97474] Moved BankAccountField from sapphire/forms to new 'formfields_nz' module
* [rev:97270] Unique_identifier now accepted as the login requirement, allowing alternatives to 'Email'
* [rev:97207] Deprecated ContentController->LangAttributes(). Use ContentLocale() instead and write attribute names suitable to XHTML/HTML templates directly in the template.
* [rev:96988] #3600 Inconsistency in File::getURL() which returns an absolute URL, when it should be relative - please use getAbsoluteURL() instead for old behaviour
* [rev:96988] #3600 Image no longer has an explicit getURL() method, instead it inherits getURL() from File which returns a relative URL
* [rev:96824] Added capability for batch actions to indicate failure through red checkboxes (from r94868)
* [rev:96823] Added canView() to CMSBatchAction so that you could hide certain batch actions from some users. (from r94846)
* [rev:96821] Added applicablePagesHelper to CMSBatchAction to ease the process of creating new applicable page methods.
* [rev:96819] Allow for an applicablePages($idArray) method to be defined on a CMSBatchAction class. (from r94761)
* [rev:96810] Added FilesystemPublisher::getExistingStaticCacheFiles(), to help build caching logic methods. (from r91354)
* [rev:96809] Added numChildrenMethod argument to LeftAndMain::getSiteTreeFor()
* [rev:96756] Added canDeleteFromLive permission to SiteTree, separate from canPublish (from r93315)
* [rev:96751] Define VirtualPage::isPublishable() so that people know not to even request publication if it's not allowed. (from r93098)
* [rev:96749] Added DataObjectDecorator::cacheKeyComponent() to ensure that the cached behind DataObject::get_one() is appropriately specific (from r93095)
* [rev:96739] Added Hierarchy::numHistoricalChildren() and Versioned::get_including_deleted_query()
* [rev:96739] Added numChildrenMethod arg to getChildrenAsUL, markPartialTree, markChildren, markingFinished
* [rev:96734] Don't generate TestOnly DataObjects in the database immediately; instead let test developers specify them in SapphireTest::$extraDataObjects.
* [rev:96734] Added SapphireTest::resetDBSchema() (from r90054)
* [rev:96727] Renamed SapphireTest::set_up_once/tear_down_once to setUpOnce/tearDownOnce, and made them instance methods.
* [rev:96727] Added SapphireTest::$illegalExtensions and SapphireTest::$requiredExtensions for making tests depending on particular extension sets (from r89958)
* [rev:96725] Moved popupdatetimefields to pop up below the text field instead of next to the icon. (from r89914)
* [rev:94430] Group::addByGroupName() now creates the group if one does not already exist (from r83010)
* [rev:94178] Renamed ViewableData->SecurityID() to getSecurityID() in order to get its value loading through Form->loadDataFrom()
* [rev:94062] Changed cms/javascript/tinymce_ssbuttons plugin name to "ssbuttons" (see r94060)
* [rev:94062] Changed cms/javascript/tinymce_ssmacron plugin name to "ssmacron" (see r94060)
* [rev:93785] removed Director::Link(). Use Controller::join_links() instead
* [rev:93693] removed deprecated RestrictedText fields
* [rev:93687] removed deprecated LeftAndMain::add_menu_item. Use CMSMenu::add_menu_item()
* [rev:93685] removed deprecated extend calls (r93632). API CHANGE: removed fieldExists(). Use hasField() (r93633). API CHANGE removed listOfFields() (r93647). API CHANGE: removed Tag() and URL() from Image. Use getTag() and getURL(). BUGFIX: updated Image.php to use getTag() (r93639, r93646). API CHANGE: removed val(). Use XML_val() (r93650). API CHANGE: removed $add_action. Use singlar_name or lang tables (r93658). API CHANGE: removed ConfirmedFormAction (r93674). API CHANGE: removed ajax_render on CTF (r93679).
* [rev:93660] Removed ComponentSet::removeByFilter() since it's not flexible enough and fixed calls to this from HtmlEditorField::saveInto() to use custom code instead
* [rev:93640] Removed deprecated static function ContentNegotiator::disable() - it's disabled by default
* [rev:92878] Refactored hiding of Permissions added in r92428. Added PermissionCheckboxSetField?->setHiddenPermissions() (from r92865)
* [rev:92428] add the ability to remove some permissions specified by their code in the rendered field html of PermissionChecksetBoxField and full-covered unit tests of this ability.
* [rev:91612] Replaced BasicAuth::enable() with BasicAuth::protect_entire_site()
* [rev:91612] BasicAuth::requireLogin() no longer has an option to automatically log you in. You can call logIn() on the object returned, instead. (from r91603)
* [rev:91576] Deprecated Security::encrypt_passwords() (merged from r90949)
* [rev:91576] Deprecated Security::$useSalt, use custom PasswordEncryptor implementation (merged from r90949)
* [rev:91576] Removed Security::get_encryption_algorithms() (merged from r90949)
* [rev:91576] MySQL-specific encyrption types 'password' and 'old_password' are no longer included by default. Use PasswordEncryptor_MySQLPassword and PasswordEncryptor_MySQLOldPassword
* [rev:91576] Built-in number of hashing algorithms has been reduced to 'none', 'md5', 'sha1'. Use PasswordEncryptor::register() and PasswordEncryptor_PHPHash to re-add others. (merged from r90949)
### Bugfixes
* [rev:98403] Fixed Hierarchy->loadDescendantIdList() to call setOwner() on the extension instance. This was necessary due to underlying Object/Extension changes in 2.4.
* [rev:98382] #5044 Hierarchy::loadDescendantIDListInto() now uses Object::getExtensionInstance('Hierarchy') instead of going through __call(), as PHP 5.3 has issues converting references to values
* [rev:98373] HTTP::setGetVar() uses parse_url() and http_build_query() to add query parameters to an existing URL, instead of doing its own regex-based parsing. This means existing GET parameters are correctly url encoded.
* [rev:98324] Fixed ContentController->deleteinstallfiles (added to $allowed_actions, see #5040)
* [rev:98272] Don't force SSL when running from CLI
* [rev:98265] Don't register member IDs that don't exist in the DB as being logged in.
* [rev:98263] Updated SiteConfig-based theme selection to remove inappropriate coupling from SSViewer
* [rev:98257] Check for SubsiteReportWrapper class, not Subsite, so the CMS still works with older versions of Subsites
* [rev:98252] allow all characters in the anchor's name attributes
* [rev:98226] Fixed side report seelctor
* [rev:98221] Let ModelAsController::init() extensions trigger redirections. (from r97767)
* [rev:98218] More fixes renaming SSReport to SS_Report
* [rev:98217] Don't allow translations of VirtualPage (until we can reliably copy data between locales) (see #5000)
* [rev:98205] Better broken reason sorting (from r96989)
* [rev:98204] Allow changing direction in broken link type (from r96987)
* [rev:98203] Fix broken reasons sorting (from r96985)
* [rev:98202] Improvements to sorting of columns on broken links report (from r96979)
* [rev:98185] Add horizontal scrolling to reports when necessary. (from r96086)
* [rev:98184] Add horizontal scrolling to reports when necessary. (from r96085)
* [rev:98183] Add horizontal scrolling to reports when necessary. (from r96075)
* [rev:98182] Removed unnecessary '?' from report URLs when there are no search criteria (from r96052)
* [rev:98180] Don't throw an error if there are no report filters.
* [rev:98180] Don't randomise the order of reports with the same priority. (from r95955)
* [rev:98177] Only list reports in admin/reports that you can actually view (from r95885)
* [rev:98176] Updated all cms side reports to use SSReport as the base class. (from r95884)
* [rev:98170] Fixed bug with report search fields not showing the value that you just searched for. (from r95567)
* [rev:98168] Fixed report pagination, with or without search params (from r95555)
* [rev:98152] pagination was being applied (with a limit of NULL) to print and export actions. This was due to $_REQUEST['methodname'] not existing. (from r97114)
* [rev:98150] TreeMultiselectField_Readonly now posts the correct value to the server (from r97100)
* [rev:98136] still use the correct methods to get a value, even if we're generating a CSV ($xmlSafe = false) (from r96212)
* [rev:98134] Don't default to sorted descending if you already have a different column sorted ascending. (from r96061)
* [rev:98133] Don't make ManifestBuilder choke on empty files. (from r96058)
* [rev:98132] Make TableListField sort checking use SQLQuery::canSortBy() to let SSReprot_FakeQuery work.
* [rev:98131] Correct direction of sort arrows in TableListField (from r96051)
* [rev:98114] fixed test that was trying to do a assertContains between a DataObjectSet and a Member object. Changed it to an assertEquals between Member and the First item in the Set. Also added an inverse test to check that Set doesn't contain the wrong Member.
* [rev:98111] removing search&replace victim, using unpopulated cache. Reverted to AllChildren, which calls the cache itself.
* [rev:98103] Fixed readonly transformation of TreeMultiselectField in cases where $this->value is explicitly set. (from r95962)
* [rev:98101] Allow creation of TreeDropdownFields on forms with querystring URLs.
* [rev:98101] Make use of the $this->value setting of TreeMultiselectFields. (from r95910)
* [rev:98095] Let FieldMap access non-data fields too (from r95825)
* [rev:98094] Make TableListField rely on SQLQuery for its count-generation.
* [rev:98094] Make SQLQuery return an appropriate count if a HAVING clause is used. (from r95814)
* [rev:98083] reintroducing the forceValue url param, so the TreeDropdownField value can be set via JS (previously if the item was deep within the tree structure it would not be selected)
* [rev:98030] fixed member labels not appearing in cms popup. #5025
* [rev:98018] Fixed incorrect logic in CMSMain::generateTreeStylingJS() stopping different tree icons from working
* [rev:98001] Ticket #4805
* [rev:97984] FileIFrameField throws sub-URLs error when changing cms to a non default language (#4767)
* [rev:97980] #5009: Removed inappropriate field-detection change on multienums with no default
* [rev:97937] missing comma
* [rev:97935] can't upload swf file in admin/assets (open ticket #4999)
* [rev:97926] remove the possibility that Director::isDev() could be recursively called when putting isDev=1 in $_GET, addressed in ticket #4978 (http://open.silverstripe.org/ticket/4978)
* [rev:97912] Allowing translations of VirtualPage by not copying over original Locale property (see #5000)
* [rev:97911] If a Group doesn't have any specific TRANSLATE_`<locale>` edit rights, but has general CMS access (CMS_ACCESS_CMSMain, CMS_ACCESS_LeftAndMain, ADMIN), then assign TRANSLATE_ALL permissions as a default. Necessary to avoid locking out CMS editors from their default language (see #4940 and 4941)
* [rev:97909] Don't let a user's theme break the CMS.
* [rev:97881] Checking that URL controller in HTTPRequest->match() is a subclass of Controller, not RequestHandler (which would include nested controllers like Form or FormField subclasses that shouldn't be accessible on their own toplevel URL namespace)
* [rev:97878] Folder::findOrMake() will call mkdir if needed, even if object already exists in database.
* [rev:97833] remove serverside Validator::get_javascript_validator_handler() checking when trying to valid the field in serverside.
* [rev:97783] File don't have method URL(), instead, we use $image->URL, which will call $image->getURL()
* [rev:97775] removed unneccessary comma (it breaks the IE)
* [rev:97764] changed the stylesheet path to proper one - #4968
* [rev:97755] add custom search function, so the search catches also the Titles (search uses DataObject::get, which bypasses the getMenuTitle function)
* [rev:97746] allow only 2 and 4 digit years.
* [rev:97731] Use BASE_PATH and BASE_URL instead of data from $_SERVER.
* [rev:97730] fix front-end validation for DYMCalendarDateField, addressed in open ticket #4967(http://open.silverstripe.org/ticket/4967).
* [rev:97728] Don't rely on the current working directory for any file access; use BASE_PATH.
* [rev:97727] Don't rely on the current directory for any logic.
* [rev:97673] the anchor dropdown now works in IE. Also fixes other anchor-related problems as described in ticket #4961
* [rev:97653] Fixed Permission::get_members_by_permission() for DB abstractions
* [rev:97638] Fixed CMS Editor loading in AssetAdmin
* [rev:97603] Fixed bug when user selects no folder and uses the search box it incorrectly doesnt append the where statements
* [rev:97599] Use correct paths for requirements
* [rev:97594] Fixed potential data corruption issue when you are changing the class of a SiteTree subclass between two subclasses that share a fieldname.
* [rev:97593] Another bugfix for r97583
* [rev:97589] Fixed bug that was caused by r97583
* [rev:97586] #4929: Fixed Object::add_static_vars() for uninherited static.s
* [rev:97581] #4471: Fixed link insertion in Safari.
* [rev:97545] Fixed widgets not being clickable to use them in IE
* [rev:97541] Clicking available widgets now applies only to h3 elements
* [rev:97541] Widgets are now prepended to the available widget stack by use of Insertion.Top
* [rev:97522] When adding a new widget by clicking one of the available widgets, add it to the top of the currently used widgets instead of the bottom
* [rev:97507] Fixed incorrect lables "TOADD" etc in WidgetAreaEditor
* [rev:97482] Fixed NumericField->jsValidation(), now accepts negative numbers, making it more like the equivalent phpValidation(), which is using is_numeric() (see #4874, thanks Allisone)
* [rev:97480] Checking for presence of all columns in Security::database_is_ready(). This was necessitated by an earlier change to the sapphire ORM which now selects all columns explicitly in a SQL query (instead of SELECT *) (see #4027)
* [rev:97472] Setting 'Locale' as HiddenField in CMSMain->getEditForm() to support translatable SiteConfig records (see r97370, #4770)
* [rev:97437] Properly closed a tag in AssetTableField that was hiding content after the back link tracking tab. From: Andrew Short (from r95036)
* [rev:97433] Fixed nested URLs operation for pages more than 4 levels deep. From: Andrew Short (from r95902)
* [rev:97414] Was using custom_database_fields in Aggregate, not database_fields, and so aggregates for the common fields (LastEdited, Created, ClassName) would fail
* [rev:97370] Fixed SiteConfig->canView()/canEdit() to respect empty CanViewType/CanEditType assignments.
* [rev:97357] old 2.3 passwords now handled correctly and migrated accordingly
* [rev:97307] getByKey replaced with objectForKey
* [rev:97300] The 5.1 replacement array_fill_keys function now made available to the cron jobs
* [rev:97267] Let users without a specific TRANSLATE_ permission edit the default locale, so that things don't break when you install the Translatabe module.
* [rev:97260] Move TreeDropdownField requirements to Field() so requirements are loaded properly in popups
* [rev:97231] removing hardcoded reference to ModelAdmin_RecordController, also added getters for model controllers.
* [rev:97211] Fixed URLSegment access for translated homepages in SiteTree->RelativeLink (#4781, thanks martijn)
* [rev:97210] Language switcher dropdown javascript uses baseHref() to avoid invalid relative links in IE8 (#4891)
* [rev:97179] Fixed redirection destionation of the modeladmin delete button on the detail form.
* [rev:97168] now hiding the permissions via SecurityAdmin::add_hidden_permission works also for PermissionRoleAdmin
* [rev:97073] Attribute escaping in PageCommentInterface?_singlecomment.ss (merged from r97071)
* [rev:97051] Fixed bug in r97036
* [rev:97038] Fix display of exception backtrace in CLI view.
* [rev:97036] Use locally included Zend framework components in favour of those installed with PEAR
* [rev:97031] the search was only operating on the part of the tree (as returned by markPartialTree), now it searches globally
* [rev:97023] HTTPResponse has been replaced with SS_HTTPResponse
* [rev:97016] Comment URL field check is now case insenstive. Included tests for various protocols. PATCH via simon_w. Ticket #4776
* [rev:97013] removed name attribute from label fields since this is invalid html. Ticket: #4887. PATCH via tobych
* [rev:96997] Check for an empty list of keys before attempting to create an array with them
* [rev:96993] #4857 Fixed potential bug where a file would just be uploaded to a random folder, also files can now be uploaded to the assets root properly
* [rev:96977] reintroduced 96961, build failed for other reason.
* [rev:96961] loading a subtree was failing - couldn't call getSiteTreeFor reliably on LeftAndMain which is abstract class in its nature. Now using valid subclass instead.
* [rev:96941] Fixed bug in VirtualPage::isPublishable() when CopyContentFromID not set
* [rev:96884] Fixed add button overlapping image/flash popups in modeladmin. #4906
* [rev:96879] fixed onBeforeDuplicate calling before page existed
* [rev:96868] Fixed a PHP segfault bug with the WidgetAreaEditor
* [rev:96828] Adjust EncryptAllPasswordsTask test to match API for BuildTask
* [rev:96822] Removed XSS holes (from r94822)
* [rev:96818] Don't show obsolete page if you refresh the CMS after deleting a page (from r94242)
* [rev:96817] Use canDeleteFromLive instead of canPublish for checking delete from live action (from r93316)
* [rev:96812] Correct labels for "delete from draft" batch actions (from r91838)
* [rev:96811] Use doDeleteFromLive when deleting pages from live, so that onBeforeUnpublish and onAfterUnpublish are called. (from r91381)
* [rev:96809] Use the correct numChildrenMethod when showing the 'all children, including deleted' tree (from r91166)
* [rev:96806] Preserve selection of LHS multiselect tree when switching between filters. (from r90290)
* [rev:96805] Correct confirmation alert message when rolling back to a specific version. (from r90261)
* [rev:96799] Updated onAfterUnpublish to republish page from static cache as well as unpublish them. (from r90002)
* [rev:96798] Removed destroy() calls from static cache builder; with the garbage collection improvements it shouldn't be necessary. (from r89983)
* [rev:96797] Fixed width of time dropdown fields in the LHS CMS (from r89913)
* [rev:96796] Don't set the Owner by default on new records. (from r89910)
* [rev:96795] Fixed viewing of deleted pages. (from r89833)
* [rev:96790] Don't cut off document.body overflow in CTF popups in the admin, when on test mode. (from r88958)
* [rev:96785] Ignore elements without a name in change detection.
* [rev:96782] Fix image tracking not working cross subsite (from r88008)
* [rev:96781] Fix changing the URLSegment on a page making the Draft Site link
* [rev:96780] Fix deleting folders in Internet Explorer (from r87390)
* [rev:96779] Fix highlighting of incorrect page when loading a page in the
* [rev:96775] Use Controller::join_links() for all TableListField and ComplexTableField link building, to support form URLs with querystrings.
* [rev:96775] If ComplexTableField::getParentRecord() can't find a record, just return null rather than erroring. (from r96555) (from r96649)
* [rev:96774] Don't let Versioned archive tables clutter the global state when testing.
* [rev:96774] Don't let mocked datetimes clutter the global state when testing. (from r96640) (from r96648)
* [rev:96773] Removed XSS holes (from r94823)
* [rev:96770] Don't set the nodelete class on the CMS tree on load, since this is now handled by the batch-action system with an Ajax call. (from r94762)
* [rev:96767] Don't let users edit the location in the Behaviour tab if they don't have sitetree reorganise permission (from r94609)
* [rev:96765] Fixed readonly form of TreeDropdownField when field is made readonly before value is set (from r94608)
* [rev:96762] Allow opening of the detail pop-ups of a record on a ComplexTableField attached to a deleted page. (from r94593)
* [rev:96761] Apply file extension restrictions to extensions properly. (from r93531)
* [rev:96760] Don't publish virtual pages on regular page publish unless the page has already been published. (from r93529)
* [rev:96759] Changed default config to restrict file-upload types to ADMINs, since it's protecting against security holes. (from r93327)
* [rev:96758] Virtual pages can be deleted from the live site even when the're not publishable. (from r93319)
* [rev:96755] Fixed notice-level errors when checking permissions of pages that don't exist anywhere (from r93166)
* [rev:96754] Resized images which return null or false are now ignored
* [rev:96752] Add a default list of allowed extensions so that the CMS works reasonably out of the box.
* [rev:96752] Allow files that don't have an extension (most notably folders)
* [rev:96752] Ensure that file URL rewriting works if you rename a page twice without publishing.
* [rev:96752] Ensure that the page doesn't go green after URLs are rewritten
* [rev:96750] Fixed bug in r93095 (from r93097)
* [rev:96748] Update virtual pages semantics to grab content from the published version of the source page when you publish the virtual page, and to not allow publication before their source page is published. (from r92209)
* [rev:96746] Amended some references to HTTPResponse, replacing with SS_HTTPResponse
* [rev:96741] Use live permissions if the stage page has been deleted. (from r91761)
* [rev:96740] Make virtual page broken link detection work across subsites. (from r91311)
* [rev:96739] Clear the bypassStaticCache cookie when you return to the live site. (from r91165)
* [rev:96736] Include newly set fields in the differences shown by DataDifferencer (from r90264)
* [rev:96735] Use draft site permissions over published, if available. (from r90220)
* [rev:96733] Change EncryptAllPasswords to BuildTask instead of DailyTask
* [rev:96732] Call onBeforeUnpublish/onAfterUnpublish events in doDeleteFromLive, because they amount to the same thing. (from r90001)
* [rev:96731] Fixed broken link correction when a page is deleted. (from r89989)
* [rev:96729] Added better handling of rendering SiteTree objects, to prevent test errors. (from r89963)
* [rev:96726] Reset the methods applied to classes after adding/removing extensions. (from r89957)
* [rev:96724] Prevented notice-level error when publishing HTMLText fiels on tables other than SiteTree. (from r89908)
* [rev:96722] Update file link tracking as part of Filesystem::sync() (from r89907)
* [rev:96721] Fixed image link rewriting in virtual pages. (from r89904)
* [rev:96720] Fixed onchange handler for DropdownTimeField (from r89903)
* [rev:96719] Fixed layout glitch in TreeDropdownField in Firefox (from r89842)
* [rev:96718] Don't let non ADMINs with permission-editing rights assign themselves ADMIN permissions. (from r89805)
* [rev:96717] Fixed SiteTree::rewriteFileURL() (from r89804)
* [rev:96715] Version field weird'ed up rollback functionality (from r89464)
* [rev:96705] Make sure Linkto Dropdown works right with filter()
* [rev:96681] alternative function for versions of PHP prior to version 5.2
* [rev:96680] array_fill_keys function created for version prior to PHP 5.2
* [rev:96679] Ensure .js variable defined with var keyword
* [rev:96678] Ensure .js variable defined with var keyword
* [rev:96663] Allow set objects as properties if the property is not a database field
* [rev:96623] anchor, target, and title are not set on a link that's inserted without selection. Also when using createElement in that way firefox encodes the spaces within href parameter breaking the shortcodes. Switched to using the 'mctmp' placeholder now.
* [rev:96566] Fix IE bug with Files&Images (#4912)
* [rev:96551] getting rid of problem with disappearing buttons on the initial page load (not ajax). The initialization was called twice on the CMSForm, and on the second call the ajaxActionsAtTop was removing the buttons - now the buttons are removed only when there is something to be added.
* [rev:96443] Check for functions existence
* [rev:96441] Check for empty
* [rev:96427] Fixed reloading of TableFields after ajax save. (http://mingle.silverstripe.com/projects/air_nz_cms_enhancements/cards/154) (from r88921)
* [rev:96363] Fix multiselect tree selection, since changes in r91342
* [rev:96362] Readonly TreeMultiSelectField has form linked properly
* [rev:95973] #4140 When clicking a tree node that was just dragged, "Stack overflow" error would be given in IE. Firebug would report "Too much recursion"
* [rev:95972] when the JS files are combined, swfupload.js gets included in pages where there are no placeholder elements available, failing with exception and killing the javascript for the page. Now the exception is intercepted and ignored.
* [rev:95968] Fallback for arrays which do not contain 'alreadyLoggedIn' values
* [rev:95788] fixing CMS_ACCESS_LeftAndMain permission (=access all cms sections). Also added the test.
* [rev:95558] Show selected row in autocomplete dropdown
* [rev:95511] Prevent text-selection during drag operation, Firefox-specific
* [rev:95422] Fixed undefined $this->Parent in SiteTree::getCMSFields()
* [rev:95388] LessThanFilter uses SearchFilter::getDbFormattedValue, just like GreaterThanFilter
* [rev:95339] pass $allowHTML through to the parent class
* [rev:95169] If running a BuildTask via AJAX, e.g. Filesystem::sync() is run from AssetAdmin, don't show the message "Running [task] ..."
* [rev:95108] Fix fatal error when exporting a csv from a tablefield with a custom query
* [rev:95093] ComplexTableField - fixed sprintf() not enough arguments when the referrer has a % character in it, the referrer is now an argument instead of being hardcoded in the string
* [rev:95091] #4847 Fixed ComplexTableField undefined in IE8 when opening a CTF popup in the Security section of the CMS
* [rev:95088] #4848 Fixed ComplexTableField undefined error in IE8 when it is not available
* [rev:95084] #4848 FileIFrameField visual problem where the preview image is hidden if the TreeDropdownField gets too long for selecting a file
* [rev:94885] Fixed ModelAsController::findOldPage() failing on MSSQLDatabase using "sqlsrv" driver
* [rev:94859] adding onAfterDelete hooks to remove the no longer necessary permissions
* [rev:94835] orphaned permissions and subsite administrator groups were causing trouble - now with the JOIN the first global administrator group is picked up when ussing the override login.
* [rev:94810] removing permissions before re-applying them (previously it just removed the components on the relation which resulted in permissions having GroupID set to 0)
* [rev:94721] fixed typing error
* [rev:94571] fixed spam not being turned into ham if spamprotection isnt enabled. PATCH via simon_w #4813
* [rev:94568] check akismet is enabled before saving spam. PATCH via simon_w - #4812
* [rev:94461] Fix fileiframefields dying when an image is attached and a folder is expanded via ajax
* [rev:94443] fixed closing action on profiler popup
* [rev:94437] include customHeadScripts in clear rule.
* [rev:94416] Fixed undefined function error ip2country() in Geoip::ipcountry_check()
* [rev:94378] match returns null on not-found, querying raw.length resulted in an error. Now it's possible to add links to the page again.
* [rev:94369] Make sure findAnAdministrator gets a global administrator when subsites is installed.
* [rev:94358] #4686 Fixed $member non-object error, and decorated checks from not working in Member::canView(), Member::canEdit() and Member::canDelete()
* [rev:94353] #4566 Time::Nice() and Time::Nice24() return bad results if there is no value
* [rev:94350] Fix default inclusion of (theme|project)/css/editor.css into the WYSWIWYG editor.
* [rev:94349] Don't throw a notice-level error if you access a setting that hasn't been set yet.
* [rev:94332] convert ImageFormAction form prototype syntax to jQuery syntax, merged from r94304
* [rev:94319] Cleanup after aborted drag operation in Assets (#4735) (from r93071)
* [rev:94301] Fixed undefined calls to URL() in SimpleImageField, replacing them with getURL() instead
* [rev:94238] is tinyMCE is not loaded, we cannot call its function. This is specially important in a pop-up of ComplexTableField
* [rev:94170] Fixed IE bug in ReportAdmin_left.js
* [rev:94134] #4661 Fix SS temporary directory bug with Windows environments - the directory would always be "silverstripe-cache" instead of a namespaced one so that multiple SS sites don't conflict with eachother
* [rev:94100] if SecurityAdmin::add_hidden_permission() is called more than once, the later one is never added due two array operator "+"
* [rev:94073] Fixed inconsistent default to ViewableData::Modulus() - should be 0 as per ViewableData::MultipleOf()
* [rev:94071] Modulus and MultipleOf should start at index 0 to match the iterator position, by default
* [rev:94061] fixed reference to incorrect class
* [rev:94002] fix some missing langs/en.js loading.
* [rev:93984] add proper language link broken
* [rev:93965] Changed paths according to moved thirdparty dependencies. This bit change is merged from r92613.
* [rev:93955] fix bug that can't find tinymce_ssbuttons under sapphire/thirdpaty. this is a change merged from r92853 http://open.silverstripe.org/changeset/92853#file3
* [rev:93950] fix bug that can't find tinymce_ssbuttons under sapphire/thirdpaty. this is a change merged from r92853 http://open.silverstripe.org/changeset/92853#file3
* [rev:93935] merge r92502 from trunk for HtmlEditorConfig.php, merge r93934 from trunk for HtmlEditorField.js, merge r92500 from trunk for sapphire/thirdpart/tinymce-advcode/editor_plugin_src.js, aiming to solve the conflict of folder name tinymce-advcode.
* [rev:93860] Fixed incorrect hasDatabaseField() in SearchFilter::getDbName() - use hasOwnTableDatabaseField() instead
* [rev:93777] Fixed SearchContextTest failure
* [rev:93754] Fixed drag link event handling on ComplexTableField.js (#4737)
* [rev:93707] Removed code that relied on deprecated functions in MemberTableField
* [rev:93677] Removed calls to Translatable::is_enabled() since it's deprecated, replaced with Object::has_extension('SiteTree', 'Translatable') instead
* [rev:93676] Removed calls to Translatable::is_enabled() since it's deprecated, replaced with Object::has_extension('SiteTree', 'Translatable') instead
* [rev:93673] #4762 Replace Debug::log_errors_to() in ConfigureFromEnv to use SS_Log instead. Thanks simon_w!
* [rev:93620] Fixed reference to tree.css which doesn't exist because of files moving around
* [rev:93579] Adjusted YamlFixture to new Spyc API: loadFile() instead of load() (from r92566)
* [rev:93542] applied patch from #4381. Observable doesnt play nice with jQuery (manual jsparty merge from r90857) (from r92571)
* [rev:93514] Fix javascript error on IE8 by forcing IE7 compat mode.
* [rev:93259] Fixed dev/build not redirecting properly on first install of SS website on IIS
* [rev:93161] Fixed newlines for Windows when logging errors in LogErrorFileFormatter
* [rev:92411] Fix TreeDropdownFields throwing an exception.
* [rev:92220] Fixed newlines working properly across different platforms - Windows, for example, won't work properly with just \n so use PHP_EOL for a cross-platform solution
* [rev:92129] More robust checks on the current member in Member::canEdit() and Member::canDelete() if there is no logged in member
* [rev:92077] Fixed regexp in anchor link rewriting
* [rev:91958] FolderID was not present in post, so file would not be uploaded to the correct place.
* [rev:91775] Fixed Group::collateFamilyIDs() when working with MSSQL
* [rev:91746] Include salt in legacy password encryptor (from r91743)
* [rev:91659] Made use of new BasicAuth::protect_entire_site() consistent. (from r91658)
* [rev:91613] Don't enable site-wide protection by default (from r91609)
* [rev:91576] Fixed password hashing design flaw in Security::encrypt_password(). Removing base_convert() packing with unsafe precision, but retaining backwards compatibilty through pluggable encryptors: PasswordEncryptor_LegacyPHPHash (#3004) (merged from r90949)
* [rev:91572] Legacy password hash migration in MemberAuthenticator::authenticate() which fixes the precision problems mentioned in #3004 when a user logs in (from r90950)
* [rev:91549] changed condition to display uploaded File
* [rev:91542] fixed order inclusion of js
* [rev:91444] Fixed PageComment boolean operators in WHERE SQL clauses that break MSSQL
* [rev:91418] MigrateSiteTreeLinkingTask returns duplicate results from databases like MSSQL - remove any duplicates that may be around
### Minor changes
* [rev:98409] Fixed HTTPTest->testSetGetVar()
* [rev:98407] Fixed HTTPTest->testSetGetVar()
* [rev:98404] Partially reverted r98382 which added unnecessarily defensive checking to Hierarchy->allChildren()
* [rev:98403] Fixed HierarchyTest assertions around including grand children counts
* [rev:98390] Removed argument to getDescendantIDList() in ThumbnailStripField that doesn't exist on the method
* [rev:98383] Fixed HTTPTest when invoked through dev/tests/all or with GET parameters (see r98373)
* [rev:98376] Testing of grand-children items in HierarchyTest::testLoadDescendantIDListIntoArray() and HierarchyTest::testNumChildren()
* [rev:98372] Documentation
* [rev:98370] Fixed test case name in Hierarchy
* [rev:98369] Added test case for Hierarchy::getDescendantIDList() which also tests Hierarchy::loadDescendantIDListInto()
* [rev:98341] Removed arguments to Hierarchy::getDescendantIDList() calls, as the method does not have any
* [rev:98326] Make pass use a password field, dont require call by reference (merged from r72930)
* [rev:98321] Use 'b' mode for fopen() where possible for better portability
* [rev:98285] Fixed SS_HTTPResponse references in CMSBatchActionHandler
* [rev:98284] Documentation
* [rev:98282] fixed setName()
* [rev:98275] Removed message alteration from ValidationResult->error() to make it more predictable for string matching in unit tests like SecurityTest
* [rev:98274] Fixed unit tests after change Member->checkPassword() to return ValidationResult instead of boolean (see r98268)
* [rev:98268] Use a ValidationResult to log in a member so that custom errors can be generated. From: Andrew Short (from r98267)
* [rev:98264] Only clear theme in CMS if we're not redirecting to the login form (better for testing).
* [rev:98228] Adding SiteConfig as Translatable dependency in SiteTreeTest and TranslatableTest
* [rev:98223] make showing virtual pages tab conditional
* [rev:98223] made virtual page tracking sitetree tablelistfield subsite agnostic (from r98005)
* [rev:98222] removed redundant method call (from r97817)
* [rev:98211] added above confiration to batch setting expiry (from r97215)
* [rev:98210] add pretty warning colors to expiring content warning (from r97151)
* [rev:98208] set Print flag correctly on TLF
* [rev:98208] custom print template for SSReport TLF's that exposes the report title, and filters set (from r97138)
* [rev:98206] fix dropdown labels (from r97063)
* [rev:98201] fixed typos in the comments
* [rev:98200] Change page title heading to "Page name" for consistency in CSV export (from r96925)
* [rev:98199] added quotes
* [rev:98198] Fixed side report tests to suit new report system. (from r96646)
* [rev:98197] using better sorting api (from r96483)
* [rev:98196] fix sorting in this report. (from r96481)
* [rev:98195] make site checking clearer on broken links report (from r96456)
* [rev:98193] typo fixes, adding missing columns (from r96433)
* [rev:98192] remove sort direction when running canSortBy. Also added test coverage for this. (from r96428)
* [rev:98189] improved wording on reports (from r96258)
* [rev:98187] added broken links report (from r96139)
* [rev:98186] Correct sidebar report order. (from r96090)
* [rev:98180] Added SSReport::dataClass() accessor.
* [rev:98178] use DB doubles only in MySQL, fall back to float
* [rev:98174] Added missing template from r95815 (from r95822)
* [rev:98171] Nicer date formatting (from r95761)
* [rev:98164] added locking to static publisher to avoid two queues running at the same time. (from r87792)
* [rev:98163] fixed IE JS errors (from r87420)
* [rev:98162] apply a sitetree filter when changing subsites (from r87369)
* [rev:98160] updated detection for an empty report (from r87362)
* [rev:98158] when you delete a user from a group, they are also removed from any sub groups. (from r87119)
* [rev:98156] applied correct decorators
* [rev:98156] Page.ss now takes advantage of the SiteConfig
* [rev:98156] fixed JS error around concurrent editing
* [rev:98156] ability to disable sorting on tablelistfield
* [rev:98156] added default timezone to static-main.php to avoid PHP warnings
* [rev:98156] only display Roles tab on groups if there are roles in the system
* [rev:98156] publishing activity report
* [rev:98155] better error reporting for broken redirector & virtual pages (from r97185)
* [rev:98154] set Print flag correctly on TLF
* [rev:98154] custom print template for SSReport TLF's that exposes the report title, and filters set (from r97138)
* [rev:98153] Fixed TableListField tests that don't set $_REQUEST['url'] (from r97127)
* [rev:98143] Always position calendars below the entry field - this gives it consistency with PopupDateTimeFields, as well as ensure the popup button isnt hidden. (from r96916)
* [rev:98142] Fixed PermissionTest assertion (from r96642)
* [rev:98141] Fixed TableListField test to suit changed behaviour. (from r96639)
* [rev:98140] if the $fieldname to DOS->sort has a direction in it, split it out, and pass it. (from r96482)
* [rev:98139] redirector link tracking is more intelligent (from r96461)
* [rev:98138] remove sort direction when running canSortBy. Also added test coverage for this. (from r96428)
* [rev:98137] move sort column&direction into their own vars, otherwise, canSortBy(Date DESC) will always return false, since DESC is not part of the column name. (from r96411)
* [rev:98135] fix field escaping in CSV export of TableListField (from r96157)
* [rev:98128] Update en_US with SiteConfig.THEME and SiteConfig.DEFAULTTHEME translatable entities
* [rev:98127] Cleanup test folder after SiteConfigTest::testAvailableThemes() is run
* [rev:98115] added descriptive text to test assert.
* [rev:98110] Unit tests for SSViewer::current_theme() and SiteConfig::getAvailableThemes()
* [rev:98106] Fixed broken tests
* [rev:98098] Removed specific removal of temporary directory in ManifestBuilderTest::testThemeRetrieval() and replaced it with Filesystem::replaceFolder() which does the same thing
* [rev:98097] don't HTML-format queries from showqueries if this is an AJAX request. (from r95855)
* [rev:98092] Initialise variables to fix unit test (from r95754)
* [rev:98091] Added ManifestBuilderTest::testThemeRetrieval() to test ManifestBuilder::get_themes()
* [rev:98090] Edit-case checking of data in ViewableData::$failover for better error message. (from r95560)
* [rev:98089] Don't try and access the ORM from ComplexTableField in situations where it shouldn't. (from r95544)
* [rev:98088] Boundary condition check in TableListField for more helpful errors. (from r95543)
* [rev:98086] Fixed FileTest execution if the assets/ directory doesn't exist. (from r88353)
* [rev:98085] added direct links to items in the backlinks report (from r88277)
* [rev:98084] unit test for getting members by permission via roles (from r88276)
* [rev:98079] Partially reverted accidental commit from r97920 (unconditionally requiring ADMIN login via BasicAuth in DevelopmentAdmin)
* [rev:98059] Changed MySQLDatabase::now() block comment to be more useful
* [rev:98056] Unit tests for Decimal field type default value through new test class DecimalTest
* [rev:98055] Allow creating fixture records without any columns by checking the fields exist first before doing a foreach() in YamlFixture::writeDataObject()
* [rev:98043] niced the way MultiEnums call requireField to give alternative adapter access
* [rev:98042] use ENUM hack for dealing with SET legacy values
* [rev:98032] visual tweaks to the widgets area including widget titles can now be spread over multiple lines and padding between columns. #4965
* [rev:98025] fix permissions
* [rev:98017] permission code is case sensitive in some cases
* [rev:97991] Deleted reference to CalendarDateField.js
* [rev:97991] Year validation (accept just 4 digit, like the error message says).
* [rev:97985] groupby works for SQLite too
* [rev:97979] Better error message on bad Enum default
* [rev:97936] add flv (flash file) to File::$allowed_extensions
* [rev:97920] Preserve theme settings in tests
* [rev:97910] Removed debug code
* [rev:97875] fix call to undefined method when a virtual page picks up the wrong object.
* [rev:97838] PHP notice error
* [rev:97825] Removed debug code
* [rev:97705] replaced proprietary update query with one that is ANSI compliant in doPublish()
* [rev:97669] #4674 applied patch for special chars in folder titles
* [rev:97652] Make SecurityDefaultAdminTest when you run it by itself.
* [rev:97602] Added better help text underneath "Available Widgets" and "Widgets currently used"
* [rev:97596] fix file iframe upload width
* [rev:97592] Re-enabled SiteTreePermissionsTest tests
* [rev:97566] If CurrencyField->setValue() passed a null or empty value, default to 0.00 so number_format() has no issues converting the number
* [rev:97543] Tree selector expands by default to show selected nodes
* [rev:97540] Cursor is now a pointer for available widgets, as you need to click them to add to the available widget stack
* [rev:97532] Removed end php tag from WidgetAreaEditor
* [rev:97511] Changed wording for WidgetAreaEditor.TOADD advising users to "click" instead of drag widgets
* [rev:97509] Fixed default wording of WidgetAreaEditor.TOADD "drag them here from the left"
* [rev:97487] Updated master translation file
* [rev:97486] Updated master translation file
* [rev:97485] Backwards compat fix for sprintf() call in CMSMain->providePermissions() (#4764)
* [rev:97484] Using SiteTree::get_by_link() in SiteTree->requireDefaultRecords() (see #4590)
* [rev:97483] Fixed setForm() invocation in Form::__construct() (see #4558, thanks ajshort)
* [rev:97481] Use addExtraClass() in FormField::__construct() instead of direct assignment (see #4607, thanks Tjofras)
* [rev:97478] Security::findAnAdministrator() names any default administrators 'Default Admin' instead of 'Admin'
* [rev:97435] Don't include files and folders starting with an underscore in the asset system.
* [rev:97435] Automatically rename files and folders beginning with an underscore. From: Andrew Short (from r97400)
* [rev:97434] Fixed deep-nested-URLs test to work on sites in subfolders (from r96836)
* [rev:97432] Made ComplexTableField sub-forms testable by returning rather than echoing results. From: Andrew Short (from r95035)
* [rev:97431] Allow a validation error to be thrown when a DataObject is saved in ComplexTableField. From: Andrew Short (from r95034)
* [rev:97369] Fixed MemberAuthenticatorTest, was setting global state in r97357
* [rev:97182] Reverted 'single instance only' feature from r79868, delayed until later release (see #4277)
* [rev:97178] Removed 'print' button from CMSMain->getEditForm() for display of older versions (see #4745)
* [rev:97072] added comments
* [rev:97035] folders without children in trees now have the folder icon
* [rev:97031] renamed 'filter' to 'search'
* [rev:96942] Removed unnecessary illegalExtensions data from TranslatableTest
* [rev:96882] Ensure DropdownField option elements have escaped the title correctly
* [rev:96877] added hooks for extending duplicate page functionality
* [rev:96830] Added explicit listing of testonly dataobjects for widget tests.
* [rev:96829] Fixed bugs with test execution.
* [rev:96827] Fixed CMSMainTest to be more flexible about modules altering the buttons.
* [rev:96816] moved allowed_extensions and friends to the model layer (from r92046)
* [rev:96815] moved File validation to the model (from r92044)
* [rev:96814] implement the allowedExtensions functionality of AssetAdmin when you rename a file (from r92037)
* [rev:96813] Made delete from draft batch action text more consistent with published. (from r91839)
* [rev:96808] add a hidden field to attach the subsite ID, rather than relying on the session (from r91014)
* [rev:96807] no longer assume with batch actions that the child pages of a parent are to be ticked (from r90999)
* [rev:96804] Fixed notice-level error in rollback. (from r90260)
* [rev:96803] Updated ModelAdminTest to use extraDataObjects (from r90055)
* [rev:96802] Removed debugging statements (from r90052)
* [rev:96801] Fixed testing quirk of static publisher unpublishing. (from r90048)
* [rev:96794] Make CMSMainTest compatible with cmsworkflow module. (from r89030)
* [rev:96789] added batch deletion back for workflow (from r88916)
* [rev:96788] more fix around batch action parameters (from r88837)
* [rev:96787] fix issue where javascript popup calendar would not fire (from r88836)
* [rev:96786] rename deleted pages report (from r88333)
* [rev:96784] create the ability to have some roles only be able to be applied by admins (from r88090)
* [rev:96783] remove default form actions. Unit tests pass. (from r88065)
* [rev:96776] fix javscript syntax that can confuse ie (from r86395)
* [rev:96772] Ensure that cuke can work with --dry-run (from r94819)
* [rev:96771] when a parent page is unpublished, unpublish all related virtual pages, includes test coverage (from r94777)
* [rev:96768] track virtual pages that link to the current page (from r94700)
* [rev:96753] Removed debugging information: (from r93151)
* [rev:96747] Give all test ADMIN privileges by default (from r92208)
* [rev:96745] Fixed SiteTree::canEdit() for records not yet saved to DB (from r92193)
* [rev:96744] can_edit_multiple() should return false, not 0, for permission failure. (from r92192)
* [rev:96743] moved allowed_extensions and friends to the model layer (from r92046)
* [rev:96742] moved File validation to the model (from r92044)
* [rev:96738] if looking at a specific stage, set a cooking to bypass static cacheing (from r91006)
* [rev:96737] virtual pages are now marked as broken if their pointer page is deleted (from r90996)
* [rev:96730] Flush get_one cache after rebuilding database schema. (from r89966)
* [rev:96716] fix syntax error (from r89472)
* [rev:96714] update merge info, merged in r87119 (from r88839)
* [rev:96710] changed the method to get a page's siteconfig, it is now subsite aware. (from r89870)
* [rev:96230] Moved defined variables in AssetAdmin::doUpload() to the top of the method for consistency
* [rev:95971] Set url variable in TreeAPI.reload as local variable in LeftAndMain_left.js
* [rev:95966] Added unit test for ViewableData::MultipleOf() when using an offset of 1 (an alternative approach)
* [rev:95086] make widgetarea/editor more suitable for generic use
* [rev:95070] remove relic of concurrent editing
* [rev:95052] remove director rule for removed Image_Uploader in r77012
* [rev:94986] adding maori macron button back
* [rev:94856] added comment
* [rev:94829] fixed bug where widget area editor would not be activated
* [rev:94711] test support for superglobals in testrequest
* [rev:94710] test support for superglobals in testrequest
* [rev:94684] added cookies to Director::test()
* [rev:94531] Fixed a few glitches in the cuke tests
* [rev:94529] Added a first cut of some cucumber tests for the CMS
* [rev:94528] Added db-fixture creation for cucumber-based testing
* [rev:94438] removed duplicate writes for performance
* [rev:94432] Don't use test manifest for dev/startsession and dev/endsession (from r93528) (from r94431)
* [rev:94429] Added small fixture YML that just lets you log in, for bootstrapping browser automation tests.
* [rev:94420] Fixed misspelled acronym for "Cross-site request forgery"
* [rev:94418] Documentation updates to SS_Log
* [rev:94359] Added tests methods for Member::can*() methods to MemberTest
* [rev:94359] Added test Extension classes for testing decorated can*() methods
* [rev:94358] Added additional tests to MemberTest
* [rev:94352] #4973 Automatically generate URLSegment for default records on SiteTree and ErrorPage instead of explicitly setting them
* [rev:94336] Tweak to test name display on the test runner
* [rev:94198] fixed widget area
* [rev:94198] added select box listing anchors in text
* [rev:94136] Fixed error message for Folder::addUploadToFolder() to be accurate
* [rev:94135] Less obtrusive tests for testing the SS temp directory
* [rev:94065] Added a few missing pieces to DataObjectSetTest::testMultipleOf()
* [rev:93966] Use jquery instead of prototype for silverstripenavigator
* [rev:93859] Fixed tabs
* [rev:93762] Javascript variable declarations in CMSMain_left.js (#4741)
* [rev:93738] Fixed reference to fieldExists() on SearchFilter which was removed from DataObject
* [rev:93701] reverted r93693 due to the field being required for the CMS
* [rev:93682] Removed calls to ContentNegotiator::disable() since it's disabled by default
* [rev:93681] Removed ContentNegotiator::disable() since it's disabled by default (in AssetAdmin)
* [rev:93662] Removed MemberTableField deprecated methods for adding fields - this should be done by implementing summary fields on a Member decorator instead
* [rev:93659] Removed ContentNegoitator::disable() from FormResponse - it's disabled already
* [rev:93641] Moved static functions in ContentNegotiator above the instance methods
* [rev:93623] Fixed capitalization of JSMin.php include (from r92870)
* [rev:93622] Fixed path for spyc thirdparty library
* [rev:93612] Updated paths from jsparty to sapphire/thirdparty, cms/thirdparty and cms/javascript
* [rev:93611] Updated paths from jsparty to sapphire/thirdparty, cms/thirdparty and sapphire/javascript
* [rev:93610] Moved jsparty/tiny_mce to sapphire/thirdparty/tinymce
* [rev:93591] Moved jsparty/greybox to sapphire/thirdparty/greybox
* [rev:93589] Moved jsparty/jquery/jquery_improvements.js to sapphire/javascript/jquery_improvements.js
* [rev:93577] Moved jsparty/prototype_improvements.js to sapphire/javascript/prototype_improvements.js
* [rev:93576] Moved jsparty/prototype15.js to sapphire/thirdparty/prototype/prototype15.js
* [rev:93575] Moved jsparty/prototype-safe.js to sapphire/thirdparty/prototype/prototype-safe.js
* [rev:93574] Moved jsparty/prototype.js to sapphire/thirdparty/prototype/prototype.js
* [rev:93571] Moved jsparty/loader.js to sapphire/javascript/loader.js
* [rev:93570] Moved jsparty/layout_helpers.js to sapphire/javascript/layout_helpers.js
* [rev:93569] Moved jsparty/hover.js to cms/javascript/hover.js
* [rev:93568] Moved jsparty/highlight.js to cms/javascript/highlight.js
* [rev:93567] Moved jsparty/tiny_mce_improvements.js to sapphire/javascript/tiny_mce_improvements.js
* [rev:93565] Moved jsparty/tree to sapphire/javascript/tree
* [rev:93564] Moved jsparty/tinymce_ssmacron to cms/javascript/tinymce_ssmacron
* [rev:93563] Moved jsparty/tinymce_ssbuttons to cms/javascript/tinymce_ssbuttons
* [rev:93562] Moved jsparty/tinymce_advcode to sapphire/thirdparty/tinymce-advcode
* [rev:93560] Moved jsparty/tabstrip to sapphire/thirdparty/tabstrip
* [rev:93559] Moved jsparty/SWFUpload to cms/thirdparty/swfupload
* [rev:93557] Copied jsparty/multifile to cms/thirdparty/multifile
* [rev:93555] Moved jsparty/calendar to sapphire/thirdparty/calendar
* [rev:93554] Moved jsparty/scriptaculous to sapphire/thirdparty/scriptaculous
* [rev:93553] Moved jsparty/jquery/plugins/greybox to sapphire/thirdparty/greybox
* [rev:93552] Moved jsparty/jquery/plugins/livequery to sapphire/thirdparty/jquery-livequery
* [rev:93551] Moved jsparty/jquery/plugins/metadata to sapphire/thirdparty/jquery-metadata
* [rev:93550] Moved jsparty/jquery/plugins/form to sapphire/thirdparty/jquery-form
* [rev:93549] Moved jsparty/jquery/plugins/effen to sapphire/thirdparty/jquery-effen
* [rev:93548] Added jquery.cookie library to allow saving of last selected jQuery UI tab (from r92507)
* [rev:93547] Moved jsparty/jquery/themes to sapphire/thirdparty/jquery-ui-themes
* [rev:93546] Moved jsparty/jquery/ui to sapphire/thirdparty/jquery-ui
* [rev:93544] Moved jsparty/jquery/jquery.js to sapphire/thirdparty/jquery
* [rev:93543] Added sapphire/thirdparty/firebug-lite (from r92496)
* [rev:93541] Added sapphire/thirdparty/behaviour (from r92497)
* [rev:93532] Added Zend_Log thirdparty dependency (merge from r84322) (merged from r92549)
* [rev:93530] Replaced sapphire/thirdparty/Zend external with piston-managed version (merged from r92492)
* [rev:93527] Added simpletest thirdparty library (previously included as an external) (merged from r92857)
* [rev:93526] Re-added sapphire/thirdparty/spyc library
* [rev:93525] Re-added sapphire/thirdparty/simplepie library
* [rev:93524] Re-added sapphire/thirdparty/jsmin library
* [rev:93521] Re-added sapphire/thirdparty/json dependency
* [rev:93449] Update the main.php PHP version numbers at the top doc block
* [rev:92351] Increase size of URL length to be lowest common denominator of maximum length in modern browsers.
* [rev:92220] Fixed appropriate failing tests to use PHP_EOL
* [rev:92135] Removed MemberTableField::setController() - this is now redundant from r92134
* [rev:92134] Added ComplexTableField::setController() which makes testing useful for switching between controllers
* [rev:91850] added stubs to allow widgets to use treedropdown fields
* [rev:91564] Moved Security::encryptallpasswords() to EncryptAllPasswordsTask (merged from r90948)
* [rev:91543] removed debug statements
* [rev:91541] fixed typo with path
* [rev:91394] BUGFIX Disabling security token in HtmlEditorField?->FlashForm?(), its not passed in by the ajax request (merged from r91392)
* [rev:91307] merged in 91306 from trunk
* [rev:91261] Whitespace change
### Other
* [rev:98173] ENHANCEMNT: Added export and print buttons to reports (from r95815)
* [rev:98172] Nicer dates (from r95776)
* [rev:98147] Validation for calendardatefields (from r96958)
* [rev:98093] Add some nice date formats (from r95772)
* [rev:98001] added a canCreateTopLevel() if there is no parent object in CMSMain.php
* [rev:98001] added testCreationOfTopLevelPage toCMSMainTest.php
* [rev:98001] added the nessessary 'database entries' in the CMSMainTest.yml
* [rev:97991] Deleted javascript/CalendarDateField.js. The file is empty.
* [rev:97898] Added values for new permission code 'VIEW_DRAFT_CONTENT' test
* [rev:97897] Added test for new permission code.
* [rev:97878] This covers the corner case where DB is out of sync with filesystem.
* [rev:97384] REVERT: r97017 (Try to tidy HTML...) as causes inconsistent HTML
* [rev:96966] REVERTED: 96961 fails the test, reverted.
* [rev:96926] `<a ... />` tag which is not so nice
* [rev:96781] point to the wrong subsite (from r87776)
* [rev:96779] admin section via URL (from r87320)
* [rev:96777] javascript syntax fixes (from r86396)
* [rev:96712] MERGE merged back a whole bunch of defect fixes from trunk (from r87846)
*

View File

@ -0,0 +1,555 @@
# 2.4.0-beta2 (2010-05-17)
## Changelog
### Features and Enhancements
* [rev:101127] Added 'Dependent pages' tab to CMS, to show virtuals, redirectors, and backlinks that point to this page.
* [rev:101054] Allowing SQLite selection in installer
* [rev:101054] Moved all Javascript containedin install.php and config-form.html to install.js, and using jQuery to simplify logic
* [rev:101054] Allow installer to attach custom form fields based on the install driver (as defined in _register_database.php)
* [rev:100989] If no arguments specified for cli-script.php/sake, then provide a friendly message to the user on where to get help
* [rev:100966] MoneyField currency dropdown can be made from an associate array like array('NZD'=>'New Zealand Dollor', 'USD'=>"United States Dollor') as well
* [rev:100940] Added help text for "locale" setting in installer
* [rev:100937] Redirecting to translated page when original is requested with a 'locale' GET parameter (e.g. 'about-us/?locale=de_DE' will redirect to 'ueber-uns' with a 301 HTTP response). Implemented in ContentController->handleRequest(). (see #5001)
* [rev:100908] Added DatabaseAdapterRegistry::unregister() to remove a database from the registry
* [rev:100902] Added _register_database.php to sapphire which sets the SS provided databases for DatabaseAdapterRegistry
* [rev:100893] Added Hebrew (he_IL) language to sapphire (thanks Oren, Yotam, tzvika, Amir, ohad)
* [rev:100893] Added Lithuanian (lt_LT) language to sapphire (thanks Irmantas, Mindaugas, Donatas, Andrius)
* [rev:100892] Added Hebrew (he_IL) language to cms (thanks Oren, Yotam, tzvika, Amir, ohad)
* [rev:100892] Added Lithuanian (lt_LT) language to cms (thanks Irmantas, Mindaugas, Donatas, Andrius)
* [rev:100884] Using jquery.live instead of livequery for SelectionGroup.js
* [rev:100852] Updated jquery.ondemand.js to sapphire trunk version, to ensure compatibility with jQuery 1.4.2
* [rev:100849] Only defining document.getElementsByClassName() in prototype.js if no native implementation exists (which speeds up the CMS). Ported from 'jquery13' module, thanks Hamish
* [rev:100847] Updated jquery.livequery from v1.0.2 to v1.1.1 (located in sapphire/thirdparty/jquery-livequery/
* [rev:100846] Updated jquery.metadata from ~v.1.0 to v2.1 (located in sapphire/thirdparty/jquery-metadata
* [rev:100845] Updated jQuery.form library from v2.08 to v2.40 (located in sapphire/thirdparty/jquery-form
* [rev:100844] Updated jQuery library from v1.2.6 to v1.4.2 (located in sapphire/thirdparty/jquery/
* [rev:100799] Creating default "Content Authors" group with limited rights if no other groups exist.
* [rev:100776] Better editing of roles through SecurityAdmin instead of a new "Roles" tab. Removed (previously unreleased) PermissionRoleAdmin. (see #4757)
* [rev:100774] Allowing custom popup requirements in ComplexTableField without subclassing through $requirementsForPopupCallback
* [rev:100771] Respecting SecurityAdmin::$hidden_permissions in PermissionRole->getCMSFields()
* [rev:100769] you can now choose your site locale at install time
* [rev:100753] Added 'updateImageForm', 'updateFlashForm', 'updateLinkForm' hooks to HtmlEditorField (the imageform hook was necessary to make the 'pixlr' module work) (see #3938)
* [rev:100696] show all database systems we support, along with messages if the user cannot use them. Also allow 3rd parties to register their own database classes to appear in this list.
* [rev:100536] Stored combined files in assets/_combinedfiles by default
* [rev:100529] Combined files now live in assets/.combinedfiles by default
* [rev:100528] #3387 Requirements now has a new static function called Requirements::set_combined_files_folder() for setting where the combined files should belong
* [rev:100453] #4599 DataObjectSet now uses more array functions instead of performing equivalent tasks - thanks simon_w!
* [rev:100423] Convert JSON functions now use the Services_JSON library where appropriate instead of custom code, and if json_decode() or json_encode() are available these are used
* [rev:100400] #5072 RSSFeed_Entry::rssField() now respects custom getters on the data class
* [rev:100327] allow ordering of page commented to be configurabled
* [rev:100058] AssetAdmin now uses Upload_Validator instead of setting the rules directly on Upload
* [rev:99954] you can now do coverage tests of single/multiple tests, or entire modules
* [rev:99942] fixed forward button underneath result form
* [rev:99929] #4787 Widget now respects updateCMSFields on extension classes so additional fields can be add (or existing ones removed)
* [rev:99845] #4043 Allow setting the from address for debug information in SS_LogEmailWriter - thanks Hamish!
* [rev:99841] #5024 Installer now checks that the user has entered a username and password correctly for the default admin, an additional button for re-checking requirements is now found at the bottom of the admin configuration section
* [rev:99841] Error messages for database AND admin configuration are now in the same place at the top of the installer
* [rev:99737] Allow DataObjectSet to remove duplicates based on any field (#5094, thanks mobiusnz) (from r99736)
* [rev:99692] Disabling/checking permission checkboxes in admin/security when 'ADMIN' permission is selected
* [rev:99690] Saving group relations on SecurityAdmin->EditForm()/RootForm() through TreeMultiselectField instead of hidden 'Group'/'GroupID' values (from r99579)
* [rev:99688] Saving MemberTableField through new 'Groups' field added in Member->getCMSFields(). (from r98882)
* [rev:99679] added new PageCommnet to yml so we have different amounts of moderated/unmodereated
* [rev:99677] Making setting optional in MemberTableField. Field instances without will list all members unfiltered, and remove members from the database rather than the group relation.
* [rev:99677] Allow disabling of 'inline add' formfields in a MemberTableField through setPermissions(array('inlineadd')) (from r98825)
* [rev:99667] Only show 'HTML Editor Config' dropdown in Group->getCMSFields() if more than one option exists
* [rev:99666] Showing checkboxes as disabled for inherited roles in Group->getCMSFields() (from r99597)
* [rev:99664] Added OptionsetField->setDisabledItems() to allow specifically disabling certain checkboxes
* [rev:99664] Added CheckboxSetField->setDefaultItems() to tick specified checkboxes regardless of the value passed (from r99596)
* [rev:99662] Showing (readonly) permissions for a Member record in admin/security popup (from r99586)
* [rev:99660] PermissionCheckboxSetField_Readonly (with all checkboxes disabled)
* [rev:99660] Added 'assigned to...' label to group permissions in PermissionCheckboxSetField - used in Member->getCMSFields() readonly permission view (from r99585)
* [rev:99658] Allowing PermissionCheckboxSetField to inspect multiple group records for existing permissions (from r99584)
* [rev:99648] View and select groups for a specific member via the member popup in admin/security (requires EDIT_PERMISSIONS) (from r98880)
* [rev:99361] Allow locale/dateformat specific reordering of day, month, year input fields in DateField
* [rev:99360] New DatetimeField class (form field wrapper composed of DateField andTimeField)
* [rev:99360] New DateField and TimeField form classes with more consistent API and easier localization
* [rev:99360] Using Zend_Date for DateField and TimeField, with more robust date handling, starting localization support. Set globally via i18n::set_locale(), or for a field instance through setLocale(). Note: Javascript validation is not localized yet.
* [rev:99302] SiteTree::batch_permission_check() populates its own cache (from r97900)
* [rev:99117] set file metadata on upload. (from r97780)
* [rev:99106] set file metadata on upload. (from r97780)
* [rev:99088] Add close link (from r97751)
* [rev:99080] Add Link to silverstripe navigator (from r97407)
* [rev:99069] added PageComment for CommentAdminTest
* [rev:99066] CommentAdmin unitest
* [rev:99047] Make navigator items more overloadable (from r97376)
* [rev:99046] Refactor links in $SilverStripeNavigator so modules can add extras (from r97299)
* [rev:98756] Added help texts for MemberImportForm and GroupImportForm (merged and rewritten from r98750)
* [rev:98737] Allow extension of LeftAndMain->getEditForm() (and subclasses) through a new updateEditForm() hook (see r98736 for additions to AssetAdmin and CMSMain)
* [rev:98736] Import groups from CSV in admin/security through the new GroupImportForm class (and GroupCsvBulkLoader) (merged and rewritten from r98711)
* [rev:98735] Allowing custom 'root forms' when id values '0' or 'root' are passed from the tree selection. (rewritten from r98710)
* [rev:98732] Import members and their group assignments from CSV in admin/security through the new MemberImportForm class (merged from r98708)
* [rev:98715] Added GroupCsvBulkLoader class to facilitate group imports with permission codes and hierarchy (merged from r94252)
* [rev:98714] MemberCsvBulkLoader for easy member import with group associations (merged from r94251)
* [rev:98713] Added BulkLoader->deleteExistingRecords(), removed unnecessary parameters from BulkLoader->load() (merged from r94250)
* [rev:98713] Decreased memory usage in BulkLoader->load() when deleting all records before importing (merged from r94250)
* [rev:98677] Added checkbox to switch off using the environment during install if it's available
* [rev:98659] #3903 Initial changes to installer to support selection of different database drivers
* [rev:98656] you can now pass arbitrary CURL options to the request() method of RestfulService.
* [rev:98469] Add HTMLCleaner abstract class, and Diff::cleanHTML()
* [rev:98428] Allow overriding TableListField_Item on TableListField by setting the property itemClass
### API Changes
* [rev:101155] Add option for DataObjectDecorator::onAfterSkippedWrite()
* [rev:101137] Partial cache adjustments - now supports nested cache blocks (which are independant of their containing cache block), conditionals to control if a given cache block is active, and includes hash of template code in key (so template changes mean cache is invalidated). Changes template control for cache block to `<% cached %>`, to which the now deprecated `<% cacheblock %>` is aliased, and an additional template control `<% uncached %>` has been added.
* [rev:101127] Added SiteTree::VirtualPages() and SiteTree::DependentPages() accessors.
* [rev:101119] Allow on_db_reset() methods on DataObjects as well as DataObjectDecortators
* [rev:101093] Replaced eval based creation of extension and field objects with Object::create_from_string().
* [rev:101093] Introduced new function Object::create_from_string() to instantiate an object from a string like 'Int(50)'
* [rev:101044] Made MySQL fulltext search optional, activated with MySQLFulltextSearchable::enable()
* [rev:101043] Pass the full extension string as the 2nd argument to DataObjectDecorator::extraStatics()
* [rev:100842] Upgraded jQuery UI from v1.6rc1 (r687) to v1.8rc3. This release prefixes all *.js and *.css files with 'jquery', so ui.core.js is now called jquery.ui.core.js.
* [rev:100842] Upgraded jQuery UI themes from v1.6rc1 to v1.8rc3. Removed 'flora' and 'default' themes, replaced with the 'base' and 'smoothness' themes found in the default distribution
* [rev:100718] Removed "auto-merging" of member records from Member->onBeforeWrite() due to security reasons - please use DataObject->merge() explicitly if this is desired behaviour (from r100705)
* [rev:100651] dbDataType function created
* [rev:100513] Refactored Requirements to use Requirements_Backend at all times - this makes testing far easier. Thanks tobych!
* [rev:100512] TreeDropdownField no longer requires your object to have the Hierarchy extension
* [rev:100503] Removed deprecated Email_Template class, please use Email instead!
* [rev:100498] Removed deprecated Image::loadUploaded() (deprecated from the parent::loadUploaded for which it called), please use Upload directly instead!
* [rev:100495] Removed deprecated File::loadUploaded(), please use Upload directly instead!
* [rev:100493] Removed deprecated function RootURLController::get_homepage_urlsegment(), please use RootURLController::get_homepage_link() instead!
* [rev:100492] Removed deprecated function SiteTree::get_by_url(), please use SiteTree::get_by_link() instead!
* [rev:100490] Removed deprecated methods DataObjectSet::filter_map() and DataObjectSet::map_multiple() - please use map() instead!
* [rev:100057] #5107 Upload now uses Upload_Validator to separate the validation rules from the File loading done in the Upload class
* [rev:99849] SiteTree::validURLSegment extendable (#5907)
* [rev:99360] Date/time parsing in DateField, TimeField and DatetimeField defaults to i18n::get_locale() ('en_US') instead of using en_NZ/en_GB specific parsing. Use i18n::set_locale('en_NZ') in mysite/_config.php to revert to old behaviour.
* [rev:99360] $timeformat constructor parameter in TimeField needs to be in ISO date notation (not PHP's date())
* [rev:99360] TimeField, DateField and related subclasses use Zend_Date for date parsing, meaning they're stricer than the previously used strtotime()
* [rev:99360] Removed DMYCalendarDateField and CalendarDateField, use DateField with setConfig('showcalendar')
* [rev:99360] Removed CompositeDateField, DMYDateField, use DateField with setConfig('dmyfields')
* [rev:99360] Removed DropdownTimeField, use TimeField with setConfig('showdropdown')
* [rev:99360] Removed PopupDateTimeField, use DatetimeField
* [rev:99360] Changed 'date', 'month' and 'year' HTML field names to lowercase in DMYDateField
* [rev:99360] Removed support for ambiguous date formats in DateField, e.g. '06/03/03'. Use DateField->setConfig('dateformat', `<format>`) to revert to this behaviour.
* [rev:99360] Removed $futureOnly flag from DateField, CalendarDateField etc., use DateField->setConfig('min') and DateField->setConfig('max')
* [rev:99119] Refactor Versioned so a single state is kept for stage, archived date, or any module specific reading modes (from r98161)
* [rev:99114] Use the same navigator items in the CMS that are used on the frontend (from r97395)
* [rev:99079] Use the same navigator items in the CMS that are used on the frontend (from r97395)
* [rev:99063] Let sitetree extensions prepopulate permisson cache for their own permissions. (from r98650)
* [rev:99051] Let any DataObjectDecorator define an on_db_reset() method that is called by tests, like in Versioned. (from r97734)
* [rev:98786] Installer now uses a database configuration helper class which isolates the logic of checking the database away from the installer, this interface can be used by other databases like MSSQL and PostgreSQL. The installer now looks for a specific file inside each database module, provided it's configured in install.php MySQL is provided by default, as it lives in sapphire
* [rev:98543] Made ComplexTableField not use Object::create() for item and popup classes to be consistent with TableListField. These can be overridden as itemClass and popupClass are public properties on ComplexTableField
* [rev:98373] HTTP::setGetVar() always returns absolute URLs. Use Director::makeRelative() to make them relative again.
* [rev:98373] HTTP::setGetVar() combines any GET parameters in PHP array notation (e.g. "foo[bar]=val") instead of replacing the whole array
### Bugfixes
* [rev:101175] Fixed quotes around Folder::hasChildFolders() ParentID column
* [rev:101173] Don't run click() on all inputs, but input:radio only
* [rev:101171] Pass correct class to allowPrimaryKeyEditing in yaml fixture
* [rev:101170] Don't recreate a missing draft page when calling SiteTree::doUnpublish()
* [rev:101167] #5216 Installer has issues with click handlers applied to the entire li, be more specific and apply it to the label and input instead
* [rev:101165] Fixed versioning of pages
* [rev:101155] Prevent failed migrateVersion writes from breaking versioning system in future writes.
* [rev:101155] MAke site tree pages go green when you save a new draft.
* [rev:101154] #5214 ViewableData::obj() was creating a DBField without a fieldname argument and caused problems, one example is the version panel of the CMS
* [rev:101153] Ensure that Versioned works on classes with underscores in the names. (from r100905)
* [rev:101138] Fixed issues with broekn link tracking
* [rev:101131] Allow classes to be referred to with casing that differs from their definition.
* [rev:101129] Fixed FileLinkTrackingTest to cope with the empty alt="" and title="" attributes that are created
* [rev:101127] Improved reliabilty of broken link tracking.
* [rev:101127] Don't mark a page as changed on stage if the only thing that has changed is broken link metadata
* [rev:101116] Flush cache after deleting an item.
* [rev:101116] Fixed databaseFieldsOnly version of DataObject::getChangedFields()
* [rev:101112] Fixed bugs with copying custom fields into Virtual pages, generally made virtual pages more robust and performant.
* [rev:101110] Fixed link rewriting to work on other HTMLText fields (from r99517)
* [rev:101109] Return true if SiteTree:doUnpublish() succeeds. (from r99515)
* [rev:101105] Update Object::parse_class_spec() to handle arrays.
* [rev:101099] call_user_func_array changed to PHP 5.1 compatible notation
* [rev:101087] #5202 Installer now properly populates database configuration inputs from request after user clicks "Re-check requirements"
* [rev:101080] Fixed TableListField->print() - was unsetting $cachedSourceItems instead of null'ing it, which breaks later access to the property
* [rev:101068] #5199 Duplicate file uploads have odd numbering attached to end of file
* [rev:101061] Fixed Upload and checking for size with files that don't have any extension
* [rev:101051] Allow files with no extensions by setting File::$allowed_extensions with an empty string
* [rev:101050] #5188 Upload and Folder don't handle the duplicate naming of files that have no extension
* [rev:101046] Cookies set to a value other than NULL (effectively unsetting the cookie) will now use the httpOnly parameter by default for better XSS protection (from r101045)
* [rev:101034] Fix static caching file lookup to match file generation.
* [rev:101005] Image should pass through the title to Image_Cached so that Image::getTag() can produce a more useful alt attribute instead of just the filename (from r101003)
* [rev:100998] column and table names now quoted properly
* [rev:100986] Disable javascript date validation via DateField->jsValidation() if locale is not 'en_NZ" (which is the only format it validates for).
* [rev:100985] HTMLEditorField->saveInto() can now find images with urlencoded information for resample (e.g. spaces in filenames)
* [rev:100982] Fixed file-write testing issues in requirements combined file generation
* [rev:100980] Remove cache for Hierarchy::AllChildren() and Hierarchy::AllChildrenIncludingDeleted(), since they increase memory usage unnecessarily.
* [rev:100979] Don't make CMS loading slow if the combined javascript files can't be written.
* [rev:100932] SiteTree::getSiteConfig() should always fall back to using a default if an alternate config wasn't found
* [rev:100924] Allow DatabaseAdmin to run dev/build in live mode when not Security::is_database_ready(), and avoid broken login due to broken db queries (selecting unknown columns before dev/build) (see #4957)
* [rev:100921] DataObject::hasValue() is now compatible with parent ViewableData::hasValue() (this also fixes E_STRICT standards in PHP)
* [rev:100919] RequestHandler::handleRequest is now compatible with Controller::handleRequest in that SS_HTTPRequest is the type hint for the $request parameter
* [rev:100918] ManifestBuilder::up_children() should be declared as static as it's called statically
* [rev:100904] Produce XHTML compliant URLs in HTTP::setGetVar() by default (regression from r98373, see #5101)
* [rev:100896] #5138: DataObjectSet::removeDuplicates() removes objects of different classes with the same ID
* [rev:100866] #5176 Javascript error in IE for the installer - use "this" instead of e.target which doesn't work
* [rev:100862] Use "wb" argument in ManifestBuilder fopen() calls for better cross-platform compatibility
* [rev:100861] #5157 If paths are longer than 255 characters, fopen() produces an "Invalid argument" error, shorten the paths by using basename() instead of realpath() on the manifest filename when producing the cache path in ManifestBuilder
* [rev:100858] Fixed notice level error with folder ID
* [rev:100854] fixed file uploading not uploading any files at all
* [rev:100853] Fixed jQuery.ondemand.js script to work with prototype.js (will probably need to be merged back to trunk for legacy purposes)
* [rev:100848] Fixed variable declaration order in tabstrip.js (necessary due to changed jquery.livequery behaviour
* [rev:100825] Added single quote as a valid local-part of an email address as per RFC5322. Other symbols still excluded although in the spec
* [rev:100795] #5157 strftime() %F format parameter does not work on Windows - use %Y-%m-%d instead
* [rev:100767] Date::now() supplies wrong string - it misses leading zeroes on hours
* [rev:100763] added uniqueness id, to prevet multiple VirtuaLage reloads on publish
* [rev:100755] TreeSelectorField doubles up on concating base_url, doesn't include the security ID (#5164, thanks marcus)
* [rev:100747] #5099 FileIFrameField fails when using it with a locale different to the default
* [rev:100727] allow selection of database adpater
* [rev:100726] misspelled variable
* [rev:100724] some sections dont have a tree at all, but they still use LeftAndMain as their base class (eg report admin). Added a guard.
* [rev:100723] Fixed SapphireTest->loginWithPermission() and MemberAuthenticatorTest to use existing Members based on their unique_identifier_field (if existing) to accommodate recent Member->onBeforeWrite() changes (see r100705)
* [rev:100722] reload page if broken link tracking values changed during a save. Ticket #1363
* [rev:100721] Unsetting 'ID' parameter in MemberTableField->addtogroup() to avoid confusion between Group and Member records (regression from r100716) (from r100720)
* [rev:100719] Fixed MemberTableField->addtogroup() to fetch existing Member records by ID or $unique_identifier_field instead of relying on the (now removed) "auto-merging" in Member->onBeforeWrite() (see r100705) (from r100716)
* [rev:100717] Fixing Member_ProfileForm to validate for existing members via Member_Validator to avoid CMS users to switch to another existing user account by using their email address (from r100704)
* [rev:100701] moving the ajaxupdatesort JS response code from php to js to get rid of eval. Also disable the "loading" on the moved element when we are done, in case we are repositioning other than the selected item - otherwise the progress indicator is displayed indefinitely.
* [rev:100699] column names quoted properly
* [rev:100693] column names quoted properly
* [rev:100692] column names quoted properly
* [rev:100691] column names quoted properly
* [rev:100690] column names quoted properly
* [rev:100689] column name capitalised
* [rev:100688] column names quoted properly
* [rev:100687] column names quoted properly
* [rev:100686] the default value for decimals are now cast as (doubles)
* [rev:100657] tables and columns now quoted properly
* [rev:100632] Fixed SiteTree->MetaTags() to either use `<meta name=>` or `<meta http-equiv=>`, and only using the "http-equiv" attribute for valid HTTP headers (see http://www.w3.org/TR/html4/struct/global.html#edef-META) (from r100631)
* [rev:100627] DB::getConnect() should be properly declared as a static function
* [rev:100616] Fixed filemtime() check in Requirements_Backend::process_combined_files() not getting the right path
* [rev:100614] Proper check for combined file path in Requirements_Backend::process_combined_files()
* [rev:100560] #4572 Fixed Windows failure on SS_Cli::supports_colour() because posix functions are not supported
* [rev:100548] If fixture file is NULL don't cause the test framework to break down because of it
* [rev:100527] Set Member default Locale
* [rev:100525] get TreeMultiselectField working with an array of items, rather than a relation.
* [rev:100519] add 'var' to local variable 'constructor' inside of function definition which break IE8 (8.0.6001.18702 +)
* [rev:100508] wrong constructor function name
* [rev:100496] replacing calls to deprecated Upload functions - using validator instead (related to r100057)
* [rev:100466] #5012 BasicAuth should check if there's already a current member logged in before asking for a login/password
* [rev:100438] GD::setQuality() persistence issue because the GD instance is re-created instead of being cloned - thanks Tjofras!
* [rev:100417] #5121 Fixed cache flushing for FieldSet when removing fields - thanks paradigmincarnate!
* [rev:100415] #5136 Ensure $coverage argument to TestRunner::runTests() has a strict check before running coverage tests, as sometimes an SS_HTTPRequest object can be passed into this argument
* [rev:100407] FormAction input tag attributes were being doubly-escaped.
* [rev:100406] Fix mismatch with $all_locales and $common_locales (#5096)
* [rev:100394] #5135 LeftAndMain extra requirements loading for "themedcss" should use Requirements::themedCSS() not Requirements::css() - thanks Hamish!
* [rev:100393] YamlFixture::writeDataObject() - some databases need special allowance to edit the primary key column - do so by using DB::getConn()->allowPrimaryKeyEditing()
* [rev:100375] Sam's fix for "Unknown column Group.SubsiteID" with new subsites
* [rev:100370] use localized prefix to compare group codes rather than hard coded english string. MINOR: updated lang file
* [rev:100367] PHP 5.1 requires an array rather than a string for call_user_func()
* [rev:100359] Show Language dropdown in English (#5098)
* [rev:100335] #5023 AssetAdmin::sync() is now used to sync tasks, as it works when the user only has access to the AssetAdmin controller instead of going to dev/tasks/FilesystemSyncTask which can only be run by administrators or if the site is in dev mode
* [rev:100116] Fix TestRunner coverage pattern to work as documented (Fixes QA scripts too)
* [rev:100053] SQL Error is a member is not part of any groups
* [rev:99993] Setting default $groups in MemberTableField::AddForm() in addition to MemberTableField_Popup::__construct() - this was broken by r99777
* [rev:99960] #2022: Fixed CMS dropdowns in Opera.
* [rev:99952] Fix #2138, allow modification of existing images
* [rev:99951] Fix #2138, notify Image Toolbar on TinyMCE node selection change
* [rev:99942] action buttons always visible (not need to scroll) ticket 5051
* [rev:99942] got rid of double scroll
* [rev:99942] do not show action buttons (delete/save) when showing result list
* [rev:99887] Use underscores in names of combined .js (#3581)
* [rev:99854] Quoting keys in JSONDataFormatter to ensure valid JSON (#5119) (from r99853)
* [rev:99850] Fix #5097, Translatable uses augmentValidURLSegment to check that URLSegment is valid
* [rev:99843] Respect SilverStripe's cache folder
* [rev:99818] Handle filename deduping when uploading of double-barrelled extensions and files ending in numbers better.
* [rev:99816] Fixed the code for the unused file list, although the feature is still disabled.
* [rev:99789] #5073: Fixed CMS version indicator for alpha and beta versions.
* [rev:99779] make siteconfig work again
* [rev:99777] #5087: Show default values in CTF 'add' popups.
* [rev:99745] #3458: Don't show javascript:mctmp(0) URLs in URL editor
* [rev:99739] tree selector base URL calculation wrong when field is nested
* [rev:99738] #4974: Improve accuracy of ManifestBuilder::parse_file() cache, to remove a source of upgrade bugs.
* [rev:99713] Fixed MemberTableField limiting of , wasnt taking children groups into account (regression from r99684) (from r99706)
* [rev:99711] Setting ID explicitly in MemberTableField-> to ensure getCsvQuery() correctly filters (the custom group filter was only implemented in sourceItems() before) (from r99684)
* [rev:99693] Changed sitetree default selection in LeftAndMain.Tree.js to fire on window.load instead of document.ready() through entwine. We need to ensure behaviour.js bindings are available before
* [rev:99693] Automatically selecting root node in CMS trees (necessary because now we actually have forms on the root node, and its a valid click target) (from r99605)
* [rev:99679] really testing deletemarked now.
* [rev:99667] Fixed bogus HTMLEditorConfig instance when get() is called without a valid identifier (due to NULL database columns) (from r99599)
* [rev:99655] Fixed TreeMultiselectField/TreeDropdownField saving with 'unchanged' default values from constructor (from r99581)
* [rev:99647] Fixed TreeMultiselectField->Field() to respect settings, and give them priority over existing relations through getItems(). This is used in MemberTableField to set default groups for 'add member' popups. (from r98879)
* [rev:99640] Fixed DataObject->fieldLabels() to respect flag (from r98748)
* [rev:99638] Folder::findOrMake() will create the assets/ folder if it's missing
* [rev:99613] Fixed bug in r99552
* [rev:99595] Fixed Access tab on SiteConfig
* [rev:99594] Debugged and simplified Access tab javascript
* [rev:99587] Show 'Inherit' option for edit and view all the time (since we now have SiteConfig)
* [rev:99572] Pages that you can't edit should always be grey, even if there are unpublished changes.
* [rev:99553] Remove buttons from display if you load a CMS page that should have no buttons - reverts bug caused by r96551 and fixes the issue it was trying to solve.
* [rev:99552] Fixed behaviour's ID selector matching when the ID is inside another context - eg 'body.className #ID'
* [rev:99522] Image::onBeforeDelete() now calls deleteFormattedImages() so resampled images in the filesystem are cleaned up
* [rev:99506] use the correct method for retrieving the report ID
* [rev:99490] tablename and columns quoted properly
* [rev:99479] Setting ID = -1 on Security/lostpassword to avoid showing toplevel navigation (see #5086)
* [rev:99465] Correct StaticPublisher filenames, now works with nested URLS
* [rev:99443] batch_permission_check returns null rather than empty array when user has no permissions
* [rev:99394] Fixed variable existence checks in setValue() in FormField::__construct() by checking for !== NULL (changed from isset($value) to $value in r99360)
* [rev:99391] Fixed MoneyField constructor - parent (FormField) constructor calls setValue() already, which needs to happen *after* setting certain field instances
* [rev:99342] Enforcing creation of temp database in SapphireTest->setUp() to avoid writing to production databases. This check should only kick in for single test case runs, as the temp database connection should be set in a dev/tests/all run after the first db-related test anyway. (see #5034)
* [rev:99303] Disable some permission caching for now, as it was breaking unit tests (from r98504)
* [rev:99302] SiteTree::batch_permission_check() doesn't recurse with ID=0 calls
* [rev:99128] Fix not being able to print/export reports (from r98684)
* [rev:99125] Fixed cache prepopulation on sitetree load. (from r98651)
* [rev:99124] Make sure navigation links update when urlsegment is changed (from r98649)
* [rev:99116] Fix navigator links not opening in new windows. (from r97510)
* [rev:99115] Fixed bug in r97395 (from r97508)
* [rev:99101] Take into account tablename with custom columns in get_title_sql (from r97003)
* [rev:99100] use proper quotes for sep (from r96401)
* [rev:99089] Only show live link when page has been published (from r97839)
* [rev:99087] Make sure draft/published links go to the right subsite (from r97747)
* [rev:99086] Fix navigator links not opening in new windows. (from r97510)
* [rev:99085] Show a hand icon and better title for the 'share link' piece of the navigator toolbar. (from r97439)
* [rev:99067] Ensure that ModelAsController::init() can trigger redirections. (from r98702)
* [rev:99065] Fixed SiteTree_versions version numbers for published virtual pages. (from r98675)
* [rev:99060] fixed query to get number of unmoderated comments
* [rev:99052] Generate SiteTree_version records for VirtualPages more reliably. (from r98309)
* [rev:99050] fix incorrect link in CMS (from r97408)
* [rev:99049] Make sure CMS link knows when its currently in the CMS (from r97403)
* [rev:99031] Don't show FailedLoginCount field unless Member::$lock_out_after_incorrect_logins is enabled
* [rev:99005] Development server list should be retained when user submits installer form and gets redirected back
* [rev:98957] fix for #5076
* [rev:98946] the ID should be that of untranslated child (it's the middle segment that's from translated version, not the last one)
* [rev:98944] testing framework needs to be reset to a clean state after each test: now also nested urls and redirection state will be reverted
* [rev:98897] Fixed strpos() check in BASE_URL check
* [rev:98895] Installer now opens if mod_rewrite is disabled. Using index.php instead of rewriting the URL didn't quite work with the new BASE_URL, so we need to take this case into account as well
* [rev:98869] Fixed big problem on Windows when redirecting to install.php - because of SCRIPT_NAME backslashes caused a bit of havoc and need special treatment
* [rev:98860] restore the original nested_urls state after running the test, so we can enable and disable nested URLs within the tests safely.
* [rev:98853] Fixed URL generation in TreeSelectorField.js, was failing to detect relative URLs - prefixing with `<base>` URL as a workaround
* [rev:98852] Added missing Requirements to TreeDropdownField->Field() and TreeMultiSelect->Field()
* [rev:98847] modified float to have the same database table schema as int. Now defaults to zero and 'not null'
* [rev:98777] Fixed quoting on ContentController::successfullyinstaller() - this broke certain databases like PostgreSQL
* [rev:98776] #5053 Aggregate::query() should not set an orderby clause, otherwise databases will complain
* [rev:98694] columns quoted properly
* [rev:98693] Fixed ManifestBuilder::has_been_included()
* [rev:98690] Closing TinyMCE image, link or flash panel when loading form (ticket #4907)
* [rev:98688] Checkbox for overriding the install from environment now checks for the file existance properly
* [rev:98678] Fixed initial state of "use environment" checkbox in installer
* [rev:98671] fallback for changes in r98101, required if TreeDropdownField is used in a widgetarea, and does not know its field
* [rev:98537] Fixed ManifestBuilder::get_themes() not to assume an existing themes/ folder
* [rev:98536] Removed obsolete start argument from ComplexTableField_Item constructor.
* [rev:98534] Make Security/login page's ID give a different number for loggedin vs loggedout, to help with partial caching
* [rev:98520] Fix virtual pages not returning correct content
* [rev:98448] Fixed missing third argument to ComplexTableField_Item when the parent class instantiates it
* [rev:98434] Fixed infinite loop in FILE_TO_URL_MAPPING lookup when calling arbitrary scripts via CLI
* [rev:98432] Make login form work without any theme loaded.
* [rev:98403] Fixed Hierarchy->loadDescendantIdList() to call setOwner() on the extension instance. This was necessary due to underlying Object/Extension changes in 2.4.
* [rev:98382] #5044 Hierarchy::loadDescendantIDListInto() now uses Object::getExtensionInstance('Hierarchy') instead of going through __call(), as PHP 5.3 has issues converting references to values
* [rev:98373] HTTP::setGetVar() uses parse_url() and http_build_query() to add query parameters to an existing URL, instead of doing its own regex-based parsing. This means existing GET parameters are correctly url encoded.
* [rev:98324] Fixed ContentController->deleteinstallfiles (added to $allowed_actions, see #5040)
### Minor changes
* [rev:101172] Fix output format of buildbot test runs to not include colour control codes.
* [rev:101166] versioning test for SiteTree
* [rev:101135] Fixed multifile.js non-standard forEach() reference, using jQuery.each() instead
* [rev:101134] Localized "dependent pages" features in SiteTree->getCMSFields()
* [rev:101132] Fixed test that was relying on bug fixed in r101116
* [rev:101117] Fixed test that was relying on bug fixed in r101116
* [rev:101111] Fixed wrong default value for AssetAdmin (see r101106)
* [rev:101107] Documentation relating to r101106
* [rev:101106] Disabled metadata upload in AssetAdmin by default, configurable through AssetAdmin::$metadata_upload_enabled. Feature needs UI review.
* [rev:101091] Use castingHelper() rather than castingHelperPair() to look for a field presence.
* [rev:101076] Fixed merge error from r99117
* [rev:101071] Updated lang files
* [rev:101070] Fixed PermissionCheckboxSetField.js checkbox toggling when no previous values have been saved through jQuery.data()
* [rev:101062] Fixed permission language code regression
* [rev:101057] Improved wording of SQLite installer
* [rev:101055] No need for a ternary for in_array check in Upload::isValidExtension()
* [rev:101053] Update function doc for Upload::isValidExtension()
* [rev:101052] phpDoc change for Upload
* [rev:101025] tests can now require default records on classes
* [rev:100992] Removed unused variable in SiteTree::MetaTags()
* [rev:100991] UploadTest now cleans up after itself when it creates a custom folder relative to assets
* [rev:100990] Added tests for Upload_Validator/UploadTest_Validator for allowed extensions validation
* [rev:100988] Updated required version to 5.1 in php5-required template
* [rev:100978] Removed whitespace from "Development servers" textarea for installer
* [rev:100975] Updated r100966 to include spaces on ternary operator for readability and coding conventions
* [rev:100974] Adjusted CMSMain->getRootForm() to SiteConfig API changes
* [rev:100967] Renamed SiteTree->getEditFormFields() to getCMSFields() (including new decorator hook for 'updateCMSFields'). Renamed SiteTree->getEditFormActions() to getCMSActions() (including new decorator hook for 'updateCMSActions'). Old API was never released
* [rev:100965] Fixed "disabled" styling for database options in config-form.html (showed all as green when "use _ss_environment" was ticked
* [rev:100950] Correction on email address validator, and a unit test for EmailField php validation
* [rev:100946] Added jQuery requirement to TreeDropdownField (see #5139)
* [rev:100940] Changed `<div>` hierarchy in config-form.html to allow right-aligned help texts which horizontically align with their respective field sets on the left.
* [rev:100922] Fixed phpDoc argument in ViewableData::hasValue()
* [rev:100898] Changed the way DatabaseAdapterRegistry accepts databases
* [rev:100893] Updated languages in cms from translate.silverstripe.org
* [rev:100892] Updated languages in cms from translate.silverstripe.org
* [rev:100891] Updated sapphire/ lang files
* [rev:100890] Updated cms/ lang files
* [rev:100888] Using jquery.live instead of livequery in MemberImportForm.js
* [rev:100887] Using jquery.live and behaviour.js instead of livequery in ModelAdmin.js
* [rev:100886] Using jquery.live instead of livequery on ImageFormAction.js
* [rev:100885] Using Behaviour.register instead of jquery.livequery in TabSet.php/tabstrip.js (already replaced with jQuery.entwine in next release, we try to reduce the dependencies to jquery plugins)
* [rev:100883] SilverStripeNavigator.js used jquery.live instead of livequery, and doesn't include unnecessary behaviour.js
* [rev:100851] Fixed jquery-ui paths in FileIframeField
* [rev:100850] Fixed jQuery selector in TreeSelectorField.js to fit jQuery 1.4 syntax
* [rev:100843] Added jQuery UI license files
* [rev:100832] Supress notice if $_REQUEST['url'] doesn't exist in Debug::showError()
* [rev:100801] removed sqlite msg
* [rev:100799] Moved Permission->requireDefaultRecords() to Group->requireDefaultRecords() and Member->requireDefaultRecords().
* [rev:100799] Removed outdated checks for CanCMS and CanCMSAdmin from Permission->requireDefaultRecords()
* [rev:100791] Using PermissionCheckboxSetField.js instead of MemberTableField.js
* [rev:100790] Moved PermissionCheckboxSetField specific javascript logic from MemberTableField.js to new sapphire/javascript/PermissionCheckboxSetField.js file
* [rev:100789] Improved help texts around permissions
* [rev:100784] Improved help texts around permissions
* [rev:100783] Improved help texts around permissions
* [rev:100775] Fixed regression from r100774
* [rev:100774] Added getParentController() to TableListField_ItemRequest and ComplexTableField_Popup
* [rev:100774] Extending ComplexTableField_ItemRequest from TableListField_ItemRequest to avoid redundant code
* [rev:100772] dont copy embargo or expiry to virtual page
* [rev:100771] Setting PermissionRole $singular_name and $plural_name
* [rev:100770] Removed "only advanced users" notice in Group->getCMSFields() - this field is now sufficiently useable for all admins with access to admin/security without knowing about permission codes
* [rev:100740] Added more allowed extensions to File::$allowed_extensions
* [rev:100732] make cache header clearer
* [rev:100697] remove the sqlite databases from the installer list.
* [rev:100670] Director::currentPage() is deprecated but shouldn't throw a notice-level error until the next major release.
* [rev:100669] Added note about other databases
* [rev:100626] BasicAuth - removed unncessary extending of Object since this class only has a bunch of static functions
* [rev:100625] Cookie - removed unncessary extending of Object since this class only has a bunch of static functions
* [rev:100624] Convert - removed unncessary extending of Object since this class only has a bunch of static functions
* [rev:100623] ArrayLib - removed unncessary extending of Object since this class only has a bunch of static functions
* [rev:100622] When the installer is using the environment for configuration, disable the development servers textarea as it's automatically configured from environment
* [rev:100618] Removed double slashes from path in Requirements_Backend::process_combined_files()
* [rev:100615] Requirements_Backend::process_combined_files() only needs one location where the combined file is
* [rev:100552] Wording change in installer for database details not correct
* [rev:100550] Fixed undefined variable $error in MySQLDatabaseConfigurationHelper
* [rev:100537] Removed underscores from combined files in LeftAndMain, made redundant by r100536
* [rev:100534] Reverted default location for combined JS/CSS as you can't customise this easily
* [rev:100533] Removed Requirements:: static call and replace with instance
* [rev:100530] LeftAndMain combined files don't need to be prefixed with "assets" because default combined folder is set in sapphire/_config.php
* [rev:100517] Removed whitespace
* [rev:100514] Removed end php tag for Requirements and RequirementsTest
* [rev:100513] Updated RequirementsTest to test Requirements_Backend instead of global statics
* [rev:100511] can always create top level if admin
* [rev:100499] Made Upload::load() error more useful
* [rev:100491] Fixed tabbing in DataObjectSet
* [rev:100487] Changed places of Object::extInstance() to Object::getExtensionInstance() and added a notice if extInstance is used in future
* [rev:100486] Pushed @deprecated 2.3 items out to 2.5 since they're still in use for now
* [rev:100485] Reverted r100484 as it was causing too many problems
* [rev:100484] Replaced locations of Director::is_ajax() and Director::redirectBack() with instance method calls - the latter static function is deprecated
* [rev:100483] Changed @deprecated note for Director::redirectBack to 2.5 as it's still widely used
* [rev:100461] Fixed regression of Convert::json2obj() not working when json_decode() is being used
* [rev:100424] phpDoc bits for Convert Services_JSON functions
* [rev:100423] Added unit tests for Convert JSON functions
* [rev:100418] Use "email" instead of username for validation of admin account during install
* [rev:100409] Geoip class no longer extends Object, as it's not necessary
* [rev:100387] Updated installer to use "CMS / Framework" instead of just "CMS"
* [rev:100387] Updated copyright year to current year
* [rev:100372] added lang file for cs_CZ
* [rev:100360] add extendability to SecurityAdmin
* [rev:100323] correct order of OBW
* [rev:100032] added Rfc2822 method to SS_Datetime. Fixed bug where dates in DataObject would not set times.
* [rev:100008] LastEdited/Created dates are now mockable via SS_Datetime
* [rev:99957] Reverted r99843 - we're not modifying thirdparty dependencies
* [rev:99862] Reinstated UploadTest
* [rev:99823] Reverted r99522 as this will cause problems if File records are deleted when the resampled images are linked to in the content fields
* [rev:99801] Added Group->CMSTreeClasses() (required for GroupCsvBulkLoader refresh in SecurityAdmin)
* [rev:99753] Cleaned up tabbing and code formatting in automated task classes
* [rev:99750] More tests for array data
* [rev:99715] Fixed OptionsetField->disabledItems omission from r99596 (from r99708)
* [rev:99714] Fixed MemberTableField regression from r99706 (from r99710)
* [rev:99689] Fixed height of MemberTableField 'Groups' tab to allow enough room for TreeMultiSelectField expansion (from r98883)
* [rev:99687] Moved generic .TreeDropdownField styling from cms/css/cms_right.css to sapphire/css/TreeDropdownField.css (from r98881)
* [rev:99686] Moved ul.tree rules from cms/css/cms_left.css to sapphire/javascript/tree/tree.css (particularly around multiselect tickbox styling) (see r98854) (merged from r98855) (from r98865)
* [rev:99668] Placing 'ADMIN' permission in new 'Administrator' group at the top of the permissions list (from r99601)
* [rev:99663] Localized strings in PermissionCheckboxSetField (from r99590)
* [rev:99660] Re-adding support for Group and PermissionRole records in PermissionCheckboxSetField
* [rev:99657] Using localized titles for permission formfields in PermissionRole and Member (from r99583)
* [rev:99656] Using TreeMultiselectField instead of MemberTableField->relationAutoSetting in Group->getCMSFields() (from r99582)
* [rev:99654] Added ComponentSetTest (from r99580)
* [rev:99646] Moved generic .TreeDropdownField styling from cms/css/cms_right.css to sapphire/css/TreeDropdownField.css
* [rev:99646] Fixed .TreeDropdownField styling (borders and margins) in TreeDropdownField.css (was assumed to be inherited from LeftAndMain/CMS stylesheets) (from r98878)
* [rev:99645] Added MemberCsvBulkLoaderTest->testCleartextPasswordsAreHashedWithDefaultAlgo() (from r98841)
* [rev:99644] Allow custom TitleText on TableListField_Item.ss (e.g. to show a description of the 'delete' button) (from r98828)
* [rev:99641] Setting new 'inlineadd' permissions on MemberTableField instance in Group->getCMSFields() (from r98827)
* [rev:99497] add pass thru group and sort methods
* [rev:99492] Fixed SapphireTest->logInWithPermission() spelling
* [rev:99491] Fixed SapphireTest->logInWithPermission() spelling
* [rev:99363] Using DateField in CMSMain->SiteTreeFilterDateField(), as CalendarDateField is now deprecated
* [rev:99362] Moved cms specific styling in CalendarDateField.css to cms/css/cms_right.css
* [rev:99359] Moved cms specific styling in CalendarDateField.css to cms/css/cms_right.css
* [rev:99350] Temporarily disabled nested url specific cases inTranslatableTest->testAlternateGetByLink(), unclear functionality requirements
* [rev:99347] Fixed FilesystemPublisherTest to have self-contained extension settings, and not rely on static publishing being enable in mysite/_config.php already. Fixed login permissions for doPublish() calls in test case.
* [rev:99178] Moved timezone coupling in SS_Report labels into timezoneawareness module
* [rev:99137] Localized reports
* [rev:99130] Fixed merge error (see r99114)
* [rev:99127] Bugfix in previous commit (from r98660)
* [rev:99126] refactored setting/getting strict hierarchy setting. (from r98654)
* [rev:99123] don't load a report by default (from r98561)
* [rev:99122] don't remember what report you had selected in ReportAdmin (from r98560)
* [rev:99121] more unit tests around loose hierarchy (from r98509)
* [rev:99120] added LiveURLSegment to ignored field in change detection (from r98494)
* [rev:99118] fixed two reports with links that did not open in new windows (from r97816)
* [rev:99113] add the ability to link-check the live table too (from r89473) (from r95310)
* [rev:99112] pingStatus ping frequency reduced
* [rev:99112] updated lang file for SiteConfig
* [rev:99112] improved documentation in StaticPublisher
* [rev:99112] improved documentation in CMSMain surrounding reports and siteconfig
* [rev:99112] migrated headers in SiteConfig to i18n'd (from r86429)
* [rev:99111] Localized File->uploadMetadataFields()
* [rev:99110] Documentation
* [rev:99099] ability to customize the text that comes out of Member->Title
* [rev:99099] updated workflow reports (from r96352)
* [rev:99098] Added Requirements for SilverStripeNavigator (see r99080)
* [rev:99097] Added Requirements for SilverStripeNavigator (see r99080)
* [rev:99081] Partially reverted r99079 - SiteTree->getNavigatorItems() was refactored to SilverStripeNavigator::get_for_record()
* [rev:99076] make static caching smarter around cacheSubdirs
* [rev:99068] adjustments to ensure that the cached permissions were actually hit (from r98835)
* [rev:99064] refactored setting/getting strict hierarchy setting. (from r98654)
* [rev:99062] more unit tests around loose hierarchy (from r98509)
* [rev:99059] added enforce_strict_hierarchy option, and tests around not cascading deletions (from r98498)
* [rev:99057] reload the virtual page if you are looking at the current one on save. To prevent overwriting fields (from r98496)
* [rev:99009] force a specific cache subdirectory
* [rev:99008] disable real-time static publishing
* [rev:98980] fix typo
* [rev:98898] Added brackets around strpos() check just to be sure it works
* [rev:98872] Fixed clearing issue in installer that was recently removed
* [rev:98855] Moved ul.tree rules from cms/css/cms_left.css to sapphire/javascript/tree/tree.css (particularly around multiselect tickbox styling) (see r98854)
* [rev:98854] Moved ul.tree rules from cms/css/cms_left.css to sapphire/javascript/tree/tree.css (particularly around multiselect tickbox styling)
* [rev:98800] Removed return of connection and changed variables to conincide with r98795
* [rev:98792] Removed whitespace in textarea value that caused an empty string in the development servers list in installer (regression from recent change)
* [rev:98781] Styling on installer
* [rev:98733] Defensive scripting in LeftAndMain.Tree.js (merged from r98709)
* [rev:98713] Re-enabled CsvBulkloaderTest cases, were disabled by accident (merged from r94250)
* [rev:98679] Reverted broken variables in installer for checking environment
* [rev:98670] Install template cleanup
* [rev:98668] Styling for help text in the installer
* [rev:98667] Styling fixes for installer
* [rev:98666] Tidy up of install template
* [rev:98662] Changed config-form to HTML 4.01 and validated the page minus a few issues with the form field placement
* [rev:98643] disable form fields if they are set from _ss_environment. See #5054
* [rev:98544] Removed useless third argument to instantiation of itemClass in TableListField::generateExportFileData()
* [rev:98538] Fixed caching of login page for tests
* [rev:98519] Renamed manifest test temp dir as there was some kind of conflict
* [rev:98480] Removed double brackets from Diff::cleanHTML()
* [rev:98477] Fix documentation for Diff::cleanHTML
* [rev:98433] Speed up cache test (1s is as good a test expiry as 8s)
* [rev:98427] Fixed SiteTreeBacklinksTest on Windows
* [rev:98409] Fixed HTTPTest->testSetGetVar()
* [rev:98407] Fixed HTTPTest->testSetGetVar()
* [rev:98404] Partially reverted r98382 which added unnecessarily defensive checking to Hierarchy->allChildren()
* [rev:98403] Fixed HierarchyTest assertions around including grand children counts
* [rev:98390] Removed argument to getDescendantIDList() in ThumbnailStripField that doesn't exist on the method
* [rev:98383] Fixed HTTPTest when invoked through dev/tests/all or with GET parameters (see r98373)
* [rev:98376] Testing of grand-children items in HierarchyTest::testLoadDescendantIDListIntoArray() and HierarchyTest::testNumChildren()
* [rev:98372] Documentation
* [rev:98370] Fixed test case name in Hierarchy
* [rev:98369] Added test case for Hierarchy::getDescendantIDList() which also tests Hierarchy::loadDescendantIDListInto()
* [rev:98341] Removed arguments to Hierarchy::getDescendantIDList() calls, as the method does not have any
* [rev:98326] Make pass use a password field, dont require call by reference (merged from r72930)
* [rev:98321] Use 'b' mode for fopen() where possible for better portability
* [rev:98282] fixed setName()
### Other
* [rev:99952] via Image panel, and keep proportions when changing size
* [rev:99952] in text input boxes.
* [rev:99849] Uses $this->extend('augmentValidURLSegment')
* [rev:99849] so that (for instance) Translatable can hook this.
* [rev:99848] Revert "FEATURE: Use tidied HTML in DataDifferencer"
* [rev:99848]
* [rev:99848] This reverts commit a0d2f7b3e289d12dedcdbd02ae52eec3e6718340.
* [rev:99732] BUFGFIX: Prevent selection of self as parent (see #5106)
* [rev:99084] Add missing JS file (from r97410)
* [rev:98873] REVERT: reverse merging the change, it breaks some tests.

View File

@ -0,0 +1,63 @@
# Changelogs
Keep up to date with new releases subscribe to the [SilverStripe Release Announcements](https://groups.google.com/group/silverstripe-announce) group,
or read our [blog posts about releases](http://silverstripe.org/blog/tag/release).
We also keep an overview of [security-related releases](http://silverstripe.org/security-releases/).
For information on how to upgrade to newer versions consult the [upgrading](/installation/upgrading) guide.
## Stable Releases
* [2.4.5](2.4.5) - 2 February 2011
* [2.4.4](2.4.4) - 21 December 2010
* [2.4.3](2.4.3) - 11 November 2010
* [2.4.2](2.4.2) - 22 September 2010
* [2.4.1](2.4.1) - 23 July 2010
* [2.4.0](2.4.0)
* [2.3.11](2.3.11) - 2 February 2011
* [2.3.10](2.3.10) - 21 December 2010
* [2.3.9](2.3.9) - 11 November 2010
* [2.3.8](2.3.8) - 23 July 2010
* [2.3.7](2.3.7) - 18 March 2010
* [2.3.6](2.3.6) - 8 February 2010
* [2.3.5](2.3.5) - 21 January 2010
* [2.3.4](2.3.4) - 27 November 2009
* [2.3.3](2.3.3) - 3 August 2009
* [2.3.2](2.3.2) - 18 June 2009
* [2.3.1](2.3.1) - 19 March 2009
* [2.3.0](2.3.0) - 23 February 2009
* [2.2.4](2.2.4) - 20 March 2009
* [2.2.3](2.2.3) - ~31 October 2008
* [2.2.2](2.2.2) - 22 May 2008
* [2.2.1](2.2.1) - 21 December 2007
* [2.2.0](2.2.0) - 28 November 2007
* [2.1.1](2.1.1) - 2 November 2007
* [2.1.0](2.1.0) - 2 October 2007
* [2.0.2](2.0.2) - 14 July 2007
* [2.0.1](2.0.1) - 17 April 2007
* 2.0.0 - 3 February 2007 (initial release)
## Alpha/beta/release candidate ##
* [2.4.5-rc1](rc/2.4.5-rc1) - 31 January 2011
* [2.4.4-rc2](rc/2.4.4-rc2) - 20 December 2010
* [2.4.4-rc1](rc/2.4.4-rc1) - 10 December 2010
* [2.4.3-rc2](rc/2.4.3-rc2) - 4 November 2010
* [2.4.3-rc1](rc/2.4.3-rc1) - 1 November 2010
* [2.4.2-rc2](rc/2.4.2-rc2) - 20 September 2010
* [2.4.2-rc1](rc/2.4.2-rc1) - 16 September 2010
* [2.4.1-rc2](rc/2.4.1-rc2) - 21 July 2010
* [2.4.1-rc1](rc/2.4.1-rc1) - 16 July 2010
* [2.4.0-rc3](rc/2.4.0-rc3) - 4 May 2010
* [2.4.0-rc2](rc/2.4.0-rc2) - 30 April 2010
* [2.4.0-rc1](rc/2.4.0-rc1) - 1st April 2010
* [2.4.0-beta2](beta/2.4.0-beta2) - 17 March 2010
* [2.4.0-beta1](beta/2.4.0-beta1) - 29 January 2010
* [2.4.0-alpha1](alpha/2.4.0-alpha1) - 11 November 2009
* [2.3.11-rc1](rc/2.3.11-rc1) - 31 January 2011
* [2.3.10-rc2](rc/2.3.10-rc2) - 20 December 2010
* [2.3.10-rc1](rc/2.3.10-rc1) - 10 December 2010
* [2.3.9-rc2](rc/2.3.9-rc2) - 4 November 2010
* [2.3.9-rc1](rc/2.3.9-rc1) - 1 November 2010
* [2.3.8-rc1](rc/2.3.8-rc1) - 16 July 2010

View File

@ -0,0 +1,11 @@
# 2.3.11-rc1 (2011-01-31)
## Overview
* Bugfix: CMSMain->rollback() fails because of CSRF protection
## Changelog
### Bugfixes
* [rev:115919] #6291 Remove rollback action from CMSMain allowed_actions and rely on form action_rollback instead which is safer

View File

@ -0,0 +1,41 @@
# 2.3.8-rc1 (2010-07-16)
## Changelog
### Features and Enhancements
* [rev:108062] Added File::$allowed_extensions (backport from 2.4 to enable File->validate() security fix)
* [rev:103684] Allowing TestRunner? to skip certain tests through the ?SkipTests?=... GET paramete (merged from branches/2.3-nzct) (from r80646)
* [rev:103659] do not show comments that need moderation in the comment rss feed
### API Changes
* [rev:108062] Don't reflect changes in File and Folder property setters on filesystem before write() is called, to ensure that validate() applies in all cases. This fixes a problem where File->setName() would circumvent restrictions in File::$allowed_extensions (fixes #5693)
* [rev:108062] Removed File->resetFilename(), use File->updateFilesystem() to update the filesystem, and File->getRelativePath() to just update the "Filename" property without any filesystem changes (emulating the old $renamePhysicalFile method argument in resetFilename())
* [rev:108062] Removed File->autosetFilename(), please set the "Filename" property via File->getRelativePath()
### Bugfixes
* [rev:108045] Don't allow direct access to PHP files in mysite module. (from r108029)
* [rev:108044] Don't allow direct access to PHP files in cms module. (from r108028)
* [rev:108043] Don't allow direct access to PHP files in sapphire module, except for main.php and static-main.php (from r108023)
### Minor changes
* [rev:108062] Added unit tests to FileTest and FolderTest (some of them copied from FileTest, to test Folder behaviour separately)
* [rev:108046] Partially reverted r108045, mistakenly committed RewriteBase change
* [rev:108040] Added .mergesources.yml
* [rev:103897] Added querystring option to Makefile (from r103884)
* [rev:103895] Added querystring option to Makefile (from r103746)
* [rev:103528] sort page comment table by Created field - show newest entries first
* [rev:103521] Fixed FileTest execution if the assets/ directory doesn't exist. (from r88353) (from r98086)
* [rev:103447] Fixed js applying to non-tinymce textarea fields in ModelAdmin.js (fixes #5453)
* [rev:103362] Fixed js applying to non-tinymce textarea fields in ModelAdmin.js (fixes #5453)
* [rev:103348] added moderation message for non-ajax mode
* [rev:101258] Fixed missing closing `<div>` in ContentController->successfullyinstalled() (from r101254)
{![](_images/./sscreatechangelog --version 2.3.8-rc1 --branch branches/2.3 --stopbranch tags/2.3.7)}

View File

@ -0,0 +1,146 @@
# 2.4.0-rc1 (2010-04-01)
## Changelog
### Features and Enhancements
* [rev:101871] Updated automatic regression tests (Salad)
* [rev:101670] RedirectorPage ExternalURL field now defaults to http:// to be consistent with the "Another website" option for HtmlEditorField LinkForm
* [rev:101661] tidied up installer process to streamline process. Moved requirements to top and button to bottom and added visual seperation of the individual steps
* [rev:101381] refactored requirements section to hide successful tests
* [rev:101378] Added links to installation introduction text for sources of help and suggested web hosts
* [rev:101246] Improved wording and styling in installer. Added links to server requirements, themes download, tutorial. Decreased vertical space before the "install" button to make it more obvious.
* [rev:101127] Added 'Dependent pages' tab to CMS, to show virtuals, redirectors, and backlinks that point to this page.
### API Changes
* [rev:102012] Changed MySQLFulltextSearchable class to FulltextSearchable (applies to all databases)
* [rev:102003] Disallow methods/actions in RequestHandler->checkAccessAction() which are implemented on parent classes (e.g. ViewableData and Object), unless access is controlled through $allowed_actions. This limits information exposure from getters used in template contexts.
* [rev:101833] Allow cached blocks within control and if blocks, as long as that control or if block is contained within an uncached block, not a cached block
* [rev:101155] Add option for DataObjectDecorator::onAfterSkippedWrite()
* [rev:101137] Partial cache adjustments - now supports nested cache blocks (which are independant of their containing cache block), conditionals to control if a given cache block is active, and includes hash of template code in key (so template changes mean cache is invalidated). Changes template control for cache block to `<% cached %>`, to which the now deprecated `<% cacheblock %>` is aliased, and an additional template control `<% uncached %>` has been added.
* [rev:101127] Added SiteTree::VirtualPages() and SiteTree::DependentPages() accessors.
### Bugfixes
* [rev:102038] #5255 LeftAndMain should include the correct editor.css file so typography from user selected theme in SiteConfig is shown in TinyMCE
* [rev:102026] Fixed SiteTree::page_type_classes() removal of base class (was broken if database driver returned classes in arbitrary order, e.g. in Postgres)
* [rev:102004] Prevent handling of controller actions which return $this avoid infinite loops in RequestHandler->handleRequest (thanks Hamish!)
* [rev:101975] Resetting image sidepanel fields when opening the panel instead of inserting an image, to avoid losing focus of TinyMCE in IE. Using getBookmark() in TinyMCE to save the original location. (fixes #5263)
* [rev:101969] Stop IE6/IE7 from redirecting in admin/assets after deleting multiple folders (fixes #5208)
* [rev:101958] Checking for existing redirections in FormResponse::respond (fixes #5208)
* [rev:101956] Fixed "object not found" javascript error in SecurityAdmin_right.js when changing group nodes (fixes #5179)
* [rev:101939] Ensure that DataObject IDs are numbers and no string equivalents of numbers - 3 not '3'
* [rev:101869] Update Salad tests to match behaviour
* [rev:101867] #4188 simon_w: Let require tags in templates be conditional
* [rev:101866] Recover if a manifestClassParse file doesn't have the necessary content.
* [rev:101812] Added allowed_actions to ContentControllerSearchExtension
* [rev:101810] #5295: Update CMS site name in LHS via Ajax after siteconfig save.
* [rev:101807] fixed undefined error in CTFs. BUGFIX: added action class to actions to allow the popup hook to open links
* [rev:101795] keep ModelAdmin from importing data twice
* [rev:101794] avoid call to non-object
* [rev:101793] preserve the port value if given in HTTP::setGetVar (#5280). BUGFIX: allow username only input rather than user:pass combo.
* [rev:101792] disable function re-enabled
* [rev:101791] deprecated split function replaced
* [rev:101758] fix #5320
* [rev:101747] Always including "Locale" field in Translatable->getCMSFields() regardless of "excluded" page types. Necessary to enable form state serialization for fields like TreeSelectorField on a VirtualPage (fixes #5269)
* [rev:101739] Versioned->publish() with $createNewVersion=TRUE now increases version number of in-memory object (fixes #5261)
* [rev:101737] RedirectorPage types shouldn't appear in "Pages with no content" side report in the CMS Pages tab
* [rev:101724] #5277 Sort of default SiteTree records is now explicitly set to avoid strange ordering set by SiteTree::onBeforeWrite for default records
* [rev:101719] Only show "Roles" tab in admin/security if user has APPLY_ROLES permissions (fixes #5258)
* [rev:101711] Don't replace "home/" URLSegment in SiteTree->RelativeLink() if Translatable is enabled and the homepage is not on the root level (nested URLs allows you to have homepages called "en/home" and "ru/home") (fixes #5244)
* [rev:101668] #5259 RedirectorPage and HtmlEditorField TinyMCE integration now prefixes http:// if no prefix is found
* [rev:101657] #5245 Sometimes page records will have a NULL ParentID value, it should be a number even if it's 0 (thanks wrossiter!)
* [rev:101638] #5243 Undefined Convert functions in ViewableData replaced with working versions. Thanks benediktb!
* [rev:101631] test that the class exists before running subclass tests
* [rev:101623] put back into the SSNavigator the archived site link (#5251)
* [rev:101608] Explicitly specify the many_many's join table name in the join's ON match statement in ManyManyComplexTableField
* [rev:101604] remove the unnecessary DOM manipulation, this is legacy code due to SilverStripeNavigator changes (open #5250)
* [rev:101603] the function makes an assumption we are working on Draft site, and breaks if we are not. Rewritten to be stage-independent, as get_version (open #5231)
* [rev:101602] IE does not accept TD element without a table, repacking into DIV (open #5228)
* [rev:101592] get a object inside transaction block will alway exist
* [rev:101554] tables and column quoted properly
* [rev:101493] tables and column quoted properly
* [rev:101492] results sorted alphabetically for consistency
* [rev:101491] results sorted alphabetically for consistency
* [rev:101392] HTTP::setGetVar() returns a relative URL if a relative URL is passed, to make behaviour closer to 2.3
* [rev:101380] disabling unused file list as feature is still buggy.
* [rev:101375] Fixed closing `</div>` which should have been a `</td>` for dragfile in AssetTableField
* [rev:101302] Fixed SiteTree->Content link shortcode parsing introduced in r101093 (#5227)
* [rev:101267] #5222 Fixed TreeDropdownField not working on FileIFrameField/ImageField
* [rev:101266] Fixed Folder writing by overloading validate() (was inheriting File->validate() which does extension checks)
* [rev:101266] Fixed Folder::findOrMake() not to create "new-folder" through File->setName() if using a trailing slash in the path (which causes an empty name). Added FolderTest to verify this.
* [rev:101264] Checking for existence of "ShowInMenus" property in Folder->liveChildren() and stageChildren() (#5190)
* [rev:101227] Don't delete index.php after successful installation - in ContentController->deleteinstallfiles(). URL routing might rely on it without mod_rewrite.
* [rev:101227] Require ADMIN permissions for ContentController->deleteinstallfiles() - together with retaining index.php this removed a vulnerability where unauthenticated users can disrupt mod_rewrite-less URL routing.
* [rev:101220] TeamComment table added to dataobjects list
* [rev:101189] Make SS_ReportWrapper::sourceRecords()' arguments optional
* [rev:101175] Fixed quotes around Folder::hasChildFolders() ParentID column
* [rev:101173] Don't run click() on all inputs, but input:radio only
* [rev:101171] Pass correct class to allowPrimaryKeyEditing in yaml fixture
* [rev:101170] Don't recreate a missing draft page when calling SiteTree::doUnpublish()
* [rev:101167] #5216 Installer has issues with click handlers applied to the entire li, be more specific and apply it to the label and input instead
* [rev:101165] Fixed versioning of pages
* [rev:101155] Prevent failed migrateVersion writes from breaking versioning system in future writes.
* [rev:101155] MAke site tree pages go green when you save a new draft.
* [rev:101154] #5214 ViewableData::obj() was creating a DBField without a fieldname argument and caused problems, one example is the version panel of the CMS
* [rev:101153] Ensure that Versioned works on classes with underscores in the names. (from r100905)
* [rev:101138] Fixed issues with broekn link tracking
* [rev:101131] Allow classes to be referred to with casing that differs from their definition.
* [rev:101129] Fixed FileLinkTrackingTest to cope with the empty alt="" and title="" attributes that are created
* [rev:101127] Improved reliabilty of broken link tracking.
* [rev:101127] Don't mark a page as changed on stage if the only thing that has changed is broken link metadata
### Minor changes
* [rev:102045] Fixed spelling mistake in ConfigureFromEnv class documentation
* [rev:102018] Fixed VersionedTest arguments in test case
* [rev:102010] Fixed regression from r101752 (adding permission roles button was missing)
* [rev:102009] Fixed indentation
* [rev:101974] Saving TinyMCE editor focus in tinymce_ssbuttons plugin when sidepanel is opened (see #5263)
* [rev:101971] Fixed indentation
* [rev:101970] Fix tests to cope with ID type cleanup changed recently
* [rev:101889] removed duplication of variable and conditional that would never pass
* [rev:101883] take advantage of an alternate path for error pages
* [rev:101882] TreeTitle really should return title, not name.
* [rev:101870] Make Salad accept "login" or "log in"
* [rev:101868] Added missing file for r101867
* [rev:101811] Fixed JSONDataFormatter excaping (fixes #5309, thanks briley)
* [rev:101782] Marked DataObject::has_own_table() as static
* [rev:101754] Removed unnecessary console.*() from cms javascript files
* [rev:101753] Removed unnecessary console.*() from sapphire javascript files
* [rev:101752] Removed unnecessary "show" icons in "Roles" and "Member" ComplexTableFields
* [rev:101751] Removed unnecessary "show" icons in "Roles" and "Member" ComplexTableFields
* [rev:101729] use red font instead of gray when displaying error
* [rev:101723] Fixed getElementsByClassName() usage in AssetTableField.js (fixes #5256)
* [rev:101718] Fixed tab naming in Group->getCMSFields()
* [rev:101698] Respecting folder sort order in admin/assets by adding Folder::$default_sort="Sort" (#5235)
* [rev:101688] Removed fullstop where it wasn't needed
* [rev:101687] Tidied up the layout of the Themes area of the installer slightly - now consistent helptext as other areas
* [rev:101686] Updated CMS Admin Account text to be more precise
* [rev:101683] Altered wording in installer for localised interface
* [rev:101671] Reverted r101670 as it broke assumptions made in RedirectorPageTest
* [rev:101638] Updated ViewableDataTest to verify ViewableData changes
* [rev:101619] Made the default database directory relative to assets ".db" which is more precise than ".sqlitedb"
* [rev:101618] Made SQLite path in installer use DIRECTORY_SEPARATOR so it shows as correct on Windows using backslashes instead of forwardslashes - this is more of a cosmetic thing, as slashes can be interchanged and still parsed correctly by PHP
* [rev:101600] fixed notice level error
* [rev:101353] Removed rewritest.php places in sapphire since it's no longer part of the phpinstaller/branches/2.4 package
* [rev:101341] Made reinstall message more precise by adding web.config to the files that will get overwritten
* [rev:101282] Moved "theme" section further down in the installer, its much less likely to be changed than the database connection and admin account fields.
* [rev:101254] Fixed missing closing `<div>` in ContentController->successfullyinstalled()
* [rev:101251] Fixed regression in install.js option selection (see r101173)
* [rev:101172] Fix output format of buildbot test runs to not include colour control codes.
* [rev:101166] versioning test for SiteTree
* [rev:101135] Fixed multifile.js non-standard forEach() reference, using jQuery.each() instead
* [rev:101134] Localized "dependent pages" features in SiteTree->getCMSFields()
* [rev:101132] Fixed test that was relying on bug fixed in r101116
### Other
* [rev:101314] ENHNACEMENT Installer no longer asks for firstname and surname for default CMS admin account, this can be changed later on and doesn't need to be entered for installation
{![](_images/./sscreatechangelog --version 2.4.0-rc1 --branch branches/2.4 --stoprevision 101127)}

View File

@ -0,0 +1,127 @@
# 2.4.0-rc2 (2010-04-30)
## Overview
* Improved permission handling in the "Security" section: "Access to all CMS sections" not automatically checks all inherited permissions
* Fixed usage of file, image and link selection in the CMS with multilingual sites (Translatable)
* Fixed core unit tests for PostgreSQL
* Fixed a core bug in PostgreSQL concerning the ordering and grouping of DataObjectSet results
* Allowing the new "SiteConfig" interface to save TinyMCE content, enabling easier usage of default content which doesn't belong to a single page
* Updated api.silverstripe.org to accurately reflect the current API in different releases, with a nightly rebuild to keep it that way
## Changelog
### Features and Enhancements
* [rev:103730] use FileSystem class to create cache directory to unsure the right permissions are set
* [rev:103710] MemberLoginForm::performLogin() now uses the authenticator_class variable set in subclasses of MemberLoginForm, without having to overload performLogin()
* [rev:103708] create cache directory when it does not exist before running the cache build test
* [rev:103581] Added i18n::set_default_locale() to set standard locale (which is different from "current locale" retrieved through i18n::get_locale())
* [rev:103466] make the getTree ajax call more generic so it get local from its containing form, rather than hard-coded "Form_EditForm_Locale" cos the field is not only used in "EditForm"
* [rev:103465] to make the FileIFrameField and TreeSelectionField easy to use in CMS with Translatable on.
* [rev:103328] Automatically checking all "CMS section" checkboxes in PermissionCheckboxSetField.js when "Access to all CMS interfaces" is selected. Saving these permissions individually also resolves certain edge cases like #5438.
* [rev:103250] added tests for checking the change password functionality, including the resulting redirection (from #5420)
* [rev:103229] allow ChangePasswordForm to redirect to BackURL (from #5420)
* [rev:103198] allow onAfterPublish and onBeforePublish handlers directly on Page classes (#5112)
* [rev:103047] allow to check for any changed fields on the DataObject, this is expected behaviour when isChanged function is called without parameters (#5421, patch by walec51)
* [rev:102899] added language (Ticket #5390)
### API Changes
* [rev:103792] changed the modulus offset to 1 to correctly order sets
### Bugfixes
* [rev:103803] Rebuilding test database for postgresql in SearchFormTest and TranslatableSearchFormTest to avoid stale index information in the database
* [rev:103745] static publisher for a site that resides in a subfolder of webroot
* [rev:103734] Fix linkCount .js in AssetAdmin deleteRecord (ticket #5486)
* [rev:103706] Use correct quoting for BrokenLinksReport (ticket #5474)
* [rev:103674] #5485 PermissionCheckboxSetField javascript would always uncheck all CMS_ACCESS_* permission checkboxes on initialize event
* [rev:103620] Fixed ordering by aggregate columns for DataObject::get() calls with joins.
* [rev:103613] Fixed unlimitedRowCount() for grouped queries
* [rev:103612] Ensure that group by of many-many queries with extraFields is set correctly.
* [rev:103591] ModelAsController test failed for projects which do not support nested urls. This fix stores the original configuration and enables 'nested-urls' at the beginning of the tests and reset the state in tearDown.
* [rev:103588] #5362: Fixed duplicate removal on DataObject:get() with join argument for all databases.
* [rev:103582] Choosing i18n::default_locale() in Member->populateDefaults() instead of "current locale". This fixes a bug where a new member created through admin/security automatically "inherits" the current locale settings of the admin creating it.
* [rev:103552] CSSContentParser now reports better errors by using simplexml_load_string() instead of SimpleXMLElement directly
* [rev:103519] Prevent duplicate HTML IDs in ModelAdmin
* [rev:103518] Fixed redirection in PageCommentInterface to use Link() instead of URLSegment (fixes 4200, thanks ktauber)
* [rev:103461] Renamed Nested URLs are automatically redirected to their new location with 301 HTTP status code in ModelAsController/ContentController (fixes #5393, thanks cbarberis)
* [rev:103451] Fixed CurrencyField->jsValidation() regex escaping (fixes #5462, thanks mobiusnz)
* [rev:103450] DateField with setConfig('dmyfields') now validates TRUE for empty values (fixes #5458)
* [rev:103448] Allow EDIT_SITECONFIG permission selection in admin/security (fixes #5459)
* [rev:103341] Don't show error when adding default SiteConfig records after upgrading a site.
* [rev:103336] Using try/catch in MemberTableField->saveComplexTableField() similiar to parent implementation, which means trying to save a Member duplicate doesn't end up in a fatal error (fixes #5444)
* [rev:103255] static publishing now uses the last non-null theme, OR the value defined in StaticPublisher::static_publisher_theme.
* [rev:103240] r101093 broke casting of values from the failover object. Add lookup to the failover for casting info, and add test
* [rev:103226] made the invalid password message translatable; disallow new blank password (as it makes it impossible to login); Member::checkPassword now returns ValidationResult - handle that properly (#5420, patch submitted by walec51)
* [rev:103214] the decorator was not completely removed, which caused trouble for tests running later in the same batch
* [rev:103183] default sort column now quoted
* [rev:103182] default sort column now quoted
* [rev:103127] realtime publishing now enabled by default
* [rev:103099] Only replace double slashes in SS_HTTPRequest->__construct() for relative- its a failsafe against wrongly formatted URLs like 'admin//assets' instead of 'admin/assets', but breaks absolute URLs with 'http://' prefix
* [rev:103092] disallow numeric actions - numeric array indexes are incorrectly picked up as allowed actions (#5331)
* [rev:103083] make the javascript-producing functions behave in the same way. Now they will return a javascript snippet and the caller is responsible for adding it to a FormResponse. Removes the duplication in AJAX response which happened when FormResponse::add has been used before the call to JS helper functions (#5359)
* [rev:103037] correct mollom field mapping
* [rev:103012] added optional separator for http_build_query in HTTP:setGetVar(). this fixes sorting columns in ModelAdmin (ticket #5325).
* [rev:102730] Fixing RquestHandler->checkAccessAction() on PHP 5.2 - ReflectionMethod->class returns inconsisent results in older PHP versions. (see r102003)
* [rev:102712] Fixed CTF sorting in ModelAdmin results (was failing because of missing 'ResultAssembly' GET parameters
* [rev:102686] Float should always be not null and default 0 in the database
* [rev:102545] Using i18n::get_locale() in ContentController->ContentLocale() to ensure the correct locale can be used in templates withouth Translatable enabled (broken in r97207, thanks DesignCity) (from r102544)
* [rev:102460] #5316 Float and Double should never try to save NULL as the "null" value
* [rev:102436] #5320 ManyManyComplexTableField::getQuery() now uses T-SQL compatible syntax CASE WHEN instead of IF THEN which works in multiple databases as well
* [rev:102386] delete from published site never calls canDeleteFromLive(). (via marcus #5364)
* [rev:102320] fixed invalid HTML output from page comments template
* [rev:102300] SSViewer now allows cli to do a flush on non-dev environments
* [rev:102265] Fix Salad tests
* [rev:102237] exchanged MySQL CONCAT function with ANSI compliant operator
* [rev:102160] allow HTMLEditorFields to save in SiteConfig, fixes #5246
* [rev:102156] fallback to the standard authenticator before throwing user_error as in some cases auth method is not passed back to the login form
* [rev:102094] Fixed bug with SiteTree::onBeforeWrite() that broke subsites.
* [rev:102084] #5343: Call DataObject::onBeforeWrite only once for SiteTree
* [rev:102081] #5337: Allow decoration of DataObject
* [rev:102074] Fixed SiteTree::page_type_classes() to exclude 'SiteTree' even if on array position 0 - slight difference in return values from Postgres to MySQL (fixes #5336)
* [rev:102072] Logging in with an invalid email returns no error message (fixes #5332, thanks ajshort)
### Minor changes
* [rev:103821] Fixed TranslatableSearchFormTest for postgresql (strict type assertions)
* [rev:103819] Fixed TranslatableTest for postgresql database driver (mostly ordering issues)
* [rev:103818] Fixed CMSMainTest for postgres by not hardcoding fixture IDs
* [rev:103799] Removed mysql specific functionality from DataObjectSchemaGenerationTest and moved it to a new MySQLDatabaseTest
* [rev:103798] Fixed TranslatableTest for postgresql database driver (mostly ordering issues)
* [rev:103787] update unit test for checking whether a DataObject has been changed or not without providing a field name
* [rev:103763] Unsetting state in FilesystemPublisherTest (regression from r103745)
* [rev:103744] Allowing querystring arguments in sapphire/Makefile
* [rev:103692] Restored docblock of SQLQuery::unlimitedRowCount()
* [rev:103640] Fixed AggregateTest for MSSQLDatabase (wrong date formatting)
* [rev:103606] recache tables if cache is empty
* [rev:103558] sort page comment table by Created field - show newest entries first
* [rev:103555] added moderation message for non-ajax mode
* [rev:103533] Fix to ModelAdmin, part of r103519
* [rev:103520] add more in-line documentation and fix the typo: should => should not
* [rev:103515] Database quoting in TreeDropdownField (fixes #5484)
* [rev:103485] Documentation
* [rev:103398] Fixed phpdoc documentation
* [rev:103397] Fixed phpdoc documentation
* [rev:103391] Fixed phpdoc documentation (from r103390)
* [rev:103388] Fixed phpdoc documentation (from r103385)
* [rev:103386] Fixed phpdoc documentation (from r103384)
* [rev:103345] Reverted accidental commit of date_default_timezone_set() to Pacific/Auckland (see r89164)
* [rev:103337] Returning ValidationResult from Member->onBeforeWrite() to ensure the ValidationException is compatible with MemberTableField (related to r103336)
* [rev:103322] Enum DBField class should default to ExactMatchFilter to avoid wrong results with overlapping Enum values in LIKE queries (see #5434)
* [rev:103226] typo
* [rev:103093] fixed the error message on class conflict (#5439, patch submitted by rorschach)
* [rev:102909] Using canView() instead of deprecated can('view') in ContentController
* [rev:102901] reverted wrong change
* [rev:102518] Fixed undefined variable in SiteTree::can_edit_multiple() (broken in r83442) (from r102516)
* [rev:102149] Fixed phpDoc @package and @subpackage for MySQLDatabaseConfigurationHelper
* [rev:102077] added abstract datetime helper functions
* [rev:102071] Removed unnecessary sapphire/thirdparty/.gitignore, as the directory doesnt contain svn:externals any longer (fixes #5334)
* [rev:102045] Fixed spelling mistake in ConfigureFromEnv class documentation
{![](_images/./sscreatechangelog --version 2.4.0-rc2 --branch branches/2.4 --stoprevision 102039)}

View File

@ -0,0 +1,27 @@
# 2.4.0-rc3 (2010-05-04)
## Overview
* Bugfix release for a minor MySQL 4 bug as well as some static publishing quirks
## Changelog
### Bugfixes
* [rev:103961] Bypass static caching through static-main.php when GET or POST parameters are set (regression from 2.3 API, fixes #5519, thanks ktauber)
* [rev:103960] Fixed publication of homepage with '/' URL through StaticPublisher (fixes #5514, thanks ktauber)
* [rev:103957] Fixed Database->requireTable() for Mysql 4.1 (fixes #5517, thanks gw0)
* [rev:103936] Fixed double pragma after referer redirection on forms with Form->httpSubmission() (fixes #5509, thanks ktauber)
* [rev:103933] login BackURL wrong when using nested urls (fixes #5520, thanks ktauber)
* [rev:103932] Fixed SS_Report::unregister() parameter naming (fixes #5511, thanks ktauber)
* [rev:103912] Trimming expected output of WebserverRoutingTest (newlines before the "ok" string were causing failures on PHP 5.3)
* [rev:103910] Disabled MemoryLimitTest for environments where memory_limit can't be freely set (e.g. PHP with suhosin patch)
* [rev:103851] table and column names now quoted properly
### Minor changes
* [rev:103975] Removed unnecessary $timeformat parameter from TimeField::__construct, and getting the default from Zend_Locale_Format in the same way that DateField behaves (unreleased API, so no api change).
* [rev:103975] Automatically choosing $locale in TimeField::__construct, to be consistent with DateField
{![](_images/./sscreatechangelog --version 2.4.0-rc2 --branch branches/2.4 --stoprevision 103839)}

View File

@ -0,0 +1,328 @@
# 2.4.1-rc1 (2010-07-16)
## Overview
* Fixed a security issue where logged-in CMS authors were allowed to rename files with harmful extensions in the "Files & Images" section
* Improved installer security by disallowing re-installation when a configuration file is already present.
* Installing in "live mode" instead of "dev mode" by default, and avoid setting certain domains as "dev mode" by default. This fixes an issue where attackers were able to force a site into "dev mode" by spoofing the domain name on certain server configurations.
* Fixed password encryption when saving members through the "Add Member" dialog in the "Security" admin. The saving process was disregarding password encyrption and saving them as plaintext (issue was introduced in 2.4.0)
* Fixed potential information disclosure on misconfigured servers by disallowing direct execution of *.php files in "sapphire", "cms" and "mysite" folders. If PHP was configured to show errors on screen (development setting), attackers could find out server paths and other environment information.
* Allow CMS authors to set their own localized date and time formats, independently from the defaults set through their interface language.
* More useable date picker (jQuery UI) for date form fields (both in the CMS and in website forms)
* Better URL "transliteration" of special characters like Umlauts or Macrons (Example title: "Brötchen für alle!", URL in 2.4.0: "brtchen-fr-alle", URL in 2.4.1: "broetchen-fuer-alle")
* Better batch editing of comments in the admin interface (e.g. marking multiple comments as "spam")
* More sophisticated access control for decorators on page types (tri-state permissions checks: allow, deny, ignore).
## Changelog
### Features and Enhancements
* [rev:108024] Show a warning inside the the CMS if you've neglected to delete install.php
* [rev:108012] added getter to get array back out of an ArrayData instance. MINOR: updated docblocks in ArrayData
* [rev:107877] Added Latvian (Latvia) translation to sapphire (thanks Kristaps and Andris!)
* [rev:107875] Added Latvian (Latvia) translation to cms (thanks Kristaps and Andris!)
* [rev:107867] Allowing custom messages and permission codes in BasicAuth::protect_entire_site()
* [rev:107867] Making $permissionCode argument optional for BasicAuth::requireLogin(). If not set the logic only checks for a valid account (but no group memberships)
* [rev:107867] Using SS_HTTPResponse_Exception instead of header()/die() in BasicAuth::requireLogin() to make it more testable
* [rev:107810] Added class to time icon in TimeField so it can be styled
* [rev:107443] html2raw now properly replace strong tag with asterix #5494
* [rev:107438] Using jQuery UI datepicker in DateField and DatetimeField instead of outdated DHTML calendar.js (fixes #5397)
* [rev:107438] Abstracted optional DateField->setConfig('showcalendar') logic to DateField_View_JQuery
* [rev:107434] allow adding a new a field to ArrayData
* [rev:107429] Added documentation and changed static names
* [rev:107426] Added static to set regeneration of default pages (ticket #5633)
* [rev:107415] Added Security::$force_database_is_ready to mock database_is_ready() state
* [rev:107415] Added permission check exception in TaskRunner and DatabaseAdmin if SapphireTest::is_running_test() returns TRUE (necessary for DevelopmentAdminTest)
* [rev:107380] Use array_combine() instead of custom logic for ArrayLib::valuekey() (thanks paradigmincarnate!)
* [rev:107365] Member_DatetimeOptionsetField toggle text is now translatable
* [rev:107334] #5352 Translatable entities for help text in Member_DatetimeOptionsetField::getFormattingHelpText()
* [rev:107327] #5352 CMS now uses the user's preferred date and time formatting in DateField and TimeField
* [rev:107326] #5352 Decouple date display from i18n locales, users now have access to change their date and time formats in Member::getCMSFields() using Member_DatetimeOptionsetField field
* [rev:107094] abstracted protocol detection out to Director::protocol() #5450
* [rev:107091] in referencing a file in combine_files() it should fall back to standard requirement tags if combining has been disabled eg dev mode
* [rev:107088] throw user error when not passing correctly formatted array rather than simply passing
* [rev:107086] added setDisabled() to set DropdownField::$disabled
* [rev:106877] Added TestRunner::$coverage_filter_dirs to exclude certain directories from PHPUnit test coverage reports
* [rev:106705] Calling Image->deleteFormattedImages() in Image->onBeforeWrite() (#5423)
* [rev:106200] added prefix and suffix support to ContextSummary
* [rev:106194] Prevent image search queries all images in the site initially when the page is loaded
* [rev:106178] Enable switch between legacy image search and new version
* [rev:106118] added setRows() and setColumns() to customize the size of the textarea field outside of the controller
* [rev:105890] Added method for $this->request->latestParam() backwards compatibility with Director::urlParam()
* [rev:105732] Ability to hide form by className or for the whole ModelAdmin
* [rev:105712] Added MySQLDatabaseConfigurationHelper::getDatabaseVersion() which abstracts the version number away from the version check the installer requires
* [rev:105275] Preserve sort options in pagination links in TableListField
* [rev:105271] 'Select all' and 'Select none' checkboxes for CommentTableField for easier batch handling of comments, improved its styling in CommentAdmin
* [rev:105269] Showing 20 comments in tabular view for CommentAdmin (and making the setting configurable via CommentAdmin::set_comments_per_page())
* [rev:105268] Abbreviating comment text display in CommentAdmin to first 150 characters
* [rev:105266] Allowing batch checkbox selection of TableListField rows with TableListField->Markable and TableListField->addSelectOptions()
* [rev:105126] Added CSSContentParser->getByXpath()
* [rev:105028] Added variable for the server configuration file so the config-form can display it for the installation
* [rev:104968] Added PageComment->canView()/canEdit()/canDelete(), and using these permissions in PageCommentInterface. Caution: canCreate() actions are still determined by PageCommentInterface::$comments_require_login/$comments_require_permission
* [rev:104935] added Month function for consistency
* [rev:104827] added plugins to i18n to support modules that provide custom translations.
* [rev:104707] Installer now supports requireDatabaseVersion() on each database configuration helper implementation, e.g. MySQLDatabaseConfigurationHelper. If it's not defined, the test is skipped.
* [rev:104706] Added MySQLDatabaseConfigurationHelper::requireDatabaseVersion() to check whether the connected instance is using version 5.0+
* [rev:104671] Macrons, umlauts, etc, are now transliterated when inserted into URLS. API CHANGE: Added Transliterator class, which uses iconv() or strtr() to convert characters with diacritical marks to their ASCII equivalents. API CHANGE: Added Extension hook updateURLSegment for SiteeTree.
* [rev:104515] initial commit
* [rev:104232] Add 'Given I load the fixture file "app/tests/xyz.yml"' step to salad
* [rev:104231] Add dev/tests/sessionloadyml to load a yml fixture into an existing test session
* [rev:104162] Added cs_CZ javascript translations (#5540, thanks Pike)
### API Changes
* [rev:107439] Using FieldHolder() instead of Field() for subfields in DatetimeField->FieldHolder(), in order to get configuraton settings for javascript DateField
* [rev:107273] Don't reflect changes in File and Folder property setters on filesystem before write() is called, to ensure that validate() applies in all cases. This fixes a problem where File->setName() would circumvent restrictions in File::$allowed_extensions (fixes #5693)
* [rev:107273] Removed File->resetFilename(), use File->updateFilesystem() to update the filesystem, and File->getRelativePath() to just update the "Filename" property without any filesystem changes (emulating the old $renamePhysicalFile method argument in resetFilename())
* [rev:107273] Removed File->autosetFilename(), please set the "Filename" property via File->getRelativePath()
* [rev:107268] Deprecated File->getLinkedURL()
* [rev:107054] Deprecated AutocompleteTextField, use third-party solutions
* [rev:106217] moved Group::addToGroupByName to $member->addToGroupByCode.
* [rev:105756] refactored methods in session to use coding conventions
* [rev:104987] Removed ImageEditor functionality, please use thirdparty modules, e.g. "silverstripe-pixlr" (http://github.com/nyeholt/silverstripe-pixlr)
* [rev:104923] Added interface method DatabaseConfigurationHelper::requireDatabaseVersion(), all database helpers that implement DatabaseConfigurationHelper must now have this method, which as of now is MySQL, PostgreSQL, SQL Server and SQLite
* [rev:104673] Added RsyncMultiHostPublisher::set_excluded_folders().
* [rev:104669] Moved site tree permission extension to a 3-state system (true, false, null, where null means "no effect")
### Bugfixes
* [rev:108032] Fixed CLI installation.
* [rev:108031] Don't set any dev servers by default, host-based dev-server selection is unreliable.
* [rev:108030] Don't allow reinstalling without first making the user manually delete mysite/_config.php
* [rev:108029] Don't allow direct access to PHP files in mysite module.
* [rev:108028] Don't allow direct access to PHP files in cms module.
* [rev:108027] Don't have any host-based dev servers set by default.
* [rev:108026] Don't allow reinstalling without first making the user manually delete mysite/_config.php
* [rev:108023] Don't allow direct access to PHP files in sapphire module, except for main.php and static-main.php
* [rev:108001] #5833 Duplicate IDs when two similar date formats in Member_DatetimeOptionsetField containing different delimiters (e.g / and .) replaced to an empty string
* [rev:107940] tests now pass when the locale is set to something other than 'en_US' in the mysite's _config.php file
* [rev:107831] dev/build always reporting index change because of a whitespace in the index column names
* [rev:107812] Styling fixes for DateField/TimeField/DatetimeField in the CMS
* [rev:107811] Added a clearing div after the date and time fields, not the best way of doing it but the only way as the overflow css trick for clearing fields doesn't work with the time dropdown
* [rev:107789] Fixed DateField->validate() with keyed, but empty array values
* [rev:107786] Using actual date format settings in DateField/TimeField->validate() messages
* [rev:107785] Limit 'showcalendar' javascript option to DateField instances (rather than applying to all available)
* [rev:107585] fixed inclusion of environment file when document root is the web root
* [rev:107539] Case insensitive extension checks in File::validate() (fixes #5781, thanks simon_w)
* [rev:107537] Remove dummy entry created by Versioned if record is first written to Live stage (fixes #5596, thanks muzdowski)
* [rev:107532] Fixed Member->PasswordEncryption defaults when writing new Member without setting a password. Fixes critical issue with MemberTableField saving in admin/security, where new members are stored with a cleartext password by default instead of using the default SHA1 (see #5772)
* [rev:107441] Allowing DatetimeField->saveInto() to save a partial array notation with missing 'time' value
* [rev:107428] Added quotes for postgres
* [rev:107423] Only highlight strings more than 2 characters long. #4949
* [rev:107417] Reverted 107414, wrong patch
* [rev:107415] Allowing dev/build in "live" mode when Security::database_is_ready() returns FALSE (typically happens when an existing SilverStripe project is upgraded and database columns in Member/Permission/Group have been added) (fixes #4957)
* [rev:107414] TableListField headings i18n translation (ticket #5742)
* [rev:107390] Added Locale hidden field to HTMLEditorField->LinkForm() in order to show correct context in "page on the site" dropdown (fixes #5743)
* [rev:107369] Fixed spelling error of $databaseConfig in cli-script.php causing database configuration to not load (thanks aimcom!)
* [rev:107116] Undo commit to wrong place
* [rev:107115] Undo incorrect commit
* [rev:107095] check the $removeAll var before removing cache files. PATCH via ajshort (#5672)
* [rev:107090] prevented HTTPRequest->shift() throwing notices when shifting multiple elements. APICHANGE: SS_HTTPRequest->shift($multiple) no longer returns an array of size $multiple spaced with nulls, it returns an array up to the size of $multiple.
* [rev:107089] fixed notice level errors getting through
* [rev:106867] Making status description in Debug::friendlyError() compatible to HTTP 1.1 spec (removing any markup and newlines)
* [rev:106777] Re-enabling theme in ErrorPage->doPublish() (it's usually disabled in the publication context through LeftAndMain->init())
* [rev:106755] Stricter checking that a relation exists on ComplexTableField::saveComplexTableField()
* [rev:106671] Fixed ImageField->EditFileForm() to list subclasses of Image in tree dropdown (fixes #5708, thanks keeny)
* [rev:106666] Prevent DateField->performReadonlyTransformation() from segfaulting on PHP 5.2 due to broken __toString() casting (fixes #5713, thanks charden)
* [rev:106360] re-enable broken link notification using BackLinkTracking() (this was broken since r101127
* [rev:106351] Apply AJShort's patch to fix SiteConfig (trac 5671)
* [rev:106225] Checking for the same combined filename in Requirements::combine_files() to avoid irrelevant error messages
* [rev:106205] updated tests for Text
* [rev:106183] fix query error when image search doesn't use legacy search
* [rev:106154] if running in cli do not output html tags when rebuilding the db
* [rev:106122] Fixed caching of homepage.
* [rev:106121] Open help in a new tab.
* [rev:106120] Replaced Versioned's unique index definition with an array syntax.
* [rev:106096] Setting 'ID' field on CMSMain->RootForm() so it can work with formfields that require it (fixes #5671, thanks ajshort)
* [rev:106086] image search was not honouring the selected folder, so could only search in root folder
* [rev:106082] Fixed SiteTree::IsModifiedOnStage() for an edge-case that was identified when deleteFromStage() stopped manipulating the current record.
* [rev:106080] Don't let deleteFromStage() kill the ID of the original record.
* [rev:106079] Add a unique index to SiteTree_versions.RecordID+Version. Fix saving methods to support this.
* [rev:106078] Throw an exception if you try an delete an unsaved or already-deleted record
* [rev:106071] MySQLDatabaseConfigurationHelper::getVersion() will fallback to trying to get the version using a query if mysql_get_server_info() returns nothing
* [rev:105907] fixed phpunit directive
* [rev:105903] reverted revision 105890 to fix build
* [rev:105889] invalid use of @covers annotation
* [rev:105876] TableListField_Item::SelectOptionClasses() can not use it parent protected variable.
* [rev:105875] rollback r105858 which introducesa bug
* [rev:105872] updated select options classes to work with the dataobjectset returned by selectoptions rather than the array previously
* [rev:105868] fixed select all link using incorrect function
* [rev:105858] TableListField_Item::SelectOptionClasses() can use it parent protected variable.
* [rev:105833] fixed incorrect include path
* [rev:105732] validate file in import from CSV form
* [rev:105726] If database version can't be determined, just use the database adapter class
* [rev:105711] Install now supports sending database version if available from the helper
* [rev:105705] ss2stat URL not generated correctly (has NULL values)
* [rev:105668] Moved SiteTree->ParentID property to Hierarchy extension (fixes #5638)
* [rev:105667] More specific regex in Requirements->includeInHTML() to avoid duplicating information by matching HTML5-style `<header>` tags instead of `<head>` (fixes #5640)
* [rev:105665] Can't set width or height on MemberTableField popup (fixes #5625, thanks smurkas)
* [rev:105514] if moderation on comments is enabled then redirect the user back down to the comment section to view the message rather than trying to direct to selector which doesnt exist
* [rev:105505] avoid adding loading class to TinyMCE add link, image, flash buttons
* [rev:105468] #5349: Use TEMP_FOLDER for Zend's cache temp dir.
* [rev:105337] get_title_sql has string concat hardcoded as ||, fixed for MSSQL which uses +, fix for #5613
* [rev:105278] Stricter object type checks in ViewableData->hasValue() and ViewableData->XMLval(). Broke in cases when SS_HTTPResponse is returned which doesn't extend from Object, hence doesn't have an exist() method (fixes #5524, thanks hamish)
* [rev:105264] addFieldToTab segfaulting under PHP 5.2
* [rev:105225] force dateformat to en_NZ if showcalendar is enabled as calendar is compatibile with en_NZ only
* [rev:105030] Fixed correct input ID in install.js due to change in r105029
* [rev:105029] Fixed inconsistent styling of reinstall actions at the bottom of the installer, and if using IIS, warn that this will overwrite the web.config file, not .htaccess
* [rev:104995] Fixed i18nTextCollector when used with i18nEntityProvider - class manifest is now stored lowercase, which means i18n::get_owner_module() didnt work reliably
* [rev:104972] TestSession::submitForm throws proper error if form not found
* [rev:104968] Requiring CMS_ACCESS_CommentAdmin instead of ADMIN permissions in PageCommentInterface and CommentAdmin administrative actions
* [rev:104962] Fixed bug in basicauth failover to session member.
* [rev:104962] Don't use session member for test site protection feature.
* [rev:104847] catch case of plugin not returning translations for the locale
* [rev:104793] Installer now checks the database version AFTER it has determined a connection can be established, which some databases require first
* [rev:104793] Database version check failures are now a warning, so a user can install at their own risk
* [rev:104745] after reset password, the site redirect to non-exisit page (SC #1)
* [rev:104720] Fixed installation problem where version error didn't show
* [rev:104679] Make URLs lowercase
* [rev:104678] Fixed Translatable::canEdit() to suit new permission customisation scheme
* [rev:104675] Prevent DataDifferencer from creating empty `<ins />` and `<del />` takes that confuse the browser.
* [rev:104672] Make RsyncMultiHostPublisher protected; give default value.
* [rev:104670] Director::test() shouldn't break if $_SESSION isn't set.
* [rev:104666] Removed references to php5 binary in Makefile
* [rev:104608] check if a request is present before using it to prevent undefined errors
* [rev:104581] Generate stage/live links using Controller::join_links() instead of string concatenation.
* [rev:104580] Fixed Controller::join_links() handling of fragment identifiers
* [rev:104552] when using custom Member title, the join was failing - it had wrong parameters. Now changed to correctly handle the ansi sql join for all Member columns.
* [rev:104533] Fix ModelAdmin Import hang (ticket 5569)
* [rev:104468] When finding an old page in the 404 handler, favour existing subpages over historical ones.
* [rev:104463] Fix legacy URL redirection for pre-nestedurls URLs, after it has been enabled.
* [rev:104436] Removed erroneous default config for unused templates module.
* [rev:104403] Wrong HTML syntax in LeftAndMain.ss (fixes #5552, thanks simon_w)
### Minor changes
* [rev:108049] Added warning about Director::set_dev_servers()
* [rev:108048] Documentation in CSVBulkLoader
* [rev:108025] Added test for #5662 (calling delete twice)
* [rev:108002] Fixed incorrect word "colon" with "dot"
* [rev:107878] Updated translations
* [rev:107876] Updated translations
* [rev:107838] Reverted r107831
* [rev:107789] Fixed DateField/TimeField validation message translation (wrong sprintf() nesting)
* [rev:107787] Fixed TimeField validation _t() entity name
* [rev:107784] Disabled 'showcalendar' option on CMSMain->SiteTreeFilterDateField() - it causes the CMS to load jQuery UI javascript just for this (rarely used field). To be re-enabled once we work with jQuery UI on a broader scale.
* [rev:107726] Moved class-specific documentation from doc.silverstripe.org back into class-level PHPDoc
* [rev:107725] Moved class-specific documentation from doc.silverstripe.org back into class-level PHPDoc
* [rev:107586] removed whitespace
* [rev:107525] Removed debug code in MemberTableField
* [rev:107442] Fixed DatetimeField display in cms
* [rev:107442] Removed obsolete .calendardate styles from cms_right.css
* [rev:107440] Using Google CDN for jQuery dependencies in FileIFrameField
* [rev:107437] Better error handling in i18n::get_language_name()
* [rev:107430] Fixed Documentation
* [rev:107415] Using Object::create() in DevelopmentAdmin to make objects mockable
* [rev:107400] Documentation in DataObjectSet
* [rev:107394] Changed "no_NO" locale for Norwegian into the more commonly used "nb_NO" in i18n class, meaning translations from translate.silverstripe.com can actually be selected now (fixes #5746)
* [rev:107366] Tweaking of installer text to avoid misleading information about "exists" when there's actually an error
* [rev:107307] Reverted r107305
* [rev:107305] Code formatting fix for setting Member locale in LeftAndMain::init()
* [rev:107276] Checking that Folder::findOrMake() can create an assets/assets/ folder
* [rev:107275] Using Filesystem::makeFolder() instead of mkdir() in Folder for file operations
* [rev:107274] Better presentation of extension error message in File and UploadValidator
* [rev:107273] Added unit tests to FileTest and FolderTest (some of them copied from FileTest, to test Folder behaviour separately)
* [rev:107272] Changed ImageTest to use fixture files located in assets/ folder, the filesystem API doesn't support Folder objects with "sapphire/..." paths, which leads to inconsistent results
* [rev:107271] Making FileTest->setUp()/tearDown() more resilient against in-test file/folder renames
* [rev:107270] More identifiable file naming in FileTest
* [rev:107269] Using File::get_file_extension() instead of substr() magic in File->setName()
* [rev:107269] Using exceptions instead of user_error() in File->setName()
* [rev:107268] Avoiding duplication by using existing getFullPath() in File->getAbsoluteURL()
* [rev:107267] Made File::get_file_extension() more readable, and added unit test
* [rev:107266] Removed File->setField(), doesn't have any overloaded functionality
* [rev:107265] Documentation in File and Folder class
* [rev:107214] updated generator tag URL
* [rev:107175] force exclusive connection
* [rev:107104] Added initial docs
* [rev:107030] return false rather than error out in case SS_Query:: is not a resource
* [rev:106938] mysql_fetch_row() expects resource, this will fatal if query was e.g. UPDATE when iterating a result because MySQLQuery::nextRecord() is used by Iterator::valid() and MySQLQuery:: is bool in this case
* [rev:106876] Making $Email available in Security_passwordsent.ss template (fixes #5737)
* [rev:106805] Added FileTest->testValidateExtension() (related to #5693)
* [rev:106804] Documentation
* [rev:106777] Reverted r88633, it breaks `<base>` tag in static HTML for ErrorPage->doPublish()
* [rev:106694] Removed trailing slash in BackURL, fixed error message sentence structure in PageCommentInterface.ss (fixes #5520)
* [rev:106687] Fixed hardcoded error message in PasswordValidator (fixes #5734)
* [rev:106687] Added PasswordValidatorTest
* [rev:106568] Provide a default message for FIELDISREQUIRED
* [rev:106313] Correct typo in comments
* [rev:106248] Made CMSMainTest more resilient against database ID changes (Postgres doesn't have auto-increment resets across tests at the moment)
* [rev:106190] Fixed memory limit setting in SapphireTest (regression from r106128)
* [rev:106187] Better checking of safe_mode in MemoryLimitTest
* [rev:106180] Add comments for ThumbnailStripField
* [rev:106156] Don't run memory limit tests in safe mode,
* [rev:106128] Preserve memory_limit between tests (for better PHP5.1 behaviour)
* [rev:106119] Added test for Database::hasTable().
* [rev:106090] Fixed test that required a separate Page table.
* [rev:106083] Removed db/build legacy wording in DevelopmentAdmin (fixes #5676)
* [rev:106081] Added test for #5657
* [rev:105985] add text/plain to the list of accepted mime types
* [rev:105912] Better error handling in Form::__construct() (fixes #5649)
* [rev:105732] Clear DB checkbox unchecked by default
* [rev:105517] Installer should not repeat "Could not determine your database version" twice in slightly varied words
* [rev:105516] Show better message if couldn't find MySQL version in MySQLDatabaseConfigurationHelper
* [rev:105305] More solid markup testing in TableListFieldTest through xpath
* [rev:105297] Fixed TableListFieldTest->testSelectOptionsRendering()
* [rev:105282] Using ASSETS_DIR and THEMES_DIR constant in Image, ManifestBuilder, Requirements, File (fixes #5619)
* [rev:105281] Using ASSETS_DIR constant in StaticPublisher (fixes #5619)
* [rev:105277] Translations
* [rev:105276] Translations
* [rev:105274] Reverted r105264, breaks CompositeFieldTest, FieldSetTest, TranslatableTest
* [rev:105273] Updated TableListField sublcass template to work with new TableListField->SelectOptions() setting
* [rev:105272] Fixed _t() call in PageCommentInterface.ss
* [rev:105270] missing slash / from Requirements::css() parameter
* [rev:105267] Removed jquery.livequery as a Requirement from LeftAndMain.php, its only necessary in SecurityAdmin for MemberImportForm.js now.
* [rev:105198] Fixed fixture location for DbDatetimeTest
* [rev:105196] Added DbDatetimeTest cases to sapphire (these were previously in the sqlite3 module, but they actually test core Database functionality)
* [rev:105188] Documentation
* [rev:105139] increased height of the todo text field in the cms
* [rev:105027] Checking for headers_sent() before setting cookies in Versioned::choose_site_stage() to avoid problems with URL parameters like showqueries=1 and ContentController calling choose_site_stage() (fixes #5557)
* [rev:105011] Documentation
* [rev:105009] Documentation
* [rev:105005] Documentation
* [rev:104996] Documentation
* [rev:104993] Language master file
* [rev:104992] Removed duplicated code in i18nTextCollector, more defensive checks for get_owner_module()
* [rev:104980] Added translations for BrokenLinksReport, ReportAdminForm.ss, AssetTableField.ss (fixes #5527, thanks Martimiz)
* [rev:104978] Allowing translation of "save" button in SiteConfig->getCMSActions()
* [rev:104970] Translations in PageCommentInterface.ss (fixes #5598, thanks Pike)
* [rev:104924] Reverted r104923, as current database releases of mssql and sqlite3 modules don't support this yet
* [rev:104883] Fixed hidden mbstring reliance in SiteTree->generateURLSegment() (broken in r104679)
* [rev:104835] Save and restore lang state in test
* [rev:104798] Fixed SiteTreeTest and SiteTreePermissionsTest to work alongside subsites module (SiteTreeSubsites changes the canEdit() behaviour)
* [rev:104796] Fixed SiteConfigTest to work alongsite subsites module (SiteTreeSubsites changes the canEdit() behaviour)
* [rev:104795] Documentation
* [rev:104769] Documentation
* [rev:104767] Documentation
* [rev:104733] fixed umlauts
* [rev:104711] Added DirectorTest->testURLParam() and DirectorTest->testURLParams()
* [rev:104710] Installing screen now has a page title called "Installing SilverStripe..." instead of "PHP 5 is required"
* [rev:104709] Removed double returns in installer (redundant code)
* [rev:104708] Renamed checkdatabase method to checkDatabase to be consistent
* [rev:104705] Show install MySQL version at 5.0+ as 4.1 does not work properly with SilverStripe
* [rev:104704] Tweaks to positioning of help text in installer
* [rev:104682] fixed api doc
* [rev:104636] added illustrator formats to the allowed extensions.
* [rev:104610] Documentation
* [rev:104598] Fixed wrong _t() notation in ChangePasswordForm (broken in r103226 and r104596)
* [rev:104596] Making strings in ContentControllerSearchExtension translatable
* [rev:104594] Defensive coding in MigrateSiteTreeLinkingTask
* [rev:104490] Removed ForumAdmin.js which shouldn't belong in the CMS module
* [rev:104483] Documentation
* [rev:104404] Documentation
* [rev:104402] Documentation
* [rev:104158] Documentation migrated from doc.ss.org
* [rev:104157] Migrated various API-style documentation from doc.ss.org
### Other
* [rev:105057] MINOT Translation in SiteTree (#5603, thanks Pike)
* [rev:104674] ENHANCMENT: RsyncMultiHostPublisher also rsyncs sapphire/static-main.php.
* [rev:104668] Sake fix: look for php binary before php5, to prevent errors on CentOS and Cygwin.
* [rev:104667] Added explicit bash handler to sake
* [rev:104442] Multi-use redemption page created
{![](_images/./sscreatechangelog --version 2.4.1-rc1 --branch branches/2.4 --stopbranch tags/2.4.0)}

View File

@ -0,0 +1,20 @@
# 2.4.1-rc2
## Changelog
### Bugfixes
* [rev:108207] Re-allowing direct execution in sapphire/thirdparty/tinymce/plugins/spellchecker/rpc.php (necessary for cms spellchecker, was disabled by global .htaccess rule)
* [rev:108195] #5837 cache_dir not writable by Zend when accessing the CMS, because of Windows default which should be the sapphire TEMP_FOLDER
* [rev:108193] Bypass !BasicAuth when in CLI mode so unit tests can run (regression from r104962)
* [rev:108099] Fixing default group selection in 'add member' dialog (in !MemberTableField) (fixes #5836)
* [rev:108096] AssetAdmin->doUpload() shows JS alert *before* triggering a page reload, as this seems to mess up TinyMCE in Firefox on subsequent page loads (fixes #5838)
### Minor changes
* [rev:108208] Disallowing more potentially active file extensions in mysite/.htaccess
* [rev:108207] Disallowing more potentially active file extensions in cms/.htaccess
* [rev:108206] Disallowing more potentially active file extensions in cms/.htaccess
* [rev:108196] Removed debug
<code>./sscreatechangelog --version 2.4.1-rc2 --branch branches/2.4 --stopbranch tags/rc/2.4.1-rc1</code>

View File

@ -0,0 +1,146 @@
# 2.4.2-rc1
## Changelog
### Features and Enhancements
* [rev:110757] added the ability to toggle the use draft site setting
* [rev:110467] #5977 Added optional argument to !ClassInfo::getValidSubClasses() and removed harcoded !SiteTree
* [rev:110211] disable basic auth by default, tests run on the assumption it is disabled.
* [rev:109104] Added -v / --verbose option to dev/tests/*, to make it output every single test name before it starts that test.
* [rev:109101] Session::set_cookie_path() and Session::set_cookie_domain() are now possible. This is useful for sharing cookies across all subdomains, for example.
* [rev:108942] make !RestfulService support PUT method.
* [rev:108663] ErrorDocument in default .htaccess so Apache serves default 404 and 500 server error pages
* [rev:108644] #3828 500 server error page is created by default on dev/build
* [rev:108499] New Member records are populated with the currently set default through i18n::set_locale()
* [rev:108437] Restful service returns cached response on http and curl errors
* [rev:108428] #2856 Limiting of relative URLs for Director::forceSSL() using a map of PCRE regular expressions
* [rev:108418] Added argument to SQLQuery->leftJoin()/innerJoin() (#5802, thanks stojg)
* [rev:108417] Full-text search with double quotes returns too many results. ticket #5733. Thanks ktauber.
### API Changes
* [rev:110856] Member->canEdit() returns false if the editing member has lower permissions than the edited member, for example if a member with CMS_ACCESS_!SecurityAdmin permissions tries to edit an ADMIN (fixes #5651)
* [rev:109156] #5873 !DataObjectSet::shift() now performs a proper shift instead of unshift (wrong). Please use !DataObjectSet::unshift($item) if unshifting was intended!
* [rev:109156] Added !DataObjectSet::pop()
* [rev:109103] Member::set_session_regenerate_id() can now be used to disable Member::session_regenerate_id() which can break setting session cookies across all subdomains of a site
### Bugfixes
* [rev:110901] delete orphaned records from versioned tables when updating. #5936
* [rev:110894] Protect !MemberTest from side effects caused by auth_openid and forum modules
* [rev:110889] Respecting field specific locale settings in !DatetimeField and !DateField when validating and saving values (fixes #5931, thanks Tjofras)
* [rev:110859] Disallow addition of members to groups with !MemberTableField->addtogroup() when the editing member doesn't have permissions on the added member
* [rev:110858] Don't suggest members in !SecurityAdmin->autocomplete() that the current user doesn't have rights to edit (fixes #5651)
* [rev:110857] Enforcing canEdit() checks in !ComplexTableField_Popup - making form readonly if the current user can't edit
* [rev:110838] Case insensitive !DateField value navigation (fixes #5990, thanks gw0(
* [rev:110835] Passing $name in !MoneyField->!FieldCurrency() (fixes #5982, thanks andersw)
* [rev:110809] Removing "typography" class from HTMLEditorField container (should just apply to the contained <iframe>) (fixes #5949)
* [rev:110808] Allowing $extraClass on !CheckboxField !FieldHolder (fixes #5939, thanks mobiusnz)
* [rev:110759] ensure that pages can only be requested from staging and live
* [rev:110463] Fixed boundary PHP notice case in !RequiredFields::php() where a field name may not be defined in the $data array when a Form is submitted
* [rev:110439] #5811 Fixed default selection of root node when CMS first opened (no currentPage set in session)
* [rev:110262] fix !TranslatableSearchFormText by supporting fulltext search for MSSQL and using extendedSQL function call that augments queries properly (previously it was using DB::query which does not augment). Added wait to !TranslatableSearchFormText so the test actually passes.
* [rev:110197] MigrateSiteTreeLinkingTask now takes a direct map when querying the page tracked links instead of looping through the direct result set. This fixes SQL Server failing when MARS (Multiple Active Result Sets) is disabled
* [rev:110165] Fixed missing "Save" action input label on !ComplexTableField popup form
* [rev:110130] force the test to wait until indexing completes. Do not use stop words ('me')
* [rev:109834] BasicAuthTests fail when Member's unique_identifier_field is anything except the default of Email
* [rev:109714] disable basic auth for the restful controller test
* [rev:109712] makeRelative would return "false" for the root path, empty string is expected - fix that
* [rev:109712] change the check in forceSSL to work on Windows - it sets the $_SERVER['https'] to off, instead of null
* [rev:109591] getItem didn't consider the PostgreSQL SQL syntax. Columns with Capital letters must be quoted. Added quotes to the where clause in getItem. I didn't added quotes to the baseTable because it causes PostgreSQL errors (tables can not be double quoted, just single quoted).
* [rev:109168] $val is now cast as an int to prevent strings always returning true (YES)
* [rev:109155] Validator::requiredField() should check the required field submitted value is an array before check strlen(). Some fields submitted as an array, e.g. !MoneyField
* [rev:109128] Remove () that was breaking coverage report
* [rev:109106] sort order of widgets is now fixed.
* [rev:109102] Themed permissionFailure messages
* [rev:109083] Group::getCMSFields() should use Tab instances with a fixed name instead of translated one, leaving the translation for the tab title instead
* [rev:109082] SiteTree decorated canView() checks not being passed through to !SiteTree::canView()
* [rev:109081] StringField::setNullifyEmpty() should assign the given value boolean, not evaluate whether it's true or not
* [rev:109079] Count() call on a non-object in File::!BackLinkTrackingCount()
* [rev:109063] Fixed File::getAbsoluteURL() absolute generation
* [rev:109062] File::getAbsoluteURL() should return a URL, not a filesystem path
* [rev:108887] CSVBulkLoader import method now no longer requires files to end in '.csv'. Some projects want to import files in CSV format, but not of csv file type.
* [rev:108811] Added specific border case for array form data in !RequiredFields::php()
* [rev:108792] Fixed validation to accept arrays (!FileField case)
* [rev:108633] NumericField javascript does not accept negatives, make use of isNaN built-in javascript function instead of custom regex
* [rev:108515] #5627 Clear session on logout
* [rev:108513] EMAIL_BOUNCEHANDLER_KEY cannot be defined
* [rev:108512] Validator/!RequiredFields should not regard "0" as an empty value
* [rev:108509] SapphireTest::create_temp_db() should restore the SS error handler from the PHPUnit one temporarily in case there's any errors building
* [rev:108492] Undefined variable destURL in Director::forceWWW() (regression from r107094)
* [rev:108436] Checking for existence of $('!SwitchView') (fixes #5282)
* [rev:108432] Database password input in installer should be password, so that the password is obfuscated when input
* [rev:108427] Take note of output format when building Location header for !RestfulServer
* [rev:108422] CurrencyField doesn't accept negative value (#5769, thanks simon_w)
* [rev:108421] Fixed !ContentNegotiator to handle HTML and XHTML base tags properly when converting, regression from r108413
* [rev:108413] #5855 SSViewer::get_base_tag() should produce a properly closed base tag for XHTML (thanks smorris!)
* [rev:108409] #5862 JSON output of JSONDataFormatter now uses quotes for keys to be safer
* [rev:108408] Member_!ProfileForm should fallback to english text for save button if no translation defined for current language
* [rev:108407] #5852 Missing translation for !SecurityAdmin save button causes it to have no text, should default to english "Save"
* [rev:108400] Undefined variable when calling !DataObject::many_many_extraFields() and relation name couldn't be found for the component
* [rev:108399] DataObjects without the Versioned decorator cannot have a "Version" field. ticket #5775. Thanks ajshort
* [rev:108397] Added condition to avoid error creating "!PastMember" cookie on dev/build (ticket #5780) Thanks simon_w
* [rev:108396] Applied/edited paradigmincarnate's patch to quote plaintext email with htmlEmail (#5120)
### Minor changes
* [rev:110847] Documentation
* [rev:110837] Check in !TableListField->!HighlightClasses() (fixes #5993, thanks lx)
* [rev:110836] Avoid using ASP-style tags in SSViewer comments, it confuses PHP with asp_tags=ON (fixes #5976, thanks ezero)
* [rev:110440] Warning about install.php existing for root site tree node as well (!SiteConfig form)
* [rev:110435] German translations for cms javascript (#5921, thanks bartlomiej)
* [rev:110243] added missing closing tag
* [rev:110205] Make dev/build not constantly show a changed index because of whitespace between VersionID and Version in the index spec
* [rev:110200] Removed removeDuplicates() call on linked pages !DataObjectSet in !MigrateSiteTreeLinkingTask which is no longer required, as the duplicate results were fixed in !DataObject directly
* [rev:110190] only call next() in iterator validation on initialisation or after reset NOT if current value is invalid
* [rev:109788] repair installer for sqlite
* [rev:109787] repair installer for sqlite
* [rev:109405] neatly quote identifiers
* [rev:109382] return a fail instead of an error
* [rev:109334] Remove whitespace if Surname field set on Member, but not !FirstName
* [rev:109333] Tests for Member::getName() and Member::setName()
* [rev:109330] trim space off end of firstname if surname is not set. #5925
* [rev:109274] CSSContentParser::__construct() now gives a better error if the content could not be parsed. This will mostly happen if tidy isn't present.
* [rev:109165] phpDoc updates for SS_!LogFileWriter and SS_!LogEmailWriter
* [rev:109156] Unit tests for !DataObjectSet::shift(), !DataObjectSet::unshift() and !DataObjectSet::pop()
* [rev:109152] Doc update for Director::forceSSL()
* [rev:109127] Applied patch from walec51 for <% control %> on empty set (#5579) Also added unit tests by ischommer
* [rev:109105] Fix links etc, and remove www. from SS urls
* [rev:109100] Clear out the test database in between each salad scenario.
* [rev:109066] Added tests for File::getURL() and File::getAbsoluteURL()
* [rev:108961] remove SQL table alias keyword AS
* [rev:108666] Fixed tests not working on the web side as redirection to https would occur
* [rev:108665] Fixed !DirectorTest to restore it's REQUEST_URI state to the original one after each test method is run
* [rev:108640] allow $icon to be overridden on !ErrorPages. PATCH via martljn (#5875).
* [rev:108571] Changed unknown web server text
* [rev:108570] Allow checking for a specific IIS version (parameter to !InstallRequirements::isIIS())
* [rev:108569] Removed double up of similar logic in !InstallRequirements
* [rev:108568] Simplified discovery of webserver during install
* [rev:108561] Removed unncessary isset() check
* [rev:108559] Add some documentation to !LeftAndMain_right.js
* [rev:108546] Removed command line functionality from installer which is no longer used
* [rev:108518] Fixed failing test as session being set before logging out and losing BackURL
* [rev:108500] Fixed failing tests because of locale not being set to the default in !SapphireTest::setUp()
* [rev:108442] Translations in CMSMain_left.ss
* [rev:108441] Making "todo" tab title translatable
* [rev:108435] Fixed Director::forceSSL() breaking unit tests because headers were already sent
* [rev:108434] Reverted r108433
* [rev:108433] DirectorTest should not extend from !FunctionalTest (regression from r108428)
* [rev:108376] Add trailing slash to image tag (thanks to mattclegg)
* [rev:108375] Cross-referencing some documentation
### Other
* [rev:110241] #5870 Block web requests to silverstripe-cache directory via htaccess !RedirectMatch rule or web.config hiddenSegments functionality if using IIS 7.x
* [rev:109177] Revert "MINOR: Applied patch from walec51 for <% control %> on empty set (#5579) Also added unit tests by ischommer"
* [rev:109177] This was not supposed to be pushed out yet.
* [rev:109177]
* [rev:109177] This reverts commit 9c2aafa414948314236674e31fd756797d695139.
* [rev:109163] Revert "BUGFIX: sort order of widgets is now fixed."
* [rev:109163]
* [rev:109163] This reverts commit 1e7781ba2b8ac30333a20d9a1b0bcb9b4ba5b0b0.
* [rev:109099] Added dev/tests/emptydb to clear out test session databases.
* [rev:108417] Using htmlentities($keywords,ENT_NOQUOTES) instead of proposed solution
<code>./sscreatechangelog --version 2.4.2-rc1 --branch branches/2.4 --stopbranch tags/2.4.1</code>

View File

@ -0,0 +1,8 @@
# 2.4.2-rc2
## Changelog
### Bugfixes
* [rev:110944] Fixed column names that were not quoted that broke PostgreSQL
* [rev:110914] Fixed double quotes around column names in Versioned::augmentDatabase()

View File

@ -0,0 +1,148 @@
# 2.4.3-rc1
## Changelog
### Features and Enhancements
* [rev:113284] Added Form->enableSecurityToken() as a counterpart to the existing disableSecurityToken()
* [rev:113272] Added !SecurityToken to wrap CSRF protection via "SecurityID" request parameter
* [rev:112973] Installer now has a fallback for mod_rewrite detection by setting an environment variable in .htaccess when "<!IfModule mod_rewrite.c>" directive is satisfied
* [rev:112272] MySQLDatabase::renameField() no longer checks that the field exists in fieldList(). alterField() does no such check, so it should be consistent. Removing this should provide a small performance improvement as well
* [rev:112247] Installer exposes database type in "Database support" configuration
* [rev:111915] Added localisation for batch actions in javascript + translations
* [rev:111891] #4903 !MemberLoginForm field for "You are logged in as %s" message customisation (thanks walec51!)
* [rev:111887] #3775 Added getter to GD so you can retrieve the internal GD resource being used. Made setGD public so you can override the GD yourself as well
* [rev:111874] "Database Configuration" section in installer shows database version and database type (without the "Database" suffix) for reference
* [rev:111873] Show "Database Configuration" section of installer requirements for reference (collapsed by default)
* [rev:111868] MySQLDatabase::getVersion() now uses mysql_get_server_info() which has been supported since PHP 4. This gives us a better version than say "5.1", instead we now get something like "5.1.51"
* [rev:111850] Make use of mysql_get_server_info() when calling MSSQLDatabase::getVersion(), if there's a problem getting info this way, falls back to using query for VERSION() details
* [rev:111828] 6017 - Configurable help link
* [rev:111495] Making "sake" script more portable by using "/usr/bin/env" shebang instead of "/bin/bash" (fixes #6045, thanks sychan)
* [rev:111489] Added "module=" argument to !FullTestSuite (to support comma-separated module lists)
* [rev:111449] allow !PageCommentForm to store all users data, rather than hardcoding the fields
* [rev:111443] simple extend hook for !PageCommentForms. Temporary measure till #6053 is implemented
* [rev:111086] #6023 Shorten SSViewer cached template path for readability of the filenames, and also so Windows doesn't break on long paths
* [rev:111055] Added phpunit.xml.dist to avoid setting bootstrap includes and other !SilverStripe specific configuration as CLI parameters and test-level includes
* [rev:111054] Created a phpunit wrapper class to ensure that Sapphire's test framework is capable of running unit tests, coverage report and retrieve clover-statistics for PHPUnit 3.4 and PHPUnit 3.5
* [rev:111050] Added custom test listener for PHPUnit in order to call setUpOnce() and tearDownOnce() on !SapphireTest
* [rev:111048] Allowing to run single tests via phpunit through new test bootstrap XML file (e.g. "phpunit sapphire/tests/api/!RestfulServerTest.php" or "phpunit sapphire/tests/api")
* [rev:111045] Added !FullTestSuite.php, so that you can test by running "phpunit sapphire/tests/!FullTestSuite".
* [rev:111041] refactored runTests, using the new phpunit wrapper classes.
* [rev:111039] Created a phpunit wrapper class to ensure that Sapphire's test framework is capable of running unit tests, coverage report and retrieve clover-statistics for PHPUnit 3.4 and PHPUnit 3.5
### API Changes
* [rev:113282] Fixed various controllers to enforce CSRF protection through Form_!SecurityToken on GET actions that are not routed through Form->httpSubmission(): !AssetAdmin, CMSBatchActionHandler, CMSMain, !CommentTableField, !LeftAndMain, !MemberTableField, !PageComment, !PageComment_Controller
* [rev:113275] Added security token to !TableListField->Link() in order to include it in all URL actions automatically. This ensures that field actions bypassing Form->httpSubmission() still get CSRF protection
### Bugfixes
* [rev:113295] Ensure that !SearchForm searchEngine() call properly escapes the Relevance field for ANSI compliance
* [rev:113277] Clear static marking caches on Hierarchy->flushCache()
* [rev:113276] Fixed !ComplexTableField and !TableListField GET actions against CSRF attacks (with Form_!SecurityToken->checkRequest())
* [rev:113273] Using current controller for !MemberTableField constructor in Group->getCMSFields() instead of passing in a wrong instance (Group)
* [rev:113249] ModelViewer doesn't work due to minor bug introduced by making $_CLASS_MANIFEST keys lowercase (fixes #6144, thanks daniel.lindkvist)
* [rev:113247] Fixed month conversion in !DateField_View_JQuery::convert_iso_to_jquery_format() (fixes #6124, thanks mbren and natmchugh)
* [rev:113193] removed taiwans province of china
* [rev:113157] Add PHPUnit includes to !SapphireTest? class (can be loaded outside of !TestRunner? for static calls, in which case the PHPUnit autoloaders/includes aren't in place yet) (merged from r113156)
* [rev:113107] Use correct language code for jquery-ui date picker for en_US
* [rev:113085] check !DisplaySignatures on the thread rather than post. #5409
* [rev:112963] Enhance the protection of the assets/ directory in both IIS and Apache by including a file type whitelist.
* [rev:112961] Don't include web.config in the assets tracked in the File table.
* [rev:112288] Renamed !MySQLQuery::__destroy() renamed to __destruct() so that it is called properly after the object is destroyed
* [rev:112258] one more requirement switched to SSL
* [rev:111949] Ensure that \r carriage return characters get stripped out before setting content in HTMLValue::setContent(). DOMDocument will transform these into &#13 entities, which is apparently XML spec, but not necessary for us as we're using HTML
* [rev:111932] #6089 Avoid javascript error when "Allow drag & drop reordering" enabled, and attempt to drag a file from one folder to another is performed
* [rev:111914] #6096 RSSFeed::feedContent() restores previous state of SSViewer::get_source_file_comments() after temporarily disabling it (thanks paradigmincarnate!)
* [rev:111898] Filesystem::removeFolder() did not remove files that ended with a "." when this is a valid file. Remove the regex and replace with specific case for "." and ".."
* [rev:111890] #6066 Form::__construct() should respect hasMethod on passed in Controller instance if it's available (thanks paradigmincarnate!)
* [rev:111889] #3910 Setting timezone parameter to !MySQLDatabase::__construct() should use $this->query() to be consistent
* [rev:111878] Ensure that windows-style newlines ("\r\n") don't get converted to their XML entity representation through DOMDocument in SS_HTMLValue->setContent()
* [rev:111843] More common defaults for en_US.xml used by Zend_!DateFormat (and !DateField/!DatetimeField), with less error prone numerical format replacing the Zend default of shortened month names (fixes #6071, thanks dalesaurus)
* [rev:111843] Correct locale mapping in !DateField_View_JQuery for "en_US" and "en_NZ"
* [rev:111842] #6055 !ErrorPage should always create static error page files when dev/build is called if they don't exist
* [rev:111841] RFC 2822 compliant validation of email adresses in !EmailField->jsValidation() and !EmailField->validate() (fixes #6067, thanks paradigmincarnate)
* [rev:111772] DB::connect() should not rely on $_SESSION existing, so we check isset() to supress any warnings of undefined indexes
* [rev:111494] Changing File->Filename property from arbitrary limitation on VARCHAR (255 characters) to TEXT (65k characters) to ensure the framework can handle deeply nested filesystem trees (fixes #6015, thanks muzdowski)
* [rev:111493] Moving folder after executing Folder::findOrMake will not set the Filenames properly. Invoking updateFilesystem() in File->onAfterWrite() instead of onBeforeWrite(), and avoid caching in FIle->getRelativePath() (fixes #5994 and #5937, thanks muzdowski)
* [rev:111492] Removing overloaded !TableField->sourceItems() method, which enables features of the underlying !TableListField implementation, such as pagination and source item caching (fixed #5965, thanks martijn)
* [rev:111464] Search didn't respect searchableClasses passed to !FulltextSearchable::enable()
* [rev:111452] added validation to the page comment form
* [rev:111369] Installer now checks for session_start() and hash() support
* [rev:111266] Installer now checks for iconv support, which is required for !DateField? (using Zend libraries) to function correctly
* [rev:111255] ContentController::!SiteConfig() should look to the !SiteTree record so an alternate !SiteConfig is considered, if this method doesn't exist on the data record then fall back to the default !SiteConfig
* [rev:111202] Fixed quoting and GROUP BY statement in !ManyManyComplexTableField->getQuery() for Postgres compatibility
* [rev:111176] Force tidy to avoid wrapping long lines in CSSContentParser, it breaks our !FunctionalTest string assertions
* [rev:111126] TarballArchive::extractTo() uses an incorrectly spelled argument
* [rev:111097] Fixed !PhpSyntaxTest not to rely on relative folder references (broken due to chdir() changes in cli-script.php and bootstrap.php)
* [rev:111092] Fixed regression where coverage report request did not get passed through to runTests() in !TestRunner::all()
* [rev:111091] Fixed regression of dev/tests/all running a coverage report instead of just unit tests
* [rev:111049] Unset $default_session when using Session::clear_all()
* [rev:111044] Allow execution of a test without a current controller.
* [rev:111043] Don't require a current controller for Session::get/set/etc to work.
### Minor changes
* [rev:113281] Removed unused !SecurityAdmin->!MemberForm() and savemember() (see !MemberTableField)
* [rev:113280] Removed unused Security->addmember() (see !MemberTableField and !SecurityAdmin->addtogroup())
* [rev:113279] Removed unused !SecurityAdmin->removememberfromgroup() (see !MemberTableField)
* [rev:113278] Removed unused !MemberList templates (see !MemberTableField)
* [rev:113274] Using !SecurityToken in !ViewableData->getSecurityID()
* [rev:113248] Javascript translations in CMSMain_right.js (fixes #6142)
* [rev:113241] Documentation
* [rev:113086] reverted previous commit. Note to self dont work on sunday nights, sigh
* [rev:112982] updated typo in comment for Cache.
* [rev:112972] Clearer message when rewrite doesn't work during installation
* [rev:112972] Fixed missing end to anchor tag
* [rev:112962] Fix to !SapphireInfo for git-svn checkouts.
* [rev:112961] Add documentation to File::$allowed_extensions explaining that there are config files to edit in assets/
* [rev:112321] Removed "In line of " text in CLI test reporter which did not work. Details are in the backtrace below anyway, so it's not required
* [rev:112278] Reverted regression in r112272
* [rev:112268] Remove whitespace from generated _config.php file in installer
* [rev:112254] change the requirement's link to use current protocol (we don't want messages from browsers saying the page has unsecured content, when accessing the CMS over SSL)
* [rev:111950] Comment about HTMLValue::setContent() stripping out of carriage returns
* [rev:111903] #6083 !FileTest doesn't remove test folders and files created during test
* [rev:111899] Use Filesystem::removeFolder() in !FilesystemPublisherTest::tearDown() instead of specific code to handle this
* [rev:111898] Code syntax formatting of Filesystem::removeFolder()
* [rev:111888] Moved GD::set_default_quality() function to the top of the file to align with conventions
* [rev:111883] #6090 !FilesystemPublisherTest now stores temporary files in assets, which is writable, instead of the webroot which almost never has write permissions
* [rev:111875] Enable non-default language for tinyMCE, setting language in _config.php didn't work. Thanks for @christian
* [rev:111852] Revert r111850 to !MySQLDatabase::getVersion as version comparisons need to happen, and this will strip out non-numeric characters e.g. "ubuntu1" or "lenny4" which are prefixed on some Linux distros
* [rev:111851] dev/build now shows database name and version next to "Building database ..." text
* [rev:111844] Fixed regression from r111843 (i18nText, !MemberDatetimeFieldTest, !MemberTest)
* [rev:111843] Fixed form validation message in !DateField to include actual date format, rather than a hardcoded value
* [rev:111821] Change matchesRoughly threshold slightly in !DbDatetimeTest to allow for slower database server connections
* [rev:111789] Added !FulltextSearchable::get_searchable_classes() in order to introspect currently searchable classes, added !FulltextSearchableTest, added documentation
* [rev:111788] Fixed documentation in !CheckboxSetField (fixes #6068, thanks paradigmincarnate)
* [rev:111787] Fixed documentation in Datetime (fixes #6062, thanks nicolaas)
* [rev:111786] Fixed SS_Datetime references in !BrokenLinksReport and !CommentAdmin (fixes #6063, thanks nicolaas)
* [rev:111772] Code formatting tidy of DB::connect() function
* [rev:111748] CoreTest::testGetTempPathInProject() will try to create a temp dirs when running. !CoreTest::tearDown() will now remove these temp dirs when the test finishes
* [rev:111676] #5943 Debug::text() boolean values are amended with (bool) so they don't get confused with "true" or "false" which could be strings (thanks Pigeon!)
* [rev:111669] Unit test breaks if another module or project extends Folder
* [rev:111597] Updated language master file
* [rev:111497] Fixed indentation in !PageCommentInterface.js
* [rev:111496] Fixed SQL quoting bug in !FolderTest (caused by r111493)
* [rev:111491] Documentation for phpunit.xml.dist
* [rev:111454] removed debug
* [rev:111450] removed debug
* [rev:111262] Add translation correction for Czech and add Slovakian translation in cms and sapphire (js). Thanks to @Pike
* [rev:111224] Ensuring !SiteTreeAccess.js is properly minified in live mode
* [rev:111133] Code formatting in !FullTestSuite
* [rev:111123] Spelling corrections to Director comments
* [rev:111117] Exclude "sanity check" type tests by default from PHPUnit runs (e.g. !PhpSyntaxTest)
* [rev:111116] PHPUnit annotations for !PhpSyntaxTest
* [rev:111053] Removing !MemberImportFormTest, breaks PHPUnit test run, and doesnt have any assertions
* [rev:111052] Documentation for constants in Core.php
* [rev:111051] Don't use chdir(), it confuses the hell out of phpunit (e.g. directory_exists() and realpath() no longer work as expected)
* [rev:111047] Fixed SSViewerTest to initialize controller properly
* [rev:111046] Remove all session data in !TestSession that might've been set by the test harness (necessary for test runs through the phpunit binary)
* [rev:111042] added phpdoc to the new PHPUnitWrapper classes.
### Other
* [rev:111880] #4029 On the fly form validation works in Opera as well
* [rev:111879] Added doc for static help_link
* [rev:111452] Fixes #2782
* [rev:111040] API-CHANGE: remove include which is not required.
* [rev:111038] ENHACENEMENT: Change behaviour of the !MenufestBuilder to use spl_autoload_register instead of traditional __autoload.

View File

@ -0,0 +1,7 @@
# 2.4.3-rc2
## Changelog
### Minor changes
* [rev:113360] Fixed regression from r113282 for changed !SecurityToken API in CMSMain->publishall() (fixes #6159)

View File

@ -0,0 +1,80 @@
# 2.4.4-rc1
## Changelog
### Features and Enhancements
* [rev:114572] 'bypassStaticCache' cookie set in Versioned is limited to httpOnly flag (no access by JS) to improve clientside security (from r114568)
* [rev:114571] Session::start() forces PHPSESSID cookies to be httpOnly (no access by JS) to improve clientside security (from r114567)
* [rev:114499] Added !RandomGenerator for more secure CRSF tokens etc. (from r114497)
* [rev:114467] PHP requirements in installer now check for date.timezone correctly being set for PHP 5.3.0+. This option is *required* to be set starting with 5.3.0 and will cause an error during installation if not
* [rev:114083] Added SS_HTTPResponse->setStatusDescription() as equivalent to setStatusCode(). Added documentation.
* [rev:113963] Split temp directory check and writability into two checks
* [rev:113961] #6206 Installer additional checks for module existence by checking _config.php exists, in addition to the directory
* [rev:113919] Allowing i18nTextCollector to discover entities in templates stored in themes/ directory (thanks nlou) (from r113918)
* [rev:113871] Update Asset's left and right panels with filders and files after 'Look for new files' was triggered (open #5543)
### API Changes
* [rev:114474] Using i18n::validate_locale() in various Translatable methods to ensure the locale exists (as defined through i18n::$allowed_locales) (from r114470)
### Bugfixes
* [rev:114783] Removed switch in !MySQLDatabase->query() to directly echo queries with 'showqueries' parameter when request is called via ajax (from r114782)
* [rev:114774] Disallow web access to sapphire/silverstripe_version to avoid information leakage (from r114773)
* [rev:114771] Disallow web access to cms/silverstripe_version to avoid information leakage (from r114770)
* [rev:114760] Avoid potential referer leaking in Security->changepassword() form by storing Member->!AutoLoginHash in session instead of 'h' GET parameter (from r114758)
* [rev:114719] Fallback text for "Password" in !ConfirmedPasswordField when no translation found
* [rev:114683] Populates the page with fake data in order to pass subsequent unit tests
* [rev:114654] Test if form is the right class (if a class decorates the content controller, this test would break ie sphinx)
* [rev:114516] Escaping $locale values in Translatable->augmentSQL() in addition to the i18n::validate_locale() input validation (from r114515)
* [rev:114512] Limiting usage of mcrypt_create_iv() in !RandomGenerator->generateEntropy() to *nix platforms to avoid fatal errors (specically in IIS) (from r114510)
* [rev:114507] Using !RandomGenerator class in Member->logIn(), Member->autoLogin() and Member->generateAutologinHash() for better randomization of tokens. Increased VARCHAR length of '!RememberLoginToken' and '!AutoLoginHash' fields to 1024 characters to support longer token strings. (from r114504)
* [rev:114506] Using !RandomGenerator class in !PasswordEncryptor->salt() (from r114503)
* [rev:114500] Using !RandomGenerator class in !SecurityToken->generate() for more random tokens
* [rev:114473] Check for valid locale in i18n::set_locale()/set_default_locale()/include_locale_file()/include_by_locale() (as defined in i18n::$allowed_locales). Implicitly sanitizes the data for usage in controllers. (from r114469)
* [rev:114445] Don't allow HTML formatting in !RequestHandler->httpError() by sending "Content-Type: text/plain" response headers. (from r114444)
* [rev:114208] Including template /lang folders in i18n::include_by_locale() (implementation started in r113919)
* [rev:114195] Added !SecurityToken to !PageCommentInterface->!DeleteAllLink() (fixes #6223, thanks Pigeon)
* [rev:114083] Strip newlines and carriage returns from SS_HTTPResponse->getStatusDescription() (fixes #6222, thanks mattclegg) (from r114082)
* [rev:114081] Removed double quoting of $where parameter in Translatable::get_existing_content_languages() (fixes #6203, thanks cloph) (from r114080)
* [rev:114036] Fixed case where !AssetAdmin would throw an error if $links was not an object in !AssetAdmin::getCustomFieldsFor()
* [rev:113976] #6201 Use of set_include_path() did not always include sapphire paths in some environments
* [rev:113962] Installer now checks temporary directory is writable, in addition to it being available.
* [rev:113809] #6197 simon_w: Fixed Internal Server Error when accessing assets on Apache without mod_php.
* [rev:113692] Avoid reloading CMS form twice after certain saving actions (fixes #5451, thanks muzdowski)
### Minor changes
* [rev:114751] Setting Content-Type to text/plain in various error responses for !RestfulServer (from r114750)
* [rev:114749] Reverting Member "!AutoLoginHash", "!RememberLoginToken" and "Salt" to their original VARCHAR length to avoid problems with invalidated hashes due to shorter field length (from r114748)
* [rev:114745] Partially reverted r114744
* [rev:114744] Reduced VARCHAR length from 1024 to 40 bytes, which fits the sha1 hashes created by !RandomGenerator. 1024 bytes caused problems with index lengths on MySQL (from r114743)
* [rev:114720] Code formatting change in !ConfirmedPasswordField::__construct()
* [rev:114454] Added exception handling if !ClassName is null in search results
* [rev:114334] Checking for class_exists() before !SapphireTest::is_running_tests() to avoid including the whole testing framework, and triggering PHPUnit to run a performance-intensive directory traversal for coverage file blacklists (from r114332)
* [rev:114079] Reverted r108515
* [rev:114078] Documentation for Aggregate caching (from r114077)
* [rev:114062] fixed visual glitch in CMS access tab for IE
* [rev:114036] Defined $backlinks as an array before adding entries to it
* [rev:114016] Fixed php tag in !SecurityTokenTest, should be "<?php" not "<?"
* [rev:113984] Installer now writes "!SetEnv HTTP_MOD_REWRITE On" in .htaccess to be consistent with the original .htaccess file that comes with the phpinstaller project
* [rev:113968] Fixed PHP strict standard where non-variables cannot be passed by reference
* [rev:113967] Fixed undefined variable $groupList
* [rev:113964] Re-use variable instead of check temp folder again
* [rev:113956] Make sure that Translatable creates a translated parent of !SiteTree only when the parent is not translated (from r113955)
* [rev:113937] don't trigger notice but Debug::show it
* [rev:113936] don't trigger notice but Debug::show it
* [rev:113933] test doesn't fail anymore due to time differences between db and php. The test now issues notices, warnings and errors depending on the severity of the offset
* [rev:113924] Fixed spaces with tabs in Core
* [rev:113923] Fixed spaces with tabs for Core::getTempFolder()
* [rev:113696] call jquery-ui from thirdparty folder instead google api (see ticket 5915) (from r113656)
* [rev:113695] Typo in !AssetAdmin (fixes #6191, thanks Juanitou)
* [rev:113690] Updated cs_CZ and sk_SK translations in sapphire/javascript (fixes #6085, thanks Pike)
* [rev:113689] Making some !JavaScript strings in cms/javascript translatable, and updated their cs_CZ and sk_SK translations (fixes #6085, thanks Pike)
### Other
* [rev:114464] FIX: Revert last commit
* [rev:114463] FIX: Revert last commit

View File

@ -0,0 +1,23 @@
# 2.4.4-rc2
## Changelog
### Features and Enhancements
* [rev:114901] Allow setting secure session cookies when using SSL. Recent change r114567 made this impossible. (thanks simon_w!) (from r114900)
### Bugfixes
* [rev:115189] Removing form actions from $allowed_actions in !AssetAdmin, CMSMain, !LeftAndMain - handled through Form->httpSubmission() (from r115185)
* [rev:115188] Checking for existence of !FormAction in Form->httpSubmission() to avoid bypassing $allowed_actions definitions in controllers containing this form
* [rev:115188] Checking for $allowed_actions in Form class, through Form->httpSubmission() (from r115182)
* [rev:115169] Fixed conflicting check of mysite directory with recommendation of removal of _config.php in installer
* [rev:114941] #6162 CMSMain::publishall() fails when over 30 pages (thanks natmchugh!) (from r114940)
* [rev:114922] #6219 Director::direct() validation fails for doubly nested file fields (thanks ajshort!) (from r114921)
* [rev:114823] Installer should check asp_tags is disabled, as it can cause issues with !SilverStripe
### Minor changes
* [rev:114916] Ensure php5-required.html template shows correct minimum and recommended PHP versions (thanks mattcleg!) (from r114915)
<code>./sscreatechangelog --version 2.4.4-rc2 --branch branches/2.4 --stopbranch tags/rc/2.4.4-rc1</code>

View File

@ -0,0 +1,41 @@
# 2.4.5-rc1 (2011-01-31)
## Overview
* Enhancement: File->canEdit() and File->canCreate() now use extendedCan()
* Enhancement: Installer check for magic_quotes_gpc (PHP option) and issues a warning if enabled
* Bugfix: CMSMain->rollback() fails because of CSRF protection
* Bugfix: Valid file uploads with uppercase extensions blocked from being web accessible
* Bugfix: Page comments saving onto wrong page
* Bugfix: Incorrect call to weekday function in Date class
* Bugfix: SilverStripeNavigator error in case where page is not published, viewing archived site
## Changelog
### Features and Enhancements
* [rev:115416] Changed canEdit and canCreate extend to extendedCan
* [rev:115265] Installer now checks for magic_quotes_gpc being turned off. This option turned on can cause issues with serialized data in cookies when unserializing (from r115264)
### Bugfixes
* [rev:115816] #6321 Whitelisted file extensions with uppercase extensions blocked by case sensitive FilesMatch directive in assets/.htaccess (does not affect IIS 7.x which uses web.config)
* [rev:115720] transaction function names fixed
* [rev:115460] DateField wrong datepicker-%s.js path (fixes #6296, thanks martijn)
* [rev:115443] Incorrect call to weekday function in Date class (thanks webbower!)
* [rev:115442] Checking for existence of draft and live records in SilverStripeNavigatorItem_ArchiveLink->getHTML() (from r115130)
* [rev:115440] #6291 Remove rollback action from CMSMain allowed_actions and rely on form action_rollback instead which is safer
* [rev:115437] Fixed edge case bug where SilverStripeNavigatorItem would fail if a page was not published, and the navigator archive link was generated
* [rev:115399] #6304 PageCommentInterface::PostCommentForm() loads inappropriate data from cookie, including wrong values for ParentID
* [rev:115379] #6299 TableListField::Link() includes $action value twice (thanks ajshort!)
* [rev:115314] #6287 open_basedir restriction breaks RandomGenerator when trying to read dev/urandom
* [rev:115313] Allowing CMSMain->rollback() outside of form contexts, temporariliy disabling CSRF protection. Necessary in order to get rollback actions working from admin/getversion (regression from 2.4.4 release, see #6291)
### Minor changes
* [rev:115854] #6397 CoreTest should use test specific paths, otherwise conflicts can occur in certain environments
* [rev:115461] Fixed en_US spelling (fixes #6316, thanks sonetseo)
### Other
* [rev:115723] Reverted to revision 101592

View File

@ -0,0 +1,25 @@
# Cache control
By default, PHP add caching headers that make the page appear "purely dynamic".
This isn't usually appropriate for most sites, even ones that are updated reasonably frequently.
In particular, the default PHP cache-control settings prevent sites from appearing in the internet archive.
SilverStripe overrides the default settings with the following:
Default setting:
* The `Last-Modified` date is set to be most recent modification date of any database record queried in the generation of the page.
* The `Expiry` date is set by taking the age of the page and adding that to the current time.
* `Cache-Control` is set to `max-age=86400, must-revalidate`
* Since a visitor cookie is set, the site won't be cached by proxies
* Ajax requests are never cached.
Overriding these defaults
* `[api:HTTP::set_cache_age()]` can be used to set the max-age component of the cache-control line, in seconds.
Set it to 0 to disable caching; the "no-cache" clause in `Cache-Control` and `Pragma` will be included.
* `[api:HTTP::register_modification_date()]` can be used to set the modification date to something more recent than the default.
How it works:
* `[api:DataObject::__construct()]` calls `[api:HTTP::register_modification_date()]` whenever a record comes from the database
* `Controller::run()` calls `[api:HTTP::add_cache_headers()]` before outputting the page

198
docs/en/howto/csv-import.md Normal file
View File

@ -0,0 +1,198 @@
# Import CSV data
## Introduction
CSV import can be easily achieved through PHP's built-in `fgetcsv()` method,
but this method doesn't know anything about your datamodel. In SilverStripe,
this can be handled through the a specialized CSV importer class that can
be customized to fit your data.
## The CsvBulkLoader class
The [api:CsvBulkLoader] class facilitate complex CSV-imports by defining column-mappings and custom converters.
It uses PHP's built-in `fgetcsv()` function to process CSV input, and accepts a file handle as an input.
Feature overview:
* Custom column mapping
* Auto-detection of CSV-header rows
* Duplicate detection based on custom criteria
* Automatic generation of relations based on one or more columns in the CSV-Data
* Definition of custom import methods (e.g. for date conversion or combining multiple columns)
* Optional deletion of existing records if they're not present in the CSV-file
* Results grouped by "imported", "updated" and "deleted"
## Usage
You can use the CsvBulkLoader without subclassing or other customizations, if the column names
in your CSV file match `$db` properties in your dataobject. E.g. a simple import for the
`[api:Member]` class could have this data in a file:
FirstName,LastName,Email
Donald,Duck,donald@disney.com
Daisy,Duck,daisy@disney.com
The loader would be triggered through the `load()` method:
:::php
$loader = new CsvBulkLoader('Member');
$result = $loader->load('<my-file-path>');
By the way, you can import `[api:Member]` and `[api:Group]` data through `http://localhost/admin/security`
interface out of the box.
## Import through ModelAdmin
The simplest way to use [api:CsvBulkLoader] is through a [api:ModelAdmin] interface - you get an upload form out of the box.
:::php
<?php
class PlayerAdmin extends ModelAdmin {
static $managed_models = array(
'Player'
);
static $model_importers = array(
'Player' => 'PlayerCsvBulkLoader',
);
static $url_segment = 'players';
}
?>
The new admin interface will be available under `http://localhost/admin/players`, the import form is located
below the search form on the left.
## Import through a custom controller
You can have more customized logic and interface feedback through a custom controller. Let's create a simple upload form (which is used for `MyDataObject` instances). You can access it through `http://localhost/MyController/?flush=all`.
:::php
<?php
class MyController extends Controller {
protected $template = "BlankPage";
function Link($action = null) {
return Controller::join_links('MyController', $action);
}
function Form() {
$form = new Form(
$this,
'Form',
new FieldSet(
new FileField('CsvFile', false)
),
new FieldSet(
new FormAction('doUpload', 'Upload')
),
new RequiredFields()
);
return $form;
}
function doUpload($data, $form) {
$loader = new CsvBulkLoader('MyDataObject');
$results = $loader->load($_FILES['CsvFile']['tmp_name']);
$messages = array();
if($results->CreatedCount()) $messages[] = sprintf('Imported %d items', $results->CreatedCount());
if($results->UpdatedCount()) $messages[] = sprintf('Updated %d items', $results->UpdatedCount());
if($results->DeletedCount()) $messages[] = sprintf('Deleted %d items', $results->DeletedCount());
if(!$messages) $messages[] = 'No changes';
$form->sessionMessage(implode(', ', $messages), 'good');
return $this->redirectBack();
}
}
Note: This interface is not secured, consider using [api:Permission::check()] to limit the controller to users
with certain access rights.
## Column mapping and relation import
We're going to use our knowledge from the previous example to import a more sophisticated CSV file.
Sample CSV Content
"SpielerNummer","Name","Geburtsdatum","Gruppe"
11,"John Doe",1982-05-12,"FC Bayern"
12,"Jane Johnson", 1982-05-12,"FC Bayern"
13,"Jimmy Dole",,"Schalke 04"
Datamodel for Player
:::php
<?php
class Player extends DataObject {
static $db = array(
'PlayerNumber' => 'Int',
'FirstName' => 'Text',
'LastName' => 'Text',
'Birthday' => 'Date',
);
static $has_one = array(
'Team' => 'FootballTeam'
);
}
?>
Datamodel for FootballTeam:
:::php
<?php
class FootballTeam extends DataObject {
static $db = array(
'Title' => 'Text',
);
static $has_many = array(
'Players' => 'Player'
);
}
?>
Sample implementation of a custom loader. Assumes a CSV-file in a certain format (see below).
* Converts property names
* Splits a combined "Name" fields from the CSV-data into `FirstName` and `Lastname` by a custom importer method
* Avoids duplicate imports by a custom `$duplicateChecks` definition
* Creates `Team` relations automatically based on the `Gruppe` colum in the CSV data
:::php
<?php
class PlayerCsvBulkLoader extends CsvBulkLoader {
public $columnMap = array(
'Number' => 'PlayerNumber',
'Name' => '->importFirstAndLastName',
'Geburtsdatum' => 'Birthday',
'Gruppe' => 'Team.Title',
);
public $duplicateChecks = array(
'SpielerNummer' => 'PlayerNumber'
);
public $relationCallbacks = array(
'Team.Title' => array(
'relationname' => 'Team',
'callback' => 'getTeamByTitle'
)
);
static function importFirstAndLastName(&$obj, $val, $record) {
$parts = explode(' ', $val);
if(count($parts) != 2) return false;
$obj->FirstName = $parts[0];
$obj->LastName = $parts[1];
}
static function getTeamByTitle(&$obj, $val, $record) {
$SQL_val = Convert::raw2sql($val);
return DataObject::get_one(
'FootballTeam', "Title = '{$SQL_val}'"
);
}
}
?>
## Related
* [api:CsvParser]
* [api:ModelAdmin]

View File

@ -0,0 +1,39 @@
# Dynamic Default Values
The [api:DataObject::$defaults] array allows you to specify simple static values to be the default value for when a
record is created, but in many situations default values needs to be dynamically calculated. In order to do this, the
[api:DataObjectSet->populateDefaults()] method will need to be overloaded.
This method is called whenever a new record is instantiated, and you must be sure to call the method on the parent
object!
A simple example is to set a field to the current date and time:
:::php
/**
* Sets the Date field to the current date.
*/
public function populateDefaults() {
$this->Date = date('Y-m-d');
parent::populateDefaults();
}
It's also possible to get the data from any other source, or another object, just by using the usual data retrieval
methods. For example:
:::php
/**
* This method combines the Title of the parent object with the Title of this
* object in the FullTitle field.
*/
public function populateDefaults() {
if($parent = $this->Parent()) {
$this->FullTitle = $parent->Title . ': ' . $this->Title;
} else {
$this->FullTitle = $this->Title;
}
parent::populateDefaults();
}

View File

@ -0,0 +1,142 @@
# Grouping Data Object Sets
The [api:DataObjectSet] class has a number of methods useful for grouping objects by fields. Together with sorting this
can be used to break up long lists of data into more manageable sub-sections.
The [api:DataObjectSet->groupBy()] method takes a field name as the single argument, and breaks the set up into a number
of arrays, where each array contains only objects with the same value of that field. The [api:DataObjectSet->GroupedBy()]
method builds on this and returns the same data in a template-friendly format.
## Grouping Sets By First Letter
This example deals with breaking up a [api:DataObjectSet] into sub-headings by the first letter.
Let's say you have a set of Module objects, each representing a SilverStripe module, and you want to output a list of
these in alphabetical order, with each letter as a heading; something like the following list:
* B
* Blog
* C
* CMS Workflow
* Custom Translations
* D
* Database Plumber
* ...
The first step is to set up the basic data model, along with a method that returns the first letter of the title. This
will be used both for grouping and for the title in the template.
:::php
class Module extends DataObject {
public static $db = array(
'Title' => 'Varchar(255)'
);
// ...
/**
* Returns the first letter of the module title, used for grouping.
*
* @return string
*/
public function getTitleFirstLetter() {
return $this->Title[0];
}
}
The next step is to create a method or variable that will contain/return all the Module objects, sorted by title. For
this example this will be a method on the Page class.
:::php
class Page extends SiteTree {
// ...
/**
* Returns all modules, sorted by their title.
*
* @return DataObjectSet
*/
public function getModules() {
return DataObject::get('Module', null, '"Title"');
}
}
The final step is to render this into a template. The [api:DataObjectSet->GroupedBy()] method breaks up the set into
a number of sets, grouped by the field that is passed as the parameter. In this case, the getTitleFirstLetter method
defined earlier is used to break them up.
:::ss
<h2>Modules</h2>
<% control Modules.GroupedBy(TitleFirstLetter) %>
<h3>$TitleFirstLetter</h3>
<ul>
<% control Children %>
<li>$Title</li>
<% end_control %>
</ul>
<% end_control %>
## Grouping Sets By Month
Grouping a set by month is a very similar process. The only difference would be to sort the records by month name, and
then create a method on the DataObject that returns the month name, and pass that to the [api:DataObjectSet->GroupedBy()]
call.
Again, the first step is to create a method on the class in question that will be displayed in a list. For this example,
a [api:DataObject] called NewsItem will be used. This will have a method which returns the month it was posted in:
:::php
class NewsItem extends DataObject {
public static $db = array(
'Title' => 'Varchar(255)',
'Date' => 'Date'
);
// ...
/**
* Returns the month name this news item was posted in.
*
* @return string
*/
public function getMonthPosted() {
return date('F', strtotime($this->Date));
}
}
The next step is to create a method that will return all the News records that exist, sorted by month name from
January to December. This can be accomplshed by sorting by the Date field:
:::php
class Page extends SiteTree {
/**
* Returns all news items, sorted by the month they were posted
*
* @return DataObjectSet
*/
public function getNewsItems() {
return DataObject::get('NewsItem', null, '"Date"');
}
}
The final step is the render this into the template using the [api:DataObjectSet->GroupedBy()] method.
:::ss
<h2>Modules</h2>
<% control NewsItems.GroupedBy(MonthPosted) %>
<h3>$MonthPosted</h3>
<ul>
<% control Children %>
<li>$Title ($Date.Nice)</li>
<% end_control %>
</ul>
<% end_control %>

18
docs/en/howto/index.md Normal file
View File

@ -0,0 +1,18 @@
# How To Guides
In this section you will find a collection of guides to answer your "How do I?" questions. These are designed to be informal and focused
on tasks and goals rather than going into deep details.
You will find it useful to read the introduction [tutorials](/tutorials) before tackling these How-Tos so you can understand some of
the language and functions which are used in the guides.
* [Import CSV Data](csv-import). Build a simple CSV importer using either ModelAdmin or a custom controller
* [Dynamic Default Fields](dynamic-default-fields). Pre populate a DataObject with data.
* [Grouping DataObjectSets](grouping-dataobjectsets). Group results in a DataObjectSet to create sub sections.
* [PHPUnit Configuration](phpunit-configuration). How to setup your testing environment with PHPUnit
## Feedback
If you have a topic you would like covered in these how to's please ask for it on our [Bug Tracker](http://open.silverstripe.org)

View File

@ -0,0 +1,139 @@
# Configure PHPUnit for your project
This guide helps you to run [PHPUnit](http://phpunit.de) tests in your SilverStripe project.
See "[Testing](/topics/testing)" for an overview on how to create unit tests.
## Executing through "sake dev/tests" or "phpunit"?
Short answer: Both are valid ways.
The `sake` executable that comes with SilverStripe can trigger a customized
"[api:TestRunner]" class that handles the PHPUnit configuration and output formatting.
It's tyically invoked to run all tests through `sake dev/tests/all`,
a single test with `sake dev/tests/MyTestClass`, or tests for a module with `sake dev/tests/module/mymodulename`.
While the custom test runner a handy tool, its also more limited than using `phpunit` directly,
particularly around formatting test output.
The `phpunit` executable uses a SilverStripe bootstrapper to autoload classes,
but handles its own test class retrieval, output formatting and other configuration.
It can format output in common structured formats used by "continuous integration" servers.
If you're using [phpUnderControl](http://phpundercontrol.org/) or a similar tool,
you will most likely need the `--log-junit` and `--coverage-xml` flags that are not available through `sake`.
All command-line arguments are documented on [phpunit.de](http://www.phpunit.de/manual/current/en/textui.html).
## Usage of "phpunit" executable
* `phpunit`: Runs all tests in all folders
* `phpunit sapphire/tests/`: Run all tests of the sapphire module
* `phpunit sapphire/tests/filesystem`: Run all filesystem tests within the sapphire module
* `phpunit sapphire/tests/filesystem/FolderTest.php`: Run a single test
* `phpunit sapphire/tests '' flush=all`: Run tests with optional `$_GET` parameters (you need an empty second argument)
## Coverage reports
* `phpunit --coverage-html assets/coverage-report`: Generate coverage report for the whole project
* `phpunit --coverage-html assets/coverage-report mysite/tests/`: Generate coverage report for the "mysite" module
## Customizing phpunit.xml.dist
The `phpunit` executable can be configured by commandline arguments or through an XML file.
File-based configuration has the advantage of enforcing certain rules across
test executions (e.g. excluding files from code coverage reports), and of course this
information can be version controlled and shared with other team members.
SilverStripe comes with a default `phpunit.xml.dist` that you can use as a starting point.
Copy the file into a new `phpunit.xml` and customize to your needs - PHPUnit will auto-detect
its existence, and prioritize it over the default file.
There's nothing stopping you from creating multiple XML files (see the `--configuration` flag in [PHPUnit documentation](http://www.phpunit.de/manual/current/en/textui.html)).
For example, you could have a `phpunit-unit-tests.xml` and `phpunit-functional-tests.xml` file (see below).
## Running unit and functional tests separately
You can use the filesystem structure of your unit tests to split
different aspects. In the simplest form, you can limit your test exeuction
to a specific directory by passing in a directory argument (`phpunit mymodule/tests`).
To specify multiple directories, you have to use the XML configuration file.
This can be useful to only run certain parts of your project
on continous integration, or produce coverage reports separately
for unit and functional tests.
Example `phpunit-unittests-only.xml`:
<phpunit bootstrap="/sapphire/tests/bootstrap.php" colors="true">
<testsuites>
<testsuite>
<directory>mysite/tests/unit</directory>
<directory>othermodule/tests/unit</directory>
<!-- ... -->
</testsuite>
</testsuites>
<!-- ... -->
</phpunit>
You can run with this XML configuration simply by invoking `phpunit --configuration phpunit-unittests-only.xml`.
The same effect can be achieved with the `--group` argument and some PHPDoc (see [phpunit.de](http://www.phpunit.de/manual/current/en/appendixes.configuration.html#appendixes.configuration.groups)).
## Adding/removing files for code coverage reports
Not all PHP code in your project should be regarded when producing [code coverage reports](http://www.phpunit.de/manual/current/en/code-coverage-analysis.html).
This applies for all thirdparty code
<filter>
<blacklist>
<directory suffix=".php">sapphire/dev/</directory>
<directory suffix=".php">sapphire/thirdparty/</directory>
<directory suffix=".php">cms/thirdparty/</directory>
<!-- Add your custom rules here -->
<directory suffix=".php">mysite/thirdparty/</directory>
</blacklist>
</filter>
See [phpunit.de](http://www.phpunit.de/manual/current/en/appendixes.configuration.html#appendixes.configuration.blacklist-whitelist) for more information.
## Speeding up your test execution with the SQLite3 module
Test execution can easily take a couple of minutes for a full run,
particularly if you have a lot of database write operations.
This is a problem when you're trying to to "[Test Driven Development](http://en.wikipedia.org/wiki/Test-driven_development)".
To speed things up a bit, you can simply use a faster database just for executing tests.
The sapphire database layer makes this relatively easy, most likely
you won't need to adjust any project code or alter SQL statements.
The [SQLite3 module](http://www.silverstripe.org/sqlite-database/) provides an interface
to a very fast database that requires minimal setup and is fully file-based.
It should give you up to 4x speed improvements over running tests in MySQL or other
more "heavy duty" relational databases.
Example `mysite/_config.php`:
// Customized configuration for running with different database settings.
// Ensure this code comes after ConfigureFromEnv.php
if(Director::isDev()) {
if($db = @$_GET['db']) {
global $databaseConfig;
if($db == 'sqlite3') $databaseConfig['type'] = 'SQLite3Database';
}
}
You can either use the database on a single invocation:
phpunit sapphire/tests "" db=sqlite3
or through a `<php>` flag in your `phpunit.xml` (see [Appenix C: "Setting PHP INI settings"](http://www.phpunit.de/manual/current/en/appendixes.configuration.html)):
<phpunit>
<!-- ... -->
<php>
<var name="db" value="sqlite3"/>
</php>
</phpunit>
Note: It is recommended that you still run your tests with the original
database driver (at least on continuous integration) to ensure a realistic test scenario.

63
docs/en/index.md Normal file
View File

@ -0,0 +1,63 @@
This website documents high-level features of the [SilverStripe open source platform](http://www.silverstripe.org), aimed
at developers.
Please read our [guide to contributing documentation](misc/contributing#writing-documentation) if you want to help out!
### Overview
* [Getting started](http://silverstripe.org/getting-started/) | [Feature Overview](http://silverstripe.org/introduction/) | [Demo](http://demo.silverstripe.org/)
* [Download and Installation](installation/) | [Upgrading](/installation/upgrading) | [Requirements](/installation/server-requirements) | [Changelog](http://open.silverstripe.org/wiki/ChangeLog) | [Roadmap](http://open.silverstripe.com/roadmap)
* [API documentation](http://api.silverstripe.org/current) | [Official english book](http://www.silverstripe.org/silverstripe-book) | [Official german book](http://www.silverstripe.org/das-silverstripe-buch)
### Getting support
[Forum](http://www.silverstripe.org/forums/) | [IRC channel](http://silverstripe.org/irc) | [End user docs](http://userhelp.silverstripe.com) | [Core mailinglist](https://groups.google.com/forum/#!forum/silverstripe-dev)
### Level 1: Building your first SilverStripe website
* [Introduction to PHP5 (zend.com)](http://devzone.zend.com/node/view/id/627)
* [Tutorials](tutorials)
* [1. Building a basic site](tutorials/1-building-a-basic-site)
* [2. Extending a basic site](tutorials/2-extending-a-basic-site)
* [3. Forms](tutorials/3-forms)
* [4. Site Search](tutorials/4-site-search)
* [5. Relationships](tutorials/5-dataobject-relationship-management)
* [Common Problems](installation/common-problems)
### Level 2: SilverStripe fundamentals
* [Templates](topics/templates): SilverStripe has its own templating engine
* [Themes](topics/themes): How to customize your site with themes
* [Controllers](topics/controller): Coordination from a URL-request to finding the controller-class
* [Pagetypes](topics/page-types): Clarifying the relationship between a page-object and a silverstripe-class
* [Datamodel](topics/datamodel): Object-relational database model with MVC
* [Database Structure](reference/database-structure): Breakdown of a typical SilverStripe database
* [Datatypes](topics/data-types): Casting database-columns
* [Forms](topics/forms): Sophisticated form generation and processing
* [Formfield Types](reference/form-field-types): Simple and complex form-elements with built-in validation
* [Javascript](topics/javascript)
* [Widgets](topics/widgets)
* [Modules](topics/modules)
* [Configuration](topics/configuration)
### Level 3: The less obvious features
* [Security](topics/security)
* [Email](topics/email)
* [RSS Feeds](reference/rssfeed)
* [Debugging](topics/debugging)
* [Errorhandling](topics/error-handling)
* [Testing Guide](topics/testing/testing-guide): Framework for automated testing like Unittests
* [Built-in Page Controls](reference/built-in-page-controls)
* [Execution Pipeline](reference/execution-pipeline): Tracking a request from director to template-rendering
* [Recipes/Howtos](howto/)
### Level 4: Contributing to the SilverStripe core
* [Contributing](http://www.silverstripe.org/contributing-to-silverstripe/)
* [Coding Conventions](misc/coding-conventions)
<div class="hint" markdown="1">
Looking for the old DokuWiki installation? See [doc.silverstripe.org/old](http://doc.silverstripe.org/old).
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -0,0 +1,67 @@
# Common Problems
From time to time, things will go wrong. Here's a few things to try when you're confused.
See ["8 Common SilverStripe Errors Explain (and solved!) (leftandmain.com)"](http://www.leftandmain.com/silverstripe-tips/2010/09/08/8-common-silverstripe-errors-explained-and-solved/) for more common problems.
## The output shows only "Website Error"
This first and foremost means that your environment is set to "live mode" (see [environment-management]), which disallows detailed error messages for security reasons. You'll typically need to get your environment into "dev mode" to see more information.
If you can log-in to the CMS as an administrator, append `?isDev=1` to any URL to temporarily set your browsing session into "dev mode". If you can't log-in in the first place because of the error, add this directive to your `mysite/_config.php` (don't forget to remove it afterwards!):
:::php
Director::set_environment_type('dev'); // temporary debugging statement
Note: On "live" environments, the `?isDev=1` solution is preferred, as it means that your other visitors don't see ugly
(and potentially security sensitive) PHP errors as well.
## My templates don't update on page refresh
Putting ?flush=1 on the end of any SilverStripe URL will clear out all cached content; this is a pretty common solution
to a lot of development problems. Here are some specifics situations:
* You've created a new SS or PHP file
* You've edited a nested template (one inserted with the `<% include %>` tag)
* You've published a new copy of your site
* You've upgraded your version of SilverStripe
## A SQL query fails with "Column not found" or "Table not found"
Whenever you change the model definitions in PHP (e.g. when adding a property to the [$db](api:DataObject::$db) array,
creating a new page type), SilverStripe will need to update the database. Visiting `http://`<my-domain>`/dev/build` in
your browser runs a script that will check the database schema and update it as necessary. Putting `?flush=1` on the
end makes sure that nothing that's linked to the old database structure will be carried over. If things aren't saving,
pages aren't loading, or other random things aren't working it's possible that the database hasn't been updated to
handle the new code. Here are some specifics situations:
* You've created a new page type / other data object type
* You've change the type of one of your database fields
* You've published a new copy of your site
* You've upgraded your version of SilverStripe
## My edited CMS content doesn't show on the website
If you've set up your site and it used to be working, but now it's suddenly totally broken, you may have forgotten to
publish your draft content. Go to the CMS and use the "publish" button. You can visit `admin/publishall` to publish
every page on the site, if that's easier.
## I can see unparsed PHP output in my browser
Please make sure all code inside '*.php' files is wrapped in classes. Due to the way `[api:ManifestBuilder]`
includes all files with this extension, any **procedural code will be executed on every call**. Most common error here
is putting a test.php/phpinfo.php file in the document root. See [datamodel](/topics/datamodel) and [controllers](/topics/controller)
for ways how to structure your code.
Also, please check that you have PHP enabled on the webserver, and you're at least running PHP 5.1.
The web-based [SilverStripe installer](/installation) can help you with this.
## I've got file permission problems during installation
The php installer needs to be able write files during installation, which should be restricted again afterwards. It
needs to create/have write-access to:
* The main installation directory (for creating .htaccess file and assets directory)
* The mysite folder (to create _config.php)
* After the install, the assets directory is the only directory that needs write access.
* Image thumbnails will not show in the CMS if permission is not given

View File

@ -0,0 +1,45 @@
# Installation from Source Control #
For getting a project up and running with a release, you are typically best off
with the official [silverstripe.org/download](http://silverstripe.org/download). If you want to get the get the "latest and greatest" pre-release code (either
on a release brank, or on "trunk"), you need to use our version control.
We also require you to use this method for any [patch contributions](/misc/contributing),
to ensure you're working on the latest codebase, and the problem you're looking at
is not already fixed.
## SilverStripe Core ##
SilverStripe core is currently hosted on Subversion at [svn.silverstripe.org](http://svn.silverstripe.org).
You can get subversion clients for any operating system, see the [subversion website](http://subversion.tigris.org).
SilverStripe projects are created by combining the "cms" and "sapphire"
modules along with any other modules that your site might need.
These modules are prepackaged in a "phpinstaller" project through [svn:externals](http://svnbook.red-bean.com/en/1.5/svn.advanced.externals.html).
To check out the installer project, use one of the following commands:
# Check out the latest release branch
svn checkout http://svn.silverstripe.org/open/phpinstaller/branches/2.4
# Check out trunk
svn checkout http://svn.silverstripe.org/open/phpinstaller/trunk
<div class="hint" markdown="1">
Please note that you will need Subversion 1.5.0 or greater
</div>
## Other Modules ##
Modules listed on [silverstripe.org/modules](http://silverstripe.org/modules) can be hosted
in any version control system (typically subversion or git). Please read the module
page for source code locations and installation instructions. The general process of
[module installation](/topics/modules) is documented as well.
A good place to start looking for the source code of popular modules are the [github.com/silverstripe](http://github.com/silverstripe)
and [github.com/silverstripe-labs](http://github.com/silverstripe-labs) project pages.
## Related ##
* [Contributing: Submitting patches](/misc/contributing)

View File

@ -0,0 +1,35 @@
# Installing SilverStripe
## Download
SilverStripe is a web application. This means that you will need to have a webserver and database meeting its
[requirements](server-requirements). We will take you through the setup of the server environment as well the application itself.
You can [download](http://silverstripe.org/download) SilverStripe as an archive or from [version control](from-source).
If you already have an installed version of SilverStripe, please see our [upgrading](upgrading) guide.
## Linux/Unix
* [Install using Apache](webserver) - our preferred platform
* [Install using Lighttpd](lighttpd) - fast, but a bit tricker to get going
* [Install using Nginx](nginx) - Super fast at serving static files. Great for large traffic sites.
## Windows
We recommend that you use the free [Microsoft Web Platform installer](windows-pi).
The more technically inclined can [install using IIS](windows-manual-iis) or [install using Apache/WAMP](windows-wamp).
## Mac OS X
Mac OS X comes with a built-in webserver, but you can also use MAMP [install using MAMP](mac-osx) or using MacPorts.
## Troubleshooting
If you run into trouble, see [common-problems](common-problems) or post to the
[SilverStripe forums](http://silverstripe.com/silverstripe-forum/).
## Related
* [Module installation](../topics/modules)
* [Suggested web hosts](http://doc.silverstripe.org/old/suggested-web-hosts)

View File

@ -0,0 +1,87 @@
# Lightttpd
1. Lighttpd works fine so long as you provide a custom config. Add the following to lighttpd.conf **BEFORE** installing
Silverstripe. Replace "yoursite.com" and "/home/yoursite/public_html/" below.
$HTTP["host"] == "yoursite.com" {
server.document-root = "/home/yoursite/public_html/"
# Disable directory listings
dir-listing.activate = "disable"
# Deny access to template files
url.access-deny += ( ".ss" )
static-file.exclude-extensions += ( ".ss" )
# Deny access to Sapphire command-line interface
$HTTP["url"] =~ "^/sapphire/cli-script.php" {
url.access-deny = ( "" )
}
# Disable FastCGI in assets directory (so that PHP files are not executed)
$HTTP["url"] =~ "^/assets/" {
fastcgi.server = ()
}
# Rewrite URLs so they are nicer
url.rewrite-once = (
"^/.*\.[A-Za-z0-9]+.*?$" => "$0",
"^/(.*?)(\?|$)(.*)" => "/sapphire/main.php?url=$1&$3"
)
# Show SilverStripe error page
server.error-handler-404 = "/sapphire/main.php"
}
Rewrite rules do not check for file existence as they do on Apache. There is a ticket about it for Lighttpd:
[http://redmine.lighttpd.net/issues/985](http://redmine.lighttpd.net/issues/985).
2. Extract the SilverStripe software to your lighttpd installation, and run http://yoursite.com/install.php and the
installation should proceed normally.
## Multiple installations of SilverStripe on the same host (www.yourhost.com)
Running multiple installations of Silverstripe on the same host is a bit more tricky, but not impossible. I would
recommend using subdomains instead if you can, for exampe: site1.yourdomain.com and site2.yourdomain.com, it makes
things a lot simpler, as you just use two of the above host example blocks. But if you really must run multiple copies
of Silverstripe on the same host, you can use something like this (be warned, it's quite nasty):
$HTTP["host"] == "yoursite.com" {
url.rewrite-once = (
"(?i)(/copy1/.*\.([A-Za-z0-9]+))(.*?)$" => "$0",
"(?i)(/copy2/.*\.([A-Za-z0-9]+))(.*?)$" => "$0",
"^/copy1/(.*?)(\?|$)(.*)" => "/copy1/sapphire/main.php?url=$1&$3",
"^/copy2/(.*?)(\?|$)(.*)" => "/copy2/sapphire/main.php?url=$1&$3"
)
$HTTP["url"] =~ "^/copy1/" {
server.error-handler-404 = "/copy1/sapphire/main.php"
}
$HTTP["url"] =~ "^/copy2/" {
server.error-handler-404 = "/copy2/sapphire/main.php"
}
}
Note: It doesn't work properly if the directory name copy1 or copy2 on your server has a dot in it, and you then open
the image editor inside admin, I found that out the hard way when using a directory name of silverstripe-v2.2.2 after
directly unzipping the Silverstripe tarball leaving the name as is. I haven't found a solution for that yet, but for now
this method still works properly if you just don't use dots in the directory names.
## Installing lighttpd on Debian
* aptitude install lighttpd *(and php5-cgi, mysql-server, etc, as necessary.)*
* if apache is already running, lighttpd can still be safely installed. It will complain it cannot start because
port 80 is in use. After installing lighttpd, edit /etc/lighttpd/lighttpd.conf and set: "server.port = 81" for example,
and run /etc/init.d/lighttpd restart
* edit /etc/lighttpd/conf-available/10-fastcgi.conf and set socket to: /var/run/lighttpd/php.socket
* enable fastcgi module with /usr/sbin/lighty-enable-mod
* /etc/init.d/lighttpd restart
* You should now be able to view PHP files in your now-working lighttpd server.
* Follow the top instructions on adding the rewrite rules, and then install SilverStripe.
## More about lighttpd
Learn more about the lighttpd webserver at http://www.lighttpd.net/

View File

@ -0,0 +1,37 @@
# Mac OSX
This topic covers setting up your Mac as a Web Server and installing SilverStripe.
While OSX Comes bundled with PHP and Apache (Thanks Apple!) Its not quite ideal for SilverStripe so for setting up a
webserver on OSX we suggest using [MAMP](http://www.mamp.info/en/index.php) or using [MacPorts](http://www.macports.org/)
to manage your packages.
If you want to use the default OSX PHP version then you will need to recompile your own versions of PHP with GD. Providing instructions
for how to recompile PHP is beyond the scope of our documentation but try a online search.
## Installing MAMP
If you have decided to install using MacPorts you can skip this section.
Once you have downloaded and Installed MAMP start the Application and Make sure everything is running by clicking the
MAMP icon. Under `Preferences -> PHP` make sure Version 5 is Selected.
Open up `/Applications/MAMP/conf/PHP5/php.ini` and make the following configuration changes:
memory_limit = 64M
Once you make that change open the MAMP App Again by clicking on the MAMP Icon and click Stop Servers then Start
Servers - this is so our changes to the php.ini take effect.
## Installing SilverStripe
[Download](http://silverstripe.org/download) the latest SilverStripe installer package. Copy the tar.gz file to the 'Document Root' for MAMP - By Default its `/Applications/MAMP/htdocs`.
Don't know what your Document Root is? Open MAMP Click `Preferences -> Apache`.
Extract the tar.gz file to a folder, e.g. `silverstripe/` (you always move the tar.gz file first and not the other way
around as SilverStripe uses a '.htaccess' file which is hidden from OSX so if you move SilverStripe the .htaccess file
won't come along.
Open your web browser and go to `http://localhost:8888/silverstripe/`. Enter your database details - by default with MAMP its user `root` and password `root` and select your account details. Click "Check Details".
Once everything is sorted hit Install! and Voila you have SilverStripe installed

View File

@ -0,0 +1,35 @@
# Nginx
These instructions are also covered on the [Nginx Wiki](http://wiki.nginx.org/SilverStripe)
The prerequisite is that you have already installed Nginx and you are able to run PHP files via the FastCGI-wrapper from
Nginx.
Now you need to setup a virtual host in Nginx with the following configuration settings:
server {
listen 80;
server_name yoursite.com;
root /home/yoursite.com/httpdocs;
index index.html index.php;
if (!-f $request_filename) {
rewrite ^/(.*?)(\?|$)(.*)$ /sapphire/main.php?url=$1&$3 last;
}
error_page 404 /sapphire/main.php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/yoursite.com/httpdocs$fastcgi_script_name;
include fastcgi_params;
}
}
The above configuration will setup a new virtual host `yoursite.com` with rewrite rules suited for SilverStripe. The
location block at the bottom will pass all php scripts to the FastCGI-wrapper.
Now you can proceed with the SilverStripe installation normally.

View File

@ -0,0 +1,49 @@
# Requirements
SilverStripe CMS needs to be installed on a web server. Content authors and website administrators use their web browser to access a web-based GUI to
do their day-to-day work. Website designers and developers require access to the files on the server to update templates,
website logic, and perform upgrades or maintainance.
Our web-based [PHP installer](/installation) can check if you meet the requirements listed below.
## Web server software requirements
* PHP 5.2.0+
* We recommend using a PHP accelerator or opcode cache, such as [xcache](http://xcache.lighttpd.net/) or [WinCache](http://www.iis.net/download/wincacheforphp).
* Allocate at least 48MB of memory to each PHP process. (SilverStripe can be resource hungry for some intensive operations.)
* Required modules: dom, gd2, hash, iconv, mbstring, mysql (or other database driver), session, simplexml, tokenizer, xml.
* Recommended configuration
safe_mode = Off
magic_quotes_gpc = Off
memory_limit = 48M
* See [phpinfo()](http://php.net/manual/en/function.phpinfo.php) for more information about your environment
* One of the following databases:
* MySQL 5.0+
* PostgreSQL 8.3+ (requires ["postgresql" module](http://silverstripe.org/postgresql-module))
* SQL Server 2008. (requires ["mssql" module](http://silverstripe.org/microsoft-sql-server-database/))
* Support for [Oracle](http://www.silverstripe.org/oracle-database-module/) and [SQLite](http://silverstripe.org/sqlite-database/) is not commercially supported, but is under development by our open source community.
* One of the following web server products:
* Apache 1.3+ with mod_rewrite and "AllowOverride All" set
* IIS 5.x+ (Version 7.5+ and URL Rewrite Module recommended)
* Support for Lighttpd and other webservers may work if you are familiar with configuring those products.
* We recommend enabling content compression (for example with mod_deflate) to speed up the delivery of HTML, CSS, and JavaScript.
* One of the following operating systems:
* Linux/Unix/BSD
* Microsoft Windows XP SP3, Vista, Windows 7, Server 2008, Server 2008 R2
* Mac OS X 10.4+
## Web server hardware requirements
Hardware requirements vary widely depending on the traffic to your website, the complexity its logic (i.e., PHP), and its size (i.e., database.) By default, all pages are dynamic, and thus access both the database and execute PHP code to generate. SilverStripe can cache full pages and segments of templates to dramatically increase performance.
A typical website page on a conservative single CPU machine (e.g., Intel 2Ghz) takes roughly 300ms to generate. This comfortably allows over a million page views per month. Caching and other optimisations can improve this by a factor of ten or even one hundred times. SilverStripe CMS can be used in multiple-server architectures to improve scalability and redunancy.
## Client side (CMS) requirements
SilverStripe CMS is designed to work well with Firefox 3.0+ and Internet Explorer 7.0+. We aim to provide satisfactory experiences in Apple Safari and Google Chrome. SilverStripe CMS works well across Windows, Linux, and Mac operating systems.
## End user requirements ##
SilverStripe CMS is designed to make excellent, standards-compliant websites that are compatible with a wide range of industry standard browsers and operating systems. A competent developer is able to produce websites that meet W3C guidelines for HTML, CSS, JavaScript, and accessibility, in addition to meeting specific guildelines, such as e-government requirements.

View File

@ -0,0 +1,40 @@
# Upgrading
Usually an update or upgrade your SilverStripe installation just means overwriting files and updating your
database-schema. Please see your [upgrade notes and changelogs](/changelogs).
## Process
Never update a website on the live server without trying it on a development copy first.
* Check if any modules (e.g. blog or forum) in your installation are compatible and need to be upgraded as well
* Backup your database
* Backup your website
* Download the new release and uncompress it to a temporary folder
* Leave custom folders like *mysite* or *themes* in place.
* Identify system folders in your webroot (`cms`, `sapphire` and any additional modules).
* Delete existing system folders (or move them outside of your webroot)
* Extract and replace system folders from your download (//Deleting instead of "copying over" existing folders
ensures that files removed from the new SilverStripe release are not persisting in your installation//)
* Visit http://yoursite.com/dev/build/?flush=1 to rebuild the website Database
* Check if you need to adapt your code to changed APIs
* Check if you need to adapt your code to changed CSS/HTML/JS
* See [common-problems](common-problems) for a list of likely mistakes that could happen during an upgrade.
## Decision Helpers
How easy will it be to update my project? It's a fair question, and sometimes a difficult one to answer. This page is
intended to help you work out how hard it will be to upgrade your site.
* If you've made custom branches of the core, or of a module, it's going to be harder to upgrade.
* The more custom features you have, the harder it will be to upgrade. You will have to re-test all of those features
and some of them may have broken.
* Customisations of a well defined type - such as custom page types or custom blog widgets - are going to be easier to
upgrade than customisations that use sneaky tricks, such as the subsites module.
## Related
* [Release Announcements](http://groups.google.com/group/silverstripe-announce/)
* [Blog posts about releases on silverstripe.org](http://silverstripe.org/blog/tag/release)

View File

@ -0,0 +1,29 @@
# Generic Webserver Installation
These instructions show you how to install SilverStripe on any web server.
For additional information about installing SilverStripe on specific operation systems, refer to:
* [Installation on a Windows Server](windows-pi.md)
* [Installation on OSX](mac-osx)
## Installation Steps
* [Download](http://silverstripe.org/download) the installer package
* Make sure the webserver has MySQL and PHP support. See [Server Requirements](server-requirements) for more
information.
* Unpack the installer somewhere into your web-root. Usually the www folder or similar. Most downloads from SilverStripe
are compressed tarballs. To extract these files you can either do them natively (Unix) or with 7-Zip (Windows)
* Visit your sites Domain or IP Address in your web browser.
* You will be presented with a form where you enter your MySQL login details and are asked to give your site a 'project
name' and the default login details. Follow the questions and select the *install* button at the bottom of the page.
* After a couple of minutes, your site will be set up. Visit your site and enjoy!
## Issues?
If the above steps don't work for any reason have a read of the [Common Problems](common-problems) section.

View File

@ -0,0 +1,150 @@
# Install SilverStripe manually on Windows using IIS 6
How to prepare Windows Server 2003 for SilverStripe using IIS 6 and FastCGI.
This guide will work for the following operating systems:
* Windows Server 2003
* Windows Server 2003 R2
Database install and configuration is not covered here, it is assumed you will do this yourself.
PHP comes with MySQL support out of the box, but you will need to install the [SQL Server Driver for PHP](http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=80e44913-24b4-4113-8807-caae6cf2ca05)
from Microsoft if you want to use SQL Server.
## Preparation
Open **Windows Update** and make sure everything is updated, including optional updates. It is important that all .NET Framework updates including service packs are installed.
## Install IIS
- Open **Control Panel** > **Add/Remove Programs**
- Click **Add/Remove Windows Components** on the left hand bar
- Check **Application Server** and then click **Next** to install it
## Install FastCGI for IIS
- Download and install this package: http://www.iis.net/download/fastcgi
- Open **inetmgr.exe**
- Right click **Web Sites** and go to **Properties**
- Click the **Home Directory** tab
- Click **Configuration...** then **Add**
- In the **Add/Edit Extension Mapping** dialog, click **Browse...** and navigate to fcgiext.dll which is located in %windir%\system32\inetsrv
- In the **Extension** text box, enter **.php**
- Under **Verbs** in the **Limit to** text box, enter **GET,HEAD,POST**
- Ensure that the **Script engine** and **Verify that file exists** boxes are checked then click **OK**
- Open fcgiext.ini located in %windir%\system32\inetsrv. In the [Types] section of the file, add **php=PHP**
- Create a new section called **[PHP]** at the bottom of the file, like this:
[PHP]
ExePath=c:\php5\php-cgi.exe
Finally, run these commands in **Command Prompt**
cd %windir%\system32\inetsrv
cscript fcgiconfig.js -set -section:"PHP" -InstanceMaxRequests:10000
cscript fcgiconfig.js -set -section:"PHP" -EnvironmentVars:PHP_FCGI_MAX_REQUESTS:10000
cscript fcgiconfig.js -set -section:"PHP" -ActivityTimeout:300
## Install PHP
- [Download PHP](http://windows.php.net/download) (**Zip** link underneath the **VC9 x86 Non Thread Safe** section)
- [Download WinCache](http://www.iis.net/download/WinCacheForPHP) (**WinCache 1.1 for PHP 5.3**)
- Extract the PHP zip contents to **c:\php5**
- Run the WinCache self-extractor and extract to **c:\php5\ext**. A file called **php_wincache.dll** should now reside in **c:\php5\ext**
- Rename **php.ini-development** to **php.ini** in **c:\php5**
- Open **php.ini**, located in **c:\php5** with **Notepad** or another editor like **Notepad++**
- Search for **date.timezone**, uncomment it by removing the semicolon and set a timezone from here: http://php.net/manual/en/timezones.php
- Search for **fastcgi.impersonate**, uncomment it by removing the semicolon and set it like this: **fastcgi.impersonate = 1**
- Search for **cgi.fix_pathinfo**, uncomment it by removing the semicolon and set it like this: **cgi.fix_pathinfo = 1**
- Search for **cgi.force_redirect**, uncomment it by removing the semicolon and set it like this: **cgi.force_redirect = 0**
- Search for **fastcgi.logging**, uncomment it by removing the semicolon and set it like this: **fastcgi.logging = 0**
- Search for **extension_dir** and make sure it looks like this: **extension_dir = "ext"** (use proper double quotation characters here)
- Find the "Dynamic Extensions" part of the file, and replace all extension entries with the following:
;extension=php_bz2.dll
extension=php_curl.dll
;extension=php_enchant.dll
;extension=php_exif.dll
;extension=php_fileinfo.dll
extension=php_gd2.dll
;extension=php_gettext.dll
;extension=php_gmp.dll
;extension=php_imap.dll
;extension=php_intl.dll
;extension=php_ldap.dll
extension=php_mbstring.dll
extension=php_mysql.dll
extension=php_mysqli.dll
;extension=php_oci8.dll
;extension=php_oci8_11g.dll
;extension=php_openssl.dll
;extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
;extension=php_pdo_odbc.dll
;extension=php_pdo_pgsql.dll
;extension=php_pdo_sqlite.dll
;extension=php_pgsql.dll
;extension=php_shmop.dll
;extension=php_snmp.dll
;extension=php_soap.dll
;extension=php_sockets.dll
;extension=php_sqlite3.dll
;extension=php_sqlite.dll
extension=php_tidy.dll
extension=php_wincache.dll
;extension=php_xmlrpc.dll
;extension=php_xsl.dll
This is a minimal set of loaded extensions which will get you started.
If want to use **SQL Server** as a database, you will need to install the [SQL Server Driver for PHP](http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=80e44913-24b4-4113-8807-caae6cf2ca05) and add an extension entry for it to the list above.
## Test PHP
- Open **Command Prompt** and type the following:
c:\php5\php.exe -v
You should see some output showing the PHP version. If you get something else, or nothing at all, then there are missing updates for your copy of Windows Server 2003. Open **Windows Update** and make sure you've updated everything including optional updates.
## Install SilverStripe
- [Download SilverStripe](http://silverstripe.org/downloads)
- Extract the download contents to **C:\Inetpub\wwwroot\silverstripe**
- Open **inetmgr.exe**
- Right click **Web Sites** and go to **New** > **Web Site**
- Fill in all appropriate details. If you enter **(All Unassigned)** for the IP address field, make sure the port is something other than **80**, as this will conflict with "Default Web Site" in IIS. When asked for path, enter **C:\Inetpub\wwwroot\silverstripe**
- Browse to **http://localhost:8888** or to the IP address you just assigned in your browser.
An installation screen should appear. There may be some permission problems, which you should be able to correct by assigning the **Users** group write permissions by right clicking files / folders in Windows Explorer and going to **Properties** then the **Security** tab.
When ready, hit **Install SilverStripe**.
SilverStripe should now be installed and you should have a basic site with three pages.
However, URLs will not look "nice", like this: http://localhost/index.php/about-us. In order to fix this problem, we need to install a third-party URL rewriting tool, as IIS 6 does not support this natively.
Proceed to **Install IIRF** below to enable nice URLs.
## Install IIRF
At the moment, all URLs will have index.php in them. This is because IIS does not support URL rewriting. To make this work, we need to install IIRF which is a third-party plugin for IIS.
- [Download IIRF](http://iirf.codeplex.com/releases/view/36814) and install it
- Create a new file called iirf.ini in C:\inetpub\wwwroot\silverstripe with this content
RewriteEngine On
MaxMatchCount 10
IterationLimit 5
# URLs with query strings
# Don't catch successful file references
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)\?(.+)$ /sapphire/main.php?url=$1&$2
# URLs without query strings
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /sapphire/main.php?url=$1
Friendly URLs should now be working when you browse to your site.
Remember that IIRF works on a per-virtual host basis. This means for each site you want IIRF to work for, you need to add a new entry to **Web Sites** in **inetmgr.exe**.
Thanks to **kcd** for the rules: [http://www.silverstripe.org/installing-silverstripe/show/10488#post294415](http://www.silverstripe.org/installing-silverstripe/show/10488#post294415)

View File

@ -0,0 +1,395 @@
# Install SilverStripe manually on Windows using IIS 7
This guide will step you through installing SilverStripe on Windows using IIS 7.x as the web server and SQL Server 2008 R2 as the database.
You can use this guide to install SilverStripe on the following:
* Windows Server 2008 or Windows Vista with Service Pack 2 installed
* Windows Server 2008 R2 or Windows 7
These versions of Windows will **NOT** work with this guide:
* Windows Server 2003
* Windows XP
**IMPORTANT**: Windows Server 2003 users should [follow this guide](http://doc.silverstripe.org/installation-on-windows-server-2003-iis-6) to installing SilverStripe.
The goal is to get a good working web server platform so that one or more SilverStripe projects can be easily deployed onto the server using SVN.
We'll also install SQL Server 2008 R2, and support for connecting to it in PHP.
## Requirements
* Windows Server 2008 or Windows Vista with Service Pack 2 installed
* Windows Server 2008 R2 or Windows 7
## Software to install
* Internet Information Services (IIS) 7.x
* SQL Server 2008 R2
* PHP 5.3
* SilverStripe 2.4
* [Microsoft URL Rewrite Module 2.0](http://www.iis.net/download/URLRewrite)
* [IIS 7 Administration Pack](http://www.iis.net/download/AdministrationPack) (ONLY required for Windows Vista or Server 2008)
* [Microsoft Drivers for PHP for SQL Server 2.0](http://www.microsoft.com/downloads/en/details.aspx?FamilyID=80E44913-24B4-4113-8807-CAAE6CF2CA05&displaylang=en)
## Install IIS
IIS 7.x comes with Windows. However, it needs to be installed. Follow these steps:
* Go to Start > Control Panel > Programs and Features
* Click **Turn Windows features on or off**. You'll find this under Tasks as a quick link
* Click **Add Roles** under the Roles Summary section when Server Manager opens
* Click Next >
* Check **Web Server (IIS)** (if a popup appears, confirm you want to proceed with the change)
* Click Next >
* Check CGI in the list - you'll find find it under Application Development
* Scroll down and check IIS Management Scripts and Tools
* OPTIONAL: For remote management capability, check Management Service
**NOTE**: These instructions are slightly different for Windows Vista and Windows 7. Instead of a Server Manager popup, you'll just get a list of features to enable. Do the same as above except click the **Internet Information Services** checkbox when the Windows Features popup appears and then expand this node and select **CGI** under World Wide Web Services > Application Development Features.
Once the installation is finished, browse to http://localhost in your browser. If an image pops up, then IIS has been installed correctly.
## IIS URL Rewrite Module
* Go to http://www.iis.net/extensions/URLRewrite
* Click x86 or x64 on the right, depending on whether you installed a x86 or x64 version of Windows
* Run the downloaded file to install and enable the URL Rewrite Module
## IIS Administration Pack
**NOTE**: Windows Server 2008 R2 or Windows 7 (IIS 7.5) users can skip this step, as it's already installed!
* [Download IIS Administration Pack](http://www.iis.net/extensions/AdministrationPack)
* Run the downloaded file to enable the IIS Administration Pack (make sure it's x86 or x64 depending on your Windows version)
## Install SQL Server 2008 R2
SQL Server doesn't come with Windows. It must be separately installed.
You can use any version of SQL Server 2008 R2 or SQL Server 2008 with the latest service pack.
If you don't have a license, there's always [SQL Server 2008 R2 Express](http://www.microsoft.com/express/database/) which is feature complete, but restricted to 10GB per database.
Ensure these features are installed with your copy of SQL Server.
* SQL Server Replication
* Full-Text Search
* Management Tools
Installing SQL Server should be relatively straightforward. Keep a note of the password you create for the "sa" user. We'll need this for later when we connect to the database server via PHP to test connectivity.
## Install PHP
From http://windows.php.net/download, pick **VC9 x86 Non Thread Safe** of the latest PHP version and click "Installer" to download the PHP installer.
**NOTE**: We chose the "Non Thread Safe" version because we'll run PHP as a FastCGI process through IIS. FastCGI ensures a single threaded execution environment so thread safety checks are not required. This provides significant performance gains over using the thread safe version of PHP.
Once finished downloading, run the installer to get PHP up and running.
When prompted, select **IIS FastCGI** for the web server setup. When asked for which items to install, expand the Extensions tree and check **LDAP** and **Multi-Byte String**. You'll probably need one or both of these in the future, so it's a safe option to install them. LDAP is required for retrieving data from an Active Directory server, for example.
Now we need to set up Handler Mappings in IIS to support PHP scripts.
Open up Internet Information Services (IIS) Manager and click on the second node that appears on the tree to the left.
* Click Handler Mappings
**NOTE**: If you already see an entry for PHP, continue to "Configure FastCGI in IIS" below.
* Click Add Module Mapping located on the right hand Actions bar
* Enter ***.php** into the Request path field
* Select FastCGIModule from the Module dropdown menu
* Enter **"C:\Program Files (x86)\PHP\php-cgi.exe"** (including the quotes) into the Executable (optional) field
* Enter **PHP** into the Name field
You can also do the same via the command line. Run these commands if you prefer to do it the CLI way:
C:\windows\system32\inetsrv\appcmd set config /section:system.webServer/fastCGI /+[fullPath='"c:\Program Files (x86)\PHP\php-cgi.exe"']
C:\windows\system32\inetsrv\appcmd set config /section:system.webServer/handlers /+[name='PHP_via_FastCGI',path='*.php',verb='*',modules='FastCgiModule',scriptProcessor='"c:\Program Files (x86)\PHP\php-cgi.exe"',resourceType='Unspecified']
## Configure FastCGI in IIS
There's some best practice configuration we need to apply to FastCGI so that our websites will run optimally.
* Click FastCGI Settings in the IIS Manager
* Click the PHP entry that appears in the list, and click Edit in the right hand Actions panel
* Look for InstanceMaxRequests and change the value to **10000**
* Look for ActivityTimeout and change the value to **900**
* Look for RequestTimeout and change the value to **900**
* Click the (Collection) field and press the ... button that appears to the right
* Click Add when the dialog box appears
* On the right, enter **PHP_FCGI_MAX_REQUESTS** for the entry to the Name field
* On the right, enter **10000** for the entry to the Value field
Again, like adding the handler mappings, the same procedures can be done using the command line:
C:\windows\system32\inetsrv\appcmd set config -section:system.webServer/fastCgi /[fullPath='"c:\Program Files (x86)\PHP\php-cgi.exe"'].instanceMaxRequests:10000
C:\windows\system32\inetsrv\appcmd set config -section:system.webServer/fastCgi /[fullPath='"c:\Program Files (x86)\PHP\php-cgi.exe"'].ActivityTimeout:900
C:\windows\system32\inetsrv\appcmd set config -section:system.webServer/fastCgi /[fullPath='"c:\Program Files (x86)\PHP\php-cgi.exe"'].RequestTimeout:900
C:\windows\system32\inetsrv\appcmd set config -section:system.webServer/fastCgi /+"[fullPath='"c:\Program Files (x86)\PHP\php-cgi.exe'].environmentVariables.[name='PHP_FCGI_MAX_REQUESTS',value='10000']"
The [official guide configuring IIS for PHP applications is available](http://learn.iis.net/page.aspx/771/configure-and-optimize-the-microsoft-web-platform-for-php-applications/) for reference.
## Add index.php as default document
This is good practise, so if you browse to http://localhost/silverstripe then it will automatically run index.php. IIS needs to be told which default documents should be checked for when accessing a directory in the URL.
To add index.php as a default document:
* Open Internet Information Services (IIS) Manager
* Click your server name on the left when the program opens
* Double click the **Default Document** icon
* Verify that index.php doesn't already exist in the file list
* Click **Add** on the right sidebar to add a new entry
* Enter **index.php** when the dialog box pops up and hit **OK**
## Install the SQL Server Driver for PHP
The following steps will install the SQL Server Driver for PHP from Microsoft:
* Download [Microsoft Drivers for PHP for SQL Server (2.0)](http://www.microsoft.com/downloads/en/details.aspx?FamilyID=80E44913-24B4-4113-8807-CAAE6CF2CA05&displaylang=en)
* Run the downloaded file, extracting to C:\sqlsrv
* In Windows Explorer, browse to C:\sqlsrv - you should see a bunch of DLL files
* Copy **php_sqlsrv_53_nts_vc9.dll** to C:\Program Files (x86)\PHP\ext
* Open C:\Program Files (x86)\PHP\php.ini using Notepad
At the bottom of the file, add this line: **extension=php_sqlsrv_53_nts_vc9.dll**
## Configure PHP
PHP is installed and works with IIS, but the configuration needs a bit of minor tweaking.
Open Windows Explorer. Browse to C:\Program Files (x86)\PHP and open php.ini.
Note: You may need to run Notepad as administrator (right click Notepad.exe and click "Run as administrator"). From inside Notepad, open C:\Program Files (x86)\PHP\php.ini.
First of all, look for **;date.timezone** and replace it with this one (replacing Pacific/Auckland to your timezone if you're not in New Zealand).
date.timezone = Pacific/Auckland
Secondly, look for **display_errors** and **display_startup_errors**. Replace the Off value for each of these with **On**.
Thirdly, PHP has a very low maximum file size of 2 megabytes for file uploads. Look for **post_max_size**, and **upload_max_filesize**. Change 2M and 8M respectively, to **128M**. This is important to allow large uploads from users, such as video. If you feel you don't require as much, change it to **64M** for both, which is a sensible limit.
Again, look for **max_input_time**. Replace the 60 value with **900**. The reason we're doing this is to match the 900 value we set earlier in IIS.
Lastly, there's one FastCGI setting we need to apply, and it's missing in the configuration by default. Look for **fastcgi.impersonate=1** and add this line below it:
cgi.fix_pathinfo=1
SilverStripe sites will email errors to developers which are crucial for debugging. It's also needed for any emails generated by the website. PHP needs to know where your SMTP server is located, and which port it listens on to be able to send emails.
In php.ini, look for this block of code:
[mail function]
; For Win32 only.
; http://php.net/smtp
SMTP = localhost
; http://php.net/smtp-port
smtp_port = 25
Make sure that the SMTP and smtp_port are set to your mail server's hostname and port respectively.
That should do it for the PHP configuration.
## Test PHP installation
Now that we've got PHP configured how we want it, let's test that PHP is working correctly.
First things first, restart IIS using IIS Manager.
Create a new file using Notepad called test.php if you haven't already, inside **C:\inetpub\wwwroot**
Inside the file, add this content:
<?php
phpinfo();
Open a browser and point it to http://localhost/test.php
You should receive a long page containing PHP configuration information. If you do receive this, PHP has been installed correctly through IIS. Congratulations!
The next part is to install SilverStripe and verify that it works.
## Install SilverStripe
Now that we've got the backend server architecture sorted out, it's time to install the SilverStripe CMS/framework.
Create a new file called **_ss_environment.php** in **C:\inetpub\wwwroot**
This file tells SilverStripe projects installed on this machine which database server and credentials, as well as anything environment specific. [[environment-management|More information]] on setting up the environment file is available.
Inside the newly created _ss_environment.php file, insert the following code:
<?php
/* What kind of environment is this: development, test, or live (ie, production)? */
define('SS_ENVIRONMENT_TYPE', 'dev');
/* Database connection */
define('SS_DATABASE_SERVER', 'localhost');
define('SS_DATABASE_USERNAME', 'sa');
define('SS_DATABASE_PASSWORD', '');
/* Configure a default username and password to access the CMS on all sites in this environment */
define('SS_DEFAULT_ADMIN_USERNAME', 'username');
define('SS_DEFAULT_ADMIN_PASSWORD', 'password');
Insert the password you created for SQL Server earlier into the **SS_DATABASE_PASSWORD** field that is currently empty.
To install SilverStripe, we're going to use TortoiseSVN so you can check out the code directly from the SilverStripe SVN repository. This is easier than unzipping and moving around files, and any code updates can be pulled in by running "SVN update" from TortoiseSVN.
First of all, install a copy of TortoiseSVN and then follow these steps:
* In Windows Explorer, browse to your desktop
* Right click anywhere inside this folder to bring up a context menu and click SVN Checkout
* Enter http://svn.silverstripe.com/open/phpinstaller/branches/2.4 into the URL of repository field
* Click OK
* Click Yes when warned of creating a new directory
* Drag the newly created folder to **C:\inetpub\wwwroot** (you'll be asked for admin permissions to do this)
## Install the SilverStripe SQL Server module ("mssql")
* In Windows Explorer, browse to your desktop
* Right click anywhere inside this folder to bring up a context menu and click SVN Checkout
* Enter http://svn.silverstripe.com/open/modules/mssql/trunk into the URL of repository field
* Click OK
* Move the newly created mssql directory into the ss24 directory inside **C:\inetpub\wwwroot** (you'll be asked for admin permissions to do this)
## Start SilverStripe installer
Open a browser and point it to http://localhost/ss24
If an installation screen shows up, congratulations! We're very close now.
Fill out the details correctly and press "Install SilverStripe".
If all goes to plan, you're done, and you should see a basic template with a few sample pages.
## Windows Cache Extension "wincache" for PHP
Microsoft has developed an extension for PHP specifically for Windows. This is designed to work similar to xcache by caching PHP code in bytecode memory for peformance improvements. It's recommended you install this for optimal PHP performance.
To install it, follow these steps:
* [Download WinCache](http://www.iis.net/extensions/WinCacheForPHP) (x86 PHP 5.3 link is on the right sidebar of the above page)
* Extract the files to a temporary location like C:\wincache
* Copy the php_wincache.dll file into the ext directory inside C:\Program Files (x86)\PHP
Edit php.ini and add the following line at the bottom of the file:
extension=php_wincache.dll
* Copy wincache.php into C:\inetpub\wwwroot
* Edit the wincache.php file you just copied, and look for the wincache username and password
* Replace wincache inside the file with your own username and password
* Restart IIS
Now that it's installed, all your PHP scripts should be executed considerably faster.
To check if it's installed, have a look at the phpinfo() output and look for wincache.
To examine how it's being cached, visit http://localhost/wincache.php and enter the login details you set up above. This page will show you which files are currently cached and some basic reports of how the module is operating.
## Configuring PHP and IIS for production environments
**TODO**: Describe turning off PHP errors, and setting up static 404 and 500 error pages instead of giving detailed errors. Finally setting up a specific database user that isn't sa with restricted permissions.
## Troubleshooting
**Q: How do I debug the IIS 500 Server error "The FastCGI process exited unexpectedly"?**
**A:** This is a very annoying error - basically it means PHP has caused a segmentation fault, probably through itself or one of it's extensions. It's very hard to track down exactly why these errors occur, but there's a few things you can do.
Most of the time, it's caused by a loaded PHP extension that is broken.
* Have you set up the MSSQL database details correctly in _ss_environment.php?
* Have you made IIS expose errors? (see "How do I make IIS expose errors..." below)
* Are you running non-standard PHP extensions? If so, try unloading them one by one
* Make sure you're using the latest [[http://www.microsoft.com/downloads/en/details.aspx?FamilyID=80E44913-24B4-4113-8807-CAAE6CF2CA05&displaylang=en/|Microsoft Drivers for PHP for SQL Server]]
**Q: I get the error "HTTP Error 500.0 - Internal Server Error - C:\Program Files (x86)\PHP\php-cgi.exe - The FastCGI process exceeded configured request timeout"**
**A:** A script is running for a long time, such as a unit test. To fix this, you'll need to increase the request timeout to a higher value in both IIS and PHP. Refer to the IIS FastCGI configuration documentation and PHP configuration parts of this document for where to change the appropriate values.
**Q: I cannot access SQL Server from a remote server, such as a development environment**
**A:** This is because the firewall settings on the server hosting SQL Server 2008 are too strict - you need to tweak the firewall to accept incoming connections.
Do the following to open a firewall port:
* In Control Panel, open Windows Firewall
* Click Allow a program through Windows Firewall
* Click the Exceptions tab, and then click Add Port
* In the Add a Port dialog box, in the Name field, enter SQL Server
* In the Port number box, type the port number of the instance of the Database Engine, such as 1433 for the default instance
* Verify that **TCP** is selected, and then click OK
To open the port to expose the SQL Server Browser service, click Add Port, type SQL Server Browser in the Name text box, type **1434** in the Port Number text box, select **UDP**, and then click OK
And then verify TCP/IP access is enabled:
* Open SQL Server Configuration Manager
* In the node "Protocols for MSSQLSERVER" (or for your instance name) verify TCP/IP is **Enabled**
* Restart SQL Server if protocol changes were made
**Q: When I try running the unit tests, I get this error: "Uncaught Zend_Cache_Exception: cache_dir is not writable"**
**A:** Sometimes you can't access the TEMP folder because the current user doesn't have permission.
The solution is to create a **silverstripe-cache** directory in your project directory. For example, inside **C:\inetpub\wwwroot\silverstripe**. Do the following:
* Create a **silverstripe-cache** directory in the directory where you installed SilverStripe
* Right click the newly created directory, and select the Security tab
* Click the Edit button
* Click the Users item in the list, and then click the Modify checkbox
* Click Apply - accept the warning that is given
* Click OK
NOTE: When **fastcgi.impersonate = 1** is set in php.ini, the current user logged in on the domain will be the user the web server runs PHP scripts under e.g "sharvey" if Windows Authentication is enabled. If nobody is logged in, and someone accesses the site anonymously, the web server will run under the "IUSR" credentials.
To find out who the current user is, try echoing the result of get_current_user() inside a test php script.
**Q: When I try to access my SilverStripe site for the first time, I get a 404 error**
**A:** Try accessing dev/build?username=admin&password=password at the end of the URL you requested. For example, http://localhost/ss24/dev/build?username=admin&password=password. This will ensure the database is built properly
**Q: How do I make IIS expose errors instead of giving a generic 500 or 404 page?**
**A:** In IIS manager, double click Error Pages for the top level server node on the left. You'll be presented with a list of status codes, and a path to the error page. To show detailed errors remotely AND locally, click Edit Feature Settings on the right panel under Actions. From the dialog box that pops up, select Detailed errors. Restart IIS for the changes to take effect. This also means that from now on, the custom error pages SilverStripe generate will be used instead of the default IIS one.
Also, make sure that display_errors, display_startup_errors and html_errors in are set to On in php.ini.
**Q: I get a 500 server error when trying to access the SilverStripe site. e.g. http://localhost/ss24**
**A:** One of the reasons why this could be happening is the web.config file inside the ss24 directory has XML that is not well formed. Make sure there are NO spaces before the starting <?xml> tag, and make sure that everything is tabbed out correctly.
One other thing you can do is make sure Show friendly HTTP error messages is unchecked in Internet Explorer. You can find this in Tools > Internet Options > Advanced.
Make sure errors are exposed by following the troubleshooting question above "How do I make IIS expose errors..."
If this still doesn't help, enable Failed Request Tracing in IIS. You could also try using DebugView, a useful debugging tool for Windows.
**Q: I get an error about SQL Server Driver for PHP requiring "SQL Server 2008 Native Client ODBC Driver (SP1 or later)"**
**A:** If you're accessing a SQL Server database that's on another server, you need to install SQL Server 2008 Native Client on the client web server that accesses the external database server.
**Q: When I try to load the CMS, the SilverStripe logo stays there and the CMS doesn't load.**
**A:** Make sure the assets directory exists, and is writable by the web server. This happens on test/live mode because SilverStripe will try to combine the javascript files, and put them in the assets directory. If it's not writable, or doesn't exist, then the CMS will fail to load.
**Q: Performance of SilverStripe is slow on Windows.**
**A:** A non-thread safe of PHP is recommended for use with IIS. Thread safety checks are not required, and you'll get a performance boost by not using a thread safe version. If possible, use a version compiled in VC9 instead of VC6. VC9 versions require you to have the [Microsoft 2008 C++ Runtime (x86)](http://www.microsoft.com/downloads/details.aspx?FamilyID=9B2DA534-3E03-4391-8A4D-074B9F2BC1BF) or the [Microsoft 2008 C++ Runtime (x64)](http://www.microsoft.com/downloads/details.aspx?familyid=bd2a6171-e2d6-4230-b809-9a8d7548c1b6&displaylang=en) installed
You should also ensure you are using the latest version of the [Microsoft Drivers for PHP for SQL Server](http://www.microsoft.com/downloads/en/details.aspx?FamilyID=80E44913-24B4-4113-8807-CAAE6CF2CA05&displaylang=en) driver.
If possible, you should also use PHP 5.3 which provides performance improvements over 5.2.
Try increasing the IIS **MaxInstances** in IIS Manager > FastCGI from 4 to a higher value. For quad core CPUs, a higher value such as **32** should prove to provide a performance enhancement.
You can also [install wincache](http://learn.iis.net/page.aspx/678/use-the-windows-cache-extension-for-php/), to improve performance on live sites.
You can also try installing and enabling static content compression for IIS on live sites. Do this in IIS Manager > Compression.
Doing all of the above should provide a significant performance boost to your site.

View File

@ -0,0 +1,31 @@
# Manual installation on Windows using IIS
Install SilverStripe manually on Windows using IIS as the web server.
If you are not confident in installing web server software manually on Windows, it is recommended you use the
[Web Platform Installer](windows-pi) method instead, which will do the installation for you.
## [Install using IIS 7.x](windows-manual-iis-7)
This applies to Windows Server 2008, Windows Server 2008 R2, Windows Vista, and Windows 7.
## [Install using IIS 6.x](windows-manual-iis-6)
*Note: It's recommended you upgrade to Windows Server 2008 R2 which uses IIS 7.5*.
This applies to Windows Server 2003 and Windows Server 2003 R2.
## Additional notes
Microsoft has no URL rewriting module for anything less than IIS 7.x. This will mean your URLs are like yoursite.com/index.php/about-us rather than yoursite.com/about-us.
However, if you do want friendly URLs you must you must buy or use other URL rewriting software:
* [IIRF](http://iirf.codeplex.com/) (should work for most cases - see [IIS 6 guide](windows-manual-iis-6) for rewrite rules)
* [ISAPI_Rewrite](http://www.helicontech.com/download-isapi_rewrite3.htm) (The freeware, lite version should be fine for simple installations)
* If you have 64-bit Windows, you can try [this](http://www.micronovae.com/ModRewrite/ModRewrite.html)
Instructions are available for [installing PHP on IIS 6](http://learn.iis.net/page.aspx/248/configuring-fastcgi-extension-for-iis60/) by the IIS team.
On Windows XP, you need to disable **Check that file exists**. See [installation-on-windows-pi](windows-pi) for more information.
Matthew Poole has expanded on these instructions [with a tutorial](http://cubiksoundz.blogspot.com/2008/12/tech-note-installing-silverstripe-cms.html).

View File

@ -0,0 +1,50 @@
# Windows with Web Platform Installer (WebPI)
(Windows XP, 2003, 2008, Vista and 7)
## Installing SilverStripe
* Download and run Microsoft Web Platform Installer (WebPI):
[![](http://www.silverstripe.org/assets/downloads/webpi/wpiBadgeGreen.jpg)](http://www.microsoft.com/web/gallery/install.aspx?appsxml=www.microsoft.com%2fweb%2fwebpi%2f2.0%2fWebApplicationList.xml&amp;appid=105)
* In WebPI, select 'SilverStripe' from the 'Content Management System' link
* Select install. It will install dependancies like MySQL and PHP if you don't have these installed already.
* Type in the questions it asks you, such as the username/password you set in the above MySQL installation:
* Everything should be installed, with you seeing the initial webpage
* And you can log-in to the CMS
## Important: Installation issue on XP
After you've installed SilverStripe on XP using WebPI. You'll need to make a configuration change to get it working.
Specifically, you need to configure XP not to check that a script file exists before executing the script. This is
necessary for URLs of the form http://localhost/silverstripe/index.php/about-us/ to work.
* Open IIS Administrator
* Expand the local computer tree node
* Expand the Web Sites tree node
* Right click on "Default Web Site" and select "Properties"
* Select the "Home Directory" Tab.
* Click the "Configuration Button towards the bottom on the right
* Select the "Mappings" Tab
* Find the .php mapping, select it and click the "Edit" button
* Make sure the check box "Check that file exists" is cleared.
* Hit OK's all the way back up and restart IIS
## Support
* http://www.silverstripe.org/installing-on-windows-now-easier-thanks-to-microsoft-web-platform-installer/ (This shows
a beta version of the software)
* Microsoft Forum: http://forums.iis.net/1155.aspx
* SilverStripe Installation Issues Forum: http://silverstripe.org/installing-silverstripe/
## Screenshots
![](_images/webpi-2-a-silverstripe-choice.jpg)
![](_images/webpi-2-b-dependencies.jpg)
![](_images/webpi-2-c-downloading-and-installaing.jpg)
![](_images/webpi-2-d-installer-questions-step1.jpg)
![](_images/webpi-2-e-installer-questions-step2.jpg)
![](_images/webpi-2-f-success-message.jpg)
![](_images/webpi-2-g-silverstripe-homepage.jpg)
![](_images/webpi-2-h-cms-interface-working.jpg)

View File

@ -0,0 +1,49 @@
# Windows with WAMPServer
An easy and reliable approach to getting SilverStripe running on Windows is to use Apache, which can be convieniently
done through [WampServer](http://www.wampserver.com/en/). This can be useful if you are deploying on Linux Apache and
want a Microsoft Windows machine with a very similar environment.
Note: Installing on Microsoft's IIS webserver through Microsoft WebPI is likely to be easier, see
[installation-on-windows-pi](windows-pi).
## Install WAMP
1. Download WampServer from http://www.wampserver.com/en/download.php
2. Run the installer. By default, it will install to C:\wamp. You can choose your own install path if you wish; the
directories mentioned below will also be different.
3. Once WampServer has been installed and launched, you will see a little half circle gauge in the task bar, next to
the clock. If everything is working, then it will be white. If it's yellow or red, then something is wrong. If you
can't see the gauge, then WampServer hasn't been started and you should start WampServer from the start menu.
4. If something's wrong, this usually means that you have another service on port 80 or port 3306. Here are some
common sources of problems to check. After correcting these issues, left-click the gauge and choose 'restart all
services'. It might a short while to restart, but the gauge should go to white.
* You might have IIS running. Check Start -> Control Panel -> Administrative Tools -> Internet Information
Services. Ensure that any web site services are stopped.
* If you run Skype, visit Select "Tools" -> "Options" in Skype's menu. Find an option "Use port 80 and 443 as
alternatives for incoming connection". Make sure that it is de-selected.
5. Left-click the gauge, then select Apache -> Apache Modules -> Rewrite Module. The gauge will flick to yellow, and
then return to white.
6. Left-click the gauge, then select MySQL -> my.ini. At the very bottom of the file, and add the following to a new
line (without the quotes): "lower_case_table_names = 2". Save the file, close Notepad and left-click the gauge, and
selected 'Restart all services'. This is used to ease the transition between a Windows-based install and a Linux-based
install where case-sensitivity is important.
## Install SilverStripe
* [Download](http://silverstripe.org/download) the latest SilverStripe installer package
* Unpack the archive into `C:\wamp\www`
* Rename the unpacked directory from `C:\wamp\www\silverstripe-vX.X.X` to `C:\wamp\www\silverstripe`
* Visit `http://localhost/silverstripe` - you will see SilverStripe's installation screen.
* You should be able to click "Install SilverStripe" and the installer will do its thing. It takes a minute or two.
* Once the installer has finished, visit `http://localhost/silverstripe`. You should see your new SilverStripe site's
home page.
## Troubleshooting
Vista's security controls can cause issues. If you have installed on Vista but you're getting errors, there is a chance
that SilverStripe does not have sufficient permissions.
Right clicked on the installation folder and go to Permissions > Security > Users > Advanced and give the user full
control.

View File

@ -0,0 +1,455 @@
# Coding Conventions
This document provides guidelines for code formatting and documentation
to developers contributing to SilverStripe. It applies to all PHP files
in the sapphire/ and cms/ modules, as well as any supported additional modules.
Coding standards are an important aspect for every software project,
and facilitate collaboration by making code more consistent and readable.
If you are unsure about a specific standard, imitate existing SilverStripe code.
## File Formatting
### Indentation
Always use hard tabs rather then spaces for indentation, with one tab per nesting level.
### Maximum Line Length
The target line length is 100 characters, meaning developers should strive keep each line of their code
under 80 characters where possible and practical.
However, longer lines are acceptable in some circumstances.
The maximum length of any line of PHP code is 120 characters.
### Line Termination
Line termination follows the Unix text file convention. Lines must end with a single linefeed (LF) character.
Linefeed characters are represented as ordinal 10, or hexadecimal 0x0A.
Note: Do not use carriage returns (CR) as is the convention in Apple OS's (0x0D) or the carriage return -
linefeed combination (CRLF) as is standard for the Windows OS (0x0D, 0x0A).
## Naming Conventions
Class, function, variable and constant names may only contain alphanumeric characters and underscores.
### Classes
Class and filenames are in `UpperCamelCase` format:
:::php
class MyClass {}
If a class name is comprised of more than one word, the first letter of each new word must be capitalized.
Successive capitalized letters are not allowed, e.g. a class `XMLImporter` is not allowed while `XmlImporter` is acceptable.
### Methods
Static methods should be in `lowercase_with_underscores()` format:
:::php
static function my_static_method() {}
Action handlers on controllers should be in `completelylowercase()` format.
This is because they go into the controller URL in the same format (eg, `home/successfullyinstalled`).
Method names are allowed to contain underscores here, in order to allow URL parts with dashes
(`mypage\my-action` gets translated to `my_action()` automatically).
:::php
function mycontrolleraction() {}
Object methods that will be callable from templates should be in `$this->UpperCamelCase()` format.
Alternatively, `$this->getUpperCamelCase()` will work the same way in templates -
you can access both coding styles as `$UpperCamelCase`.
Other instance methods should be in `$this->lowerCamelCase()` format:
:::php
function myInstanceMethod() {}
### Variables
Static variables should be `self::$lowercase_with_underscores`
:::php
self::$my_static_variable = 'foo';
Wherever possible, set up static variables like this:
:::php
protected static $simple_setting = 50;
static function set_simple_setting($v) {self::$simple_setting = $v;}
static function get_simple_setting() {return self::$simple_setting;}
protected static $more_complex_variable = "default value";
static function set_more_complex_variable($v) {self::$more_complex_variable = $v;}
static function get_more_complex_variable() {
//complex code here;
//complex code here;
}
....
Object variables should be `$this->lowerCamelCase`
:::php
$this->myObjectVariable = 'foo';
### Constants
All letters used in a constant name must be capitalized,
while all words in a constant name must be separated by underscore characters.
:::php
define('INTEREST_RATE', 0.19);
Constants must be defined as class members with the `const` modifier.
Defining constants in the global scope with the `define` function is permitted but strongly discouraged.
### File Naming and Directory Structure
Classes need to be in a file of the same name. Multiple classes are allowed to be contained in one file,
as long as the prefix of the class equals the filename, and is separated by an underscore from the remaining name.
For example `MyClass` and `MyClass_Controller` will both need to be placed into `MyClass.php`.
Example: `mysite/code/MyClass.php`
:::php
<?php
class MyClass {}
class MyClass_Controller {}
class MyClass_OtherRelatedClass {}
To help with namespacing common class names (like Database) it is recommended to use a prefix convention `SS_ClassName` but the filename will remain `ClassName.php`.
See [directory-structure](/topics/directory-structure) for more information.
## Coding Style
### PHP Code Declaration
PHP code must always be delimited by the full-form, standard PHP tags:
:::php
<?php
Short tags are never allowed. For files containing only PHP code, the closing tag must always be omitted.
It is not required by PHP, and omitting it prevents the accidental injection of trailing white space into the response.
### Strings
#### String Literals
When a string is literal (contains no variable substitutions), the apostrophe or "single quote" should always be used to demarcate the string:
:::php
$a = 'Example String';
#### String Literals Containing Apostrophes
When a literal string itself contains apostrophes, it is permitted to demarcate the string with quotation marks or "double quotes".
:::php
$greeting = "She said 'hello'";
This syntax is preferred over escaping apostrophes as it is much easier to read.
#### String Substitution
Variable substitution is permitted using either of these forms:
:::php
$greeting = "Hello $name, welcome back!";
$greeting = "Hello {$name}, welcome back!";
For consistency, placing the dollar sign outside of the brackets is not permitted:
:::php
$greeting = "Hello ${name}, welcome back!";
#### String Concatentation
Strings must be concatenated using the "." operator. A space must always be added before and after the "." operator to improve readability:
:::php
$copyright = 'SilverStripe Ltd (' . $year . ')';
When concatenating strings with the "." operator, it is encouraged to break the statement into multiple lines to improve readability.
In these cases, each successive line should be padded with white space such that the "."; operator is aligned under the "=" operator:
:::php
$sql = 'SELECT "ID", "Name" FROM "Person" '
. 'WHERE "Name" = \'Susan\' '
. 'ORDER BY "Name" ASC ';
### Arrays
#### Numerically Indexed Arrays
Negative numbers are not permitted as indices.
An indexed array may start with any non-negative number, however all base indices besides 0 are discouraged.
When declaring indexed arrays with the Array function, a trailing space must be added after each comma delimiter to improve readability:
:::php
$sampleArray = array(1, 2, 3, 'Zend', 'Studio');
It is permitted to declare multi-line indexed arrays using the "array" construct.
In this case, each successive line must be padded with spaces such that beginning of each line is aligned:
:::php
$sampleArray = array(1, 2, 3, 'Zend', 'Studio',
$a, $b, $c,
56.44, $d, 500);
Alternately, the initial array item may begin on the following line.
If so, it should be padded at one indentation level greater than the line containing the array declaration,
and all successive lines should have the same indentation;
the closing paren should be on a line by itself at the same indentation level as the line containing the array declaration:
:::php
$sampleArray = array(
1, 2, 3, 'Zend', 'Studio',
$a, $b, $c,
56.44, $d, 500,
);
When using this latter declaration, we encourage using a trailing comma for the last item in the array;
this minimizes the impact of adding new items on successive lines, and helps to ensure no parse errors occur due to a missing comma.
#### Associative Arrays
When declaring associative arrays with the `array` construct, breaking the statement into multiple lines is encouraged.
In this case, each successive line must be padded with white space such that both the keys and the values are aligned:
:::php
$sampleArray = array('firstKey' => 'firstValue',
'secondKey' => 'secondValue');
Alternately, the initial array item may begin on the following line.
If so, it should be padded at one indentation level greater than the line containing the array declaration,
and all successive lines should have the same indentation; the closing paren should be on a line by itself at the
same indentation level as the line containing the array declaration.
For readability, the various "=>" assignment operators should be padded such that they align.
:::php
$sampleArray = array(
'firstKey' => 'firstValue',
'secondKey' => 'secondValue',
);
### Function and Method Declaration
No method or function invocation is allowed to have spaces directly
before or after the opening parathesis, as well as no space before the closing parenthesis.
:::php
function foo($arg1, $arg2) {} // good
function foo ( $arg1, $arg2 ) {} // bad
Keep the opening brace on the same line as the statement.
:::php
// good
function foo() {
// ...
}
:::php
// bad
function bar()
{
// ...
}
In cases where the argument list exceeds the maximum line length, you may introduce line breaks.
Additional arguments to the function or method must be indented one additional level beyond the function or method declaration.
A line break should then occur before the closing argument paren,
which should then be placed on the same line as the opening brace of the function
or method with one space separating the two, and at the same indentation level as the function or method declaration.
:::php
public function bar($arg1, $arg2, $arg3,
$arg4, $arg5, $arg6
) {
// indented code
}
Function and method arguments should be separated by a single trailing space after the comma delimiter,
apart from the last argument.
### Control Structures
#### if/else/elseif
No control structure is allowed to have spaces directly
before or after the opening parathesis, as well as no space before the closing parenthesis.
The opening brace and closing brace are written on the same line as the conditional statement.
Any content within the braces must be indented using a tab.
:::php
if ($a != 2) {
$a = 2;
}
If the conditional statement causes the line length to exceed the maximum line length and has several clauses,
you may break the conditional into multiple lines. In such a case, break the line prior to a logic operator,
and pad the line such that it aligns under the first character of the conditional clause.
The closing paren in the conditional will then be placed on a line with the opening brace,
with one space separating the two, at an indentation level equivalent to the opening control statement.
:::php
if (($a == $b)
&& ($b == $c)
|| (Foo::CONST == $d)
) {
$a = $d;
}
The intention of this latter declaration format is to prevent issues when adding or removing clauses
from the conditional during later revisions. For `if` statements that include `elseif` or `else`,
the formatting conventions are similar to the `if` construct.
The following examples demonstrate proper formatting for `if` statements with `else` and/or `elseif` constructs:
:::php
if ($a != 2) {
$a = 2;
} elseif ($a == 3) {
$a = 4;
} else {
$a = 7;
}
Statements with `if` can be written without braces on a single line as the block, as long as no `else` statement exists.
:::php
// good
if($a == $b) doThis();
// bad
if($a == $b) doThis();
else doThat();
#### switch
All content within the "switch" statement must be indented using tabs.
Content under each "case" statement must be indented using an additional tab.
:::php
switch($numPeople) {
case 1:
break;
case 2:
break;
default:
break;
}
The construct `default` should never be omitted from a switch statement.
#### for/foreach/while
Loop constructs follow the same principles as "Control Structures: if/else/elseif".
### Separation of Logic and Presentation
Try to avoid using PHP's ability to mix HTML into the code.
:::php
// PHP code
function getTitle() {
return "<h2>Bad Example</h2>";
}
// Template code
$Title
Better: Keep HTML in template files:
:::php
// PHP code
function getTitle() {
return "Better Example";
}
// Template code
<h2>$Title</h2>
## Comments
Use [phpdoc](http://phpdoc.org/) syntax before each definition (see [tutorial](http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_phpDocumentor.quickstart.pkg.html)
and [tag overview](http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.pkg.html)).
* All class definitions and PHP files should have `@package` and `@subpackage`.
* Methods should include at least `@param` and `@return`.
* Include a blank line after the description.
* Use `{@link MyOtherClass}` and `{@link MyOtherClass->otherMethod}` for inline references.
* Denote preformatted code examples in `<code></code>` blocks.
* Always start block-level comments containing phpdoc with two asterisks (`/** ... */`).
Example:
:::php
/**
* My short description for this class.
* My longer description with
* multiple lines and richer formatting.
*
* Usage:
* <code>
* $c = new MyClass();
* $c->myMethod();
* </code>
*
* @package custom
*/
class MyClass extends Class {
/**
* My Method.
* This method returns something cool. {@link MyParentMethod} has other cool stuff in it.
*
* @param string $colour The colour of cool things that you want
* @return DataObjectSet A list of everything cool
*/
public function myMethod($foo) {}
}
### Class Member Ordering
Put code into the classes in the following order (where applicable).
* Static variables
* Object variables
* Static methods
* Data-model definition static variables. (`$db`, `$has_one`, `$many_many`, etc)
* Commonly used methods like `getCMSFields()`
* Accessor methods (`getMyField()` and `setMyField()`)
* Controller action methods
* Template data-access methods (methods that will be called by a `$MethodName` or `<% control MethodName %>` construct in a template somewhere)
* Object methods
### SQL Format
To make sure your code works across databases make sure you escape your queries like below,
with the column or table name escaped with double quotes and values with single quotes.
:::php
DataObject::get("MyClass", "\"Title\" = 'my title'");
Use [ANSI SQL](http://en.wikipedia.org/wiki/SQL#Standardization) format where possible.
### Secure Development
See [security](/topics/security) for conventions related to handing security permissions.
## License
Parts of these coding conventions were adapted from [Zend Framework](http://framework.zend.com/manual/en/coding-standard.overview.html),
which are licensed under BSD (see [license](http://framework.zend.com/license)).

View File

@ -0,0 +1,285 @@
# Contributing
Any open source product is only as good as the community behind it. You can participate by sharing
code, ideas, or simply helping others. No matter what your skill level is, every contribution counts.
See our [high level overview on silverstripe.org](http://silverstripe.org/contributing-to-silverstripe) on how you can help out.
## Sharing your Opinion
* [silverstripe.org/forums](http://silverstripe.org/forums): Forums on silverstripe.org
* [silverstripe-dev](http://groups.google.com/group/silverstripe-dev): Core development mailinglist
* [silverstripe-documentation](http://groups.google.com/group/silverstripe-documentation): Documentation team mailing list
## Reporting Bugs
If you have discovered a bug in SilverStripe, we'd be glad to hear about it -
well written bug reports can be half of the solution already!
Our bugtracker is located on [open.silverstripe.org](http://open.silverstripe.org/) (create a [new ticket](http://open.silverstripe.org/newticket)).
## Submiting Patches, Bugfixes and Enhancements
We're not perfect, and need your help - for example in the form of patches for our modules and core codebase.
### Setup your project for contributions
In contrast to running a SilverStripe website, you can't use the standard download archive for this purpose.
Our [module list on silverstripe.org](http://silverstripe.org/modules) lists the repository locations alongside
the archive downloads, typically using a version control system like "git" or "[subversion](subversion)".
General guidelines:
* Adhere to our [coding conventions](coding-conventions)
* If your patch is extensive, discuss it first on the [silverstripe forum](http///www.silverstripe.org/forums/) (ideally before doing any serious coding)
* Check your patches against the latest "trunk" or "master", as well as the latest release.
Please not that the latest stable release will often not be sufficient! (of all modules)
* Provide complete [unit test coverage](/topics/testing) - depending on the complexity of your work, this is a required
step.
* Do not set milestones. If you think your patch should be looked at with priority, mark it as "critical".
* Describe specifics on how to test the effects of the patch
* It's better to submit multiple patches with separate bits of functionality than a big patch containing lots of
changes
* Document your code inline through [PHPDoc](http://en.wikipedia.org/wiki/PHPDoc) syntax. See our
[API documentation](http://api.silverstripe.org/trunk) for good examples.
* Also check and update documentation on [doc.silverstripe.org](http://doc.silverstripe.org). Check for any references to functionality deprecated or extended through your patch. Documentation changes should be included in the patch.
### Sending pull requests (for git)
The SilverStripe core (`sapphire` and `cms`), as well as some of the more popular modules are in
git version control. SilverStripe hosts its modules on [github.com/silverstripe](http://github.com/silverstripe).
After [installing git](http://help.github.com/git-installation-redirect) and creating a [free github.com account](https://github.com/signup/free), you can "fork" a module,
which creates a copy that you can commit to (see github's [guide to "forking"](http://help.github.com/forking/)).
Example: [Fork the blog module](https://github.com/silverstripe/silverstripe-blog)
After committing your fix, you can send the module authors a so called ["pull request"](http://help.github.com/pull-requests/).
The module authors will get notified automatically, review your patch, and merge it back as appropriate.
For new features, we recommend creating a ["feature branch"](http://progit.org/book/ch3-3.html) rather than a really big patch.
If you want to learn more about git, please have a look at the [free online git book](http://progit.org/book/) and the [git crash course](http://gitref.org/).
### Submitting patches (for subversion)
Other modules will be hosted on [subversion](http://subversion.tigris.org), in which case you have to
package your changes as a "patch" file. Please read the [official Subversion book](http://svnbook.red-bean.com/) (available free online) for a general introduction to subversion.
To submit a patch, [register](http://open.silverstripe.com/apply) and attach the patch to the appropriate ticket.
Please include in the comment the revision number that the patch is applicable for and a brief outline of what you fixed and how.
Only use the provided link to submit patches, as it prefills information about owner and ticket-type:
[Submit a patch (requires account on open.silverstripe.org)](http://open.silverstripe.com/newticket?field_type=patch&field_owner=ischommer&attachment=1)
The core team is responsible for reviewing the patches and deciding if they will make it into core. If
there are any problems they will assign the ticket back to you, so make sure you have an email address loaded into Trac
so that it will notify you! The Trac report [Active Patches](http://open.silverstripe.com/report/10) will let you see
where all the patches are at.
You can create a patch file through the svn diff-command on the command-line.
More info in the [svn redbook](http://svnbook.red-bean.com/en/1.1/ch03s05.html#svn-ch-3-sect-5.3.2).
Your code editor might have a GUI for creating patches.
# in a working copy folder (e.g /myproject)
svn diff sapphire/ > ~/patch.diff
Some gotchas when using subversion and the patch format:
* Submit your patch in *diff -u* or *diff -c format*.
* If your patch involves new files, create a compressed archive for them (including any required directory-structures)
* Create patches relative to the working copy (*sapphire/main.php* instead of */Users/myuser/sapphire/main.php*)
* Remember the shortcomingsof *svn diff*: Please document moved files and created/deleted directories separately
### Commit Messages
We try to maintain a consistent record of descriptive commit messages. As we automatically generate changelogs from them, we need a way to categorize and filter. Please prefix **all** commit messages with one of the following tags:
* `API CHANGE`: You've added or modified the functions available to developers writing custom PHP.
* `ENHANCEMENT`: You've added something to the user-visible aspects of SilverStripe.
* `BUGFIX`: You've fixed something that was broken.
* `MINOR` Mark things that are so trivial they're not even worth telling users about; specifically, to prevent adding
clutter to our automatically generated changelogs. MINOR is not used to mark a minor bugfix or feature, see above.
Some examples:
* a subsequent commit to a bugfix/feature that you committed earlier that day
* adding unit tests (that are more interesting to developers of SilverStripe than users of it)
* subversion/codebase plumbing (changing externals, blocking revisions, moving files around, etc)
* In summary: if it's worth including in the changelog, it's not `MINOR`.
Further guidelines:
* Each commit should form a logical unit - if you fix two unrelated bugs, commit each one separately
* If you are fixing a ticket from our [bugtracker](http://open.silverstripe.com), please append `(fixes #<ticketnumber>)`
* If your change is related to another changeset, reference it with `r<revisionnumber>`.
* Please mention the changed classes and methods in your comment - the message should be understandable on its own without browsing any sourcecode
Example: Bad commit message
finally fixed this dumb rendering bug that Joe talked about ... LOL
also added another form field for password validation
Example: Good commit message
ENHANCEMENT Added prepValueForDB() which is called on DBField->writeToManipulation() to ensure formatting of value before insertion to DB on a per-DBField type basis (see #1234)
MINOR Added documentation for DBField->writeToManipulation() (see r55555)
<div class="hint" markdown="1">
Note: By supplying code in patches, tickets and pull requests,
you agree that is can be used in distributions and derivative works of SilverStripe CMS and associated modules, under the BSD license.
</div>
## Reporting Security Issues
Report security issues to [security@silverstripe.com](mailto:security@silverstripe.com). Please don't file security
issues in our [bugtracker](http://open.silverstripe.org). In the event of a confirmed vulnerability in SilverStripe
core, we will take the following actions:
* Acknowledge to the reporter that weve received the report and that a fix is forthcoming. Well give a rough
timeline and ask the reporter to keep the issue confidential until we announce it.
* Halt all other development as long as is needed to develop a fix, including patches against the current and one
previous major release (if applicable).
* We will inform you about resolution and [announce](http://groups.google.com/group/silverstripe-announce) a [new
release](http://silverstripe.org/security-releases/) publically.
You can help us determine the problem and speed up responses by providing us with more information on how to reproduce
the issue: SilverStripe version (incl. any installed modules), PHP/webserver version and configuration, anonymized
webserver access logs (if a hack is suspected), any other services and web packages running on the same server.
## Writing Documentation
Documentation for a software project is a continued and collaborative effort,
we encourage everybody to contribute, from simply fixing spelling mistakes, to writing recipes/howtos,
reviewing existing documentation, and translating the whole thing.
Modifying documentation requires basic [PHPDoc](http://en.wikipedia.org/wiki/PHPDoc) and
[Markdown](http://daringfireball.net/projects/markdown/)/[SSMarkdown](ss-markdown) knowledge.
If you have downloaded SilverStripe or a module, chances
are that you already have the documentation files - they are kept alongside the source code.
The [doc.silverstripe.org](http://doc.silverstripe.org) website itself is powered by a
SilverStripe project that uses the ["sapphiredocs" module](http://open.silverstripe.org/browser/modules/sapphiredocs/trunk)
to convert Markdown formatted files into searchable HTML pages with index lists.
### Repositories
* End-user: [userhelp.silverstripe.org](http://userhelp.silverstripe.org)
* Developer Guides: [doc.silverstripe.org](http://doc.silverstripe.org)
* Developer API Docuumentation: [api.silverstripe.org](http://api.silverstripe.org)
### Source Control
In order to balance editorial control with effective colaboration, we keep
documentation alongside the module source code, e.g. in `sapphire/docs/`,
or as code comments within PHP code.
Contributing documentation is the same process as providing any other patch
(see [Patches and Bugfixes](#submiting-patches-bugfixes-and-enhancements)).
### What to write
* **API Docs**: Written alongside source code and displayed on [api.silverstripe.com](http://api.silverstripe.org).
This documents the low-level, technical usage of a class, method or property.
Not suited for longer textual descriptions, due to the limited support of PHPDoc formatting for headlines.
* **Tutorials**: The first contact for new users, guiding them step-by-step through achievable projects, in a book-like style.
*Example: Building a basic site*
* **Topics**: Provides an overview on how things fit togehter, the "conceptual glue" between APIs and features.
This is where most documentation should live, and is the natural "second step" after finishing the tutorials.
*Example: Templates, Testing, Datamodel*
* **Howto**: Recipes that solve a specific task or problem, rather than describing a feature.
*Example: Export DataObjects as CSV, Customizing TinyMCE in the CMS*
* **Reference**: Complements API docs in providing deeper introduction into a specific API. Most documentation
should fit elsewhere. *Example: ModelAdmin*
* **Misc**: "Meta" documentation like coding conventions that doesn't directly relate to a feature or API.
See [What to write (jacobian.org)](http://jacobian.org/writing/great-documentation/what-to-write/) for an excellent
introduction to the different types of documentation, and [Producing OSS: "Documentation"](http://producingoss.com/en/getting-started.html#documentation)
for good rules of thumb for documenting opensource software.
### Structure
* Don't duplicate: Search for existing places to put your documentation. Do you really require a new page, or just a new paragraph
of text somewhere?
* Use PHPDoc in source code: Leave lowlevel technical documentation to code comments within PHP, in [PHPDoc](http://en.wikipedia.org/wiki/PHPDoc) format.
* Use Markdown in Developer Guides: We have a slightly customized version of Markdown called [SSMarkdown][ss-markdown]
* API and Developer Guides complement each other: Both forms of documenting sourcecode (API and Developer Guides) are valueable ressources.
* Provide context: Give API documentation the "bigger picture" by referring to Developer Guides inside your PHPDoc.
* Make your documentation findable: Documentation lives by interlinking content, so please make sure your contribution doesn't become an
inaccessible island. Your page should at least be linked on the index page in the same folder. It can also appear
as "related content" on other resource (e.g. `/topics/search` might link to `howto/search-dataobjects`).
* Avoid FAQs: FAQs are not a replacement of a coherent, well explained documentation. If you've done a good job
documenting, there shouldn't be any "frequently asked questions" left ;)
* Commit early and often: You don't need to completely finish documentation, as long as you mark areas needing refinement.
* Every file should have exactly one `<h1>` headline, roughly matching the filename. It should be short enough to be
used in table of content lists.
### Writing Style
* Write in second plural form: Use "we" instead of "I". It gives the text an instructive and collaborative style.
* Its okay to address the reader: For example "First you'll install a webserver" is good style.
* Write in an active and direct voice
* Mark up correctly: Use preformatted text, emphasis and bold to make technical writing more "scannable".
### Highlighted blocks ###
There are several built-in block styles for highlighting a paragraph of text.
Please use these graphical elements sparingly.
<div class="hint" markdown='1'>
"Tip box": Adds, deepens or accents information in the main text.
Can be used for background knowledge, or "see also" links.
</div>
Code:
<div class="hint" markdown='1'>
...
</div>
<div class="notice" markdown='1'>
"Notification box": Technical notifications relating to the main text.
For example, notifying users about a deprecated feature.
</div>
Code:
<div class="notice" markdown='1'>
...
</div>
<div class="warning" markdown='1'>
"Warning box": Highlight a severe bug or technical issue requiring
a users attention. For example, a code block with destructive functionality
might not have its URL actions secured to keep the code shorter.
</div>
Code:
<div class="warning" markdown='1'>
...
</div>
See [Markdown Extra Documentation](http://michelf.com/projects/php-markdown/extra/#html) for more restriction
on placing HTML blocks inside Markdown.
### Translating Documentation
Documentation is kept alongside the source code, typically in a module subdirectory like `sapphire/docs/en/`.
Each language has its own subfolder, which can duplicate parts or the whole body of documentation.
German documentation would for example live in `sapphire/docs/de/`.
The [sapphiredocs](http://open.silverstripe.org/browser/modules/sapphiredocs/trunk) module that drives
[doc.silverstripe.org](http://doc.silverstripe.org) automatically resolves these subfolders into a language dropdown.
### Further reading
* [Writing great documentation (jacobian.org)](http://jacobian.org/writing/great-documentation/)
* [How tech writing sucks: Five Sins](http://www.slash7.com/articles/2006/11/15/tech-writing-the-five-sins)
* [What is good documentation?](http://www.techscribe.co.uk/techw/whatis.htm)
## Translating the User Interface
The content for UI elements (button labels, field titles) and instruction texts shown in the CMS and
elsewhere is stored in the PHP code for a module (see [i18n](/topics/i18n)). All content can be extracted as a "language file"
which is then uploaded to [translate.silverstripe.org](http://translate.silverstripe.org). This website provides
an online editor for translators (like you!). Every now and then, translations will be merged back into
the codebase from there, and released alongside other PHP code.
SilverStripe is already translated in over 60 languages, and we're relying on native speakers
to keep these up to date, and of course add new languages. Please [register](http://translate.silverstripe.org/apply)
a free translator account to get started, even if you just feel like fixing up a few sentences.

15
docs/en/misc/index.md Normal file
View File

@ -0,0 +1,15 @@
# Misc
This section is dedicated to going to detail about an assortment of topics which don't necessary fit into other documentation
sections.
* [Coding conventions](coding-conventions): Guidelines and standards for code formatting and documentation
* [Contributing](contributing): How you can be a part of the SilverStripe Open Source community
* [Module release process](module-release-process): Creating and looking after a module
* [Release process](release-process): Describes the Sapphire and CMS release process
* [SS markdown](ss-markdown): Markdown syntax for our technical documentation
## Feedback
If you have a topic you would like covered in the misc section please ask for it on our [Bug Tracker](http://open.silverstripe.org)

View File

@ -0,0 +1,242 @@
# Module Maintenance and Release Procedures #
## Creating a module
One of the best ways that you can contribute to SilverStripe is by developing a module for SilverStripe.
If you do, we would love to host your module and have you become an official module maintainer on our site.
Please read our ["Contributing to SilverStripe"](http://silverstripe.org/contributing-to-silverstripe/) overview.
Once you have created a module, login at [silverstripe.org](http://silverstripe.org) and
[submit your module](http://silverstripe.org/modules/manage/add)
It's very important to us that users of SilverStripe can come to expect a level of quality from the core product and any
modules running on it. In order to provide this, we require certain things from module maintainers.
<div class="hint" markdown="1">
The following documentation describes aspects of subversion, you can read about similiar
strategies for git on a [free online book](http://progit.org/book).
</div>
### Principles
Strive for features you add to the CMS to be innovatively usable by a content editor rather than a web-developer.
Think Wordpress and Apple. Most modules should work by merely placing the code in your SilverStripe installation and
running /dev/build. Provide a default set of configuration options that are easily changed in `_config.php`
(for instance the `ecommerce` module works out of the box, and you can easily set up a payment provider), aiding a pleasant
user experience.
### Code
Each line of code you write should be version controlled, in version control systems like
[subversion](http://subversion.tigris.org) or [Git](http://gitscm.com). There's lots of services that are freely
available for opensource projects, including wiki and bugtracker functionality
(e.g. [Google Code for Subversion](http://code.google.com) or [Github for Git](http://github.com)).
* Add your module to [silverstripe.org/modules](http://silverstripe.org/modules) (and keep the version compatibility information current)
* Follow our [coding-conventions](coding-conventions)
* Write unit tests and functional tests covering code bundled with the module - see [testing-guide](/topics/testing)
* Ensure your code is [localizable](/topics/i18n) and [translatable](/topics/translation)
### Maintenance
* Create releases (see ["Module Releases"](#module-releases) below)
* Ensure that your module is patched to always work with the latest SilverStripe release, and note these compatibilities on
your modules page on silverstripe.org
* Be involved in our community
* Subscripe to our developer mailing list and be available to answer questions on the forum.
* Attend [irc:our weekly core discussions on IRC](irc/our weekly core discussions on IRC) as regularly as you can.
* Create an **issue tracker** so your users can file bugs and feature requests (see ["Feedback and Bugtracking"](#feedback-and-bugtracking) below)
* Create a **roadmap** and **milestones** outlining future release planning
### Feedback and Bugtracking
Both Google Code and github.com provide their own bugtracker - we encourage you to use any built-in tools that come with
your version control hoster. Most Silverstripe-maintained modules have their bugtracker on
[open.silverstripe.org](http://open.silverstripe.org).
Providing bugtracking is a major form of communicating with your users in an efficient way, and will provide a good overview
of outstanding work and the stability of your code to an interested user.
If the user community finds bugs that shouldn't be included in the next stable release, you will need to release another
release candidate. If your release candidate is found to be stable, then you can create the stable release.
### Documentation
You should have both **developer documentation** and **user documentation**, and keep them updated with your releases.
See [Producing OSS: "Documentation"](http://producingoss.com/en/getting-started.html#documentation) and our
[contributing guide](contributing#writing-documentation).
### README file
Each module should have a `README.md file` in the project root in
[markdown format](http://daringfireball.net/projects/markdown/), roughly following this template:
# <MODULENAME> Module
## Maintainer Contact
* <FULLNAME> (Nickname: <NICKNAME>, <EMAIL>)
## Requirements
* <Specific SilverStripe version, PHP, MySQL, ...>
## Documentation
<Links to the wiki, blog posts, etc>
## Installation Instructions
<Step by step instructions>
## Usage Overview
<Highlevel usage, refer to wiki documentation for details>
## Known issues
<Popular issues, how to solve them, and links to tickets in the bugtracker>
### The docs/ folder ###
The `README.md` file might get a bit long for bigger modules, and you might want to break it up into multiple files
that you can link from the `README.md` file. Example:
mymodule/
README.md
code/
docs/
installation.md
tutorial.md
howto-search-mymodule.md
The ["sapphiredocs" module](http://open.silverstripe.org/browser/modules/sapphiredocs/trunk) can be used
to list and render content inside a `docs/` folder (although it is not required, Markdown is designed
to be readable in plain text as well).
### What do you get?
In return for all your hard work in putting a high-quality module on the site, the SilverStripe project has the following
options to support you:
* Use of [trac](http://open.silverstripe.org) to keep your bugs and feature requests organised
* Advertising of your module on the http://silverstripe.org/modules/ modules page once it has reached a beta stage and shown
to meet our requirements above.
* We might showcase your module on our blog and/or newsletter, when it's first released and/or when a major version with
significant new features is released. We'll work with you to publicise it on other blogs too (it helps if you deliver
screenshots and screencasts)
* More influence in suggesting changes to the core product
* Kudos on [Ohloh](http://www.ohloh.net/projects/5034?p=SilverStripe+CMS)
## Releasing a Module
If you are a module maintaienr, you will be responsible for creating new releases of the module.
Releases are important for each codebase to provide stability for its users,
and clearly communicate dependencies/requirements.
### Release Branches
In order to ensure stability, the first thing we do when making a release is to create a release branch. This branch
will exist for the duration of the testing and release candidate phase. The key is that **you should only commit
bugfixes to this branch**. This lets you focus on getting a stable version of module ready for release, and new
features can still be added to trunk.
Creating a release branch is a simple `svn cp` command. In the example below, (modulename) would be something like
"ecommerce" or "flickrservice", and (releasenumber) would be something like "0.2.1" (see
[Producing OSS: Release Numbering](http://producingoss.com/en/development-cycle.html#release-numbering))
svn cp http://svn.silverstripe.com/open/modules/(modulename)/trunk http://svn.silverstripe.com/open/modules/(modulename)/branches/(releasenumber)
Once you have created a release branch, you should do some testing of the module yourself. Try installing it on a new
site, and existing site, use the different features, and if possible, install on a couple of different servers.
See [SVN Book: "Release Branches"](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.commonpatterns.html#svn.branchmerge.commonpatterns.release),
[Producing OSS: "Release Branches"](http://producingoss.com/en/release-branches.html) and
[Producing OSS: "Stabilizing a release"](http://producingoss.com/en/stabilizing-a-release.html) for more details.
### Release Candidates
Once you've done your own testing, it's time to create a release candidate (RC). This is a copy of your module that
will be sent to the developer community for testing and feedback. Creating a release candidate is a matter of executing
a `svn cp` command.
Note: If you are the only developer on the module, and you aren't going to be creating any new features for the duration
of the release cycle, then you can get away with creating your RCs directly from trunk instead of creating a release
branch. For major modules, we advise against this, but for very simple modules, going through the whole release process
might be overkill.
svn cp http://svn.silverstripe.com/open/modules/(modulename)/branches/(releasenumber) http://svn.silverstripe.com/open/modules/(modulename)/tags/rc/(releasenumber)-rc1
svn co http://svn.silverstripe.com/open/modules/(modulename)/tags/rc/(releasenumber)-rc1 (modulename)
tar czf (modulename)_(releasenumber)-rc1.tar.gz (modulename)
See ["ReleaseBranches" chapter](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.commonpatterns.html#svn.branchmerge.commonpatterns.release)
and ["Tags" chapter](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.tags.html).
### Stabilizing A Release
After you have put a release candidate out for testing and no-one has found any bugs that would prevent a release, you
can create the stable release! Please: **The stable release should always be a copy of a release candidate**. Even if
"there's just one tiny bug to fix", you shouldn't release that bug fix onto a stable release - there is always the risk
that you inadvertently broke something! As you might guess, `svn cp` is used to create the final release, and then an
export to a tar.gz.
svn cp http://svn.silverstripe.com/open/modules/(modulename)/tags/rc/(releasenumber)-rc2 http://svn.silverstripe.com/open/modules/(modulename)/tags/(releasenumber)
svn export http://svn.silverstripe.com/open/modules/(modulename)/tags/(releasenumber) (modulename)
tar czf (modulename)_(releasenumber).tar.gz (modulename)
### Announcing a Release or Release Candidate
* See [Producing OSS: "Announcing Releases"](http://producingoss.com/en/testing-and-releasing.html#release-announcement)
* Update your [documentation](#documentation) in the sourcecode, wiki and README
* Add your release to the [silverstripe.org/modules](http://silverstripe.org/modules) listing
* Announce the release on [silverstripe-announce](http://groups.google.com/group/silverstripe-announce). Include a
[changelog](#changelogs), the download link and instructions for filing bug reports.
* If this release is a major release, our [marketing guys](http://silverstripe.com/contact/) will strive to announce it
on the main [silverstripe.com blog](http://silverstripe.com/blog) as well
### Changelogs
Each release you make should contain `CHANGELOG` file in the project root with a highlevel overview of additions and
bugfixes in this release. The `svn log` command gives you all commit messages for a specific project, and is a good
start to build a changelog (see ["Examining historical changes" chapter](http://svnbook.red-bean.com/en/1.5/svn.tour.history.html)).
Depending on the volume of changes, it is preferred that you summarize these messages in a more "digestible"
form (see [Producing OSS: "Changes vs. Changelog"](http://producingoss.com/en/packaging.html#changelog)).
A good `CHANGELOG` example from the subversion project itself:
Version 1.5.2
(29 Aug 2008, from /branches/1.5.x)
http://svn.collab.net/repos/svn/tags/1.5.2
User-visible changes:
* Set correct permissions on created fsfs shards (r32355, -7)
* Pass client capabilities to start-commit hook (issue #3255)
* Disallow creating nested repositories (issue #3269)
Developer-visible changes:
* make libsvn_ra_neon initialization thread-safe (r32497, r32510)
Version 1.5.1
(24 Jul 2008, from /branches/1.5.x)
http://svn.collab.net/repos/svn/tags/1.5.1
...
### Release Branch Maintenance
This is also the time to remove the release branch from the subversion tree - we don't want to have lots of branches on
the source tree to confuse everyone. However, before you do this, you will need to merge your changes back to the
trunk.
## See Also
[Module Development](/topics/module-development)
[Documentation Guide](contributing#writing-documentation)
[Contributing to SilverStripe](http://silverstripe.org/contributing-to-silverstripe/)
[Submit your Module](http://silverstripe.org/modules/manage/add)
[subversion](subversion)

View File

@ -0,0 +1,116 @@
# Release Process #
Describes the process followed for "core" releases (mainly the `sapphire` and `cms` modules).
For other modules, we've compiled a helpful guide for a good [module release process](module-release-process).
## Release Maintainer
The current maintainer responsible for planning and performing releases is Ingo Schommer (ingo at silverstripe dot com).
## Release Planning
Our most up-to-date release plans are typically in the [roadmap](http://open.silverstripe.com/roadmap).
New features and API changes are typically discussed on the [core
mailinglist](http://groups.google.com/group/silverstripe-dev). They are prioritized by the core team as tickets on
[open.silverstripe.org](http://open.silverstripe.com/).
Release dates are usually not published prior to the release, but you can get a good idea of the release status by
reviewing the [release milestone](http://open.silverstripe.com/roadmap) on open.silverstripe.org. Releases will be
announced on the [release announcements mailing list](http://groups.google.com/group/silverstripe-announce).
Releases of the *cms* and *sapphire* modules are coupled at the moment, they follow the same numbering scheme. Module
releases are documented separately in [module-release-process](module-release-process).
## Release Numbering
* Versions are numbered by major version number, minor version number, and micro version number, in the form *A.B.C*
(e.g. *2.4.1*)
* *A* is the *major version number*, which is only incremented for major changes and core rewrites, lots of them won't
be backwards compatible.
* *B* is the *minor version number*. It is incremented for our typical releases with new features and bugfixes. We
strive for few changes to be backwards incompatible, and will deprecate any APIs before removing them.
* *C* is the *micro version number*, incremented for bugfixes, minor enhancements and security fixes. Unless
security-related, all changes will be fully backwards compatible to the minor version number.
* Major and minor releases have an *alpha* cycle, which is a preview developer release which that see major changes
until release. It is followed by a *beta* cycle, which is feature complete and used by the wider development community
for stability and regression testing. Naming convention is *A.B.C-alpha* and *A.B.C-beta*.
* Major, minor and micro releases can have one or more *release candidates (RC)*, to be used by the wider community. A
release candidate signifies that the core team thinks the release is ready without further changes. The actual release
should be a identical copy of the latest RC. Naming convention is *A.B.C-rc1* (and further increments).
### Major releases
So far, major releases have happened every couple of years. Most new releases are *minor version number* or *micro
version number* increments.
So far, we only had one major release, from the *1.x* to the *2.x* line.
### Minor releases
Minor releases have happened about once every 18 months.
For example, *2.3* was released in February 2009, followed by *2.4* in May 2010.
These releases will contain new features, general enhancements and bugfixes. APIs from previous minor releases can be
*deprecated*, but will stay available for one more minor release. So, if an API is deprecated in *A.B*, it will continue
to work in *A.B+1*, and removed in *A.B+2*.
An example: Say we'd want to rename *BasicAuth::requireLogin()* to follow our coding conventions, which is
*BasicAuth::require_login()*. The method was introduced in *2.1*, we've made the change in *2.3*?
* *2.3* would've marked the method as *@deprecated*, and documents it as an *API CHANGE* in our
[changelog](/changelogs). The old method continues to work, but will throw an *E_USER_NOTICE*.
* *2.4* would've removed the method, also documenting it as an *API CHANGE*, and mentioning it in the
[upgrading](/installation/upgrading) guidelines.
Exceptions to the deprecation cycle are APIs that have been moved into their own module, and continue to work with the
new minor release. These changes can be performed in a single minor release without a deprecation period.
### Micro releases
Micro releases are issued about every two months for the latest release, typically for security reasons.
You can safely upgrade to those releases (after reading the [upgrading](/installation/upgrading) guidelines).
For example, *2.3.6* was released in February 2010, followed by *2.3.7* in March 2010.
### Supported versions
At any point in time, the core development team will support a set of releases to varying levels:
* The current *development trunk* will get new features and bug fixes that might require major refactoring before going
into a release (Note: At the moment, bugfixing and feature development might happen on the current release branch, to be
merged back to trunk regularly).
* Applicable bugfixes on trunk will also be merged back to the last minor release branch, to be released as the next
micro release.
* Security fixes will be applied to the current trunk and the previous two minor releases (e.g. *2.3.8* and *2.4.1*).
This page details the processes by which we (should) make APIs deprecated.
## Deprecation ##
Needs of developers (both on core framework and custom projects) might outgrow the capabilities
of a certain API. Existing APIs might turn out to be hard to understand, maintain, test or stabilize.
In these cases, it is best practice to "refactor" these APIs into something more useful.
SilverStripe acknowledges that developers have built a lot of code on top of existing APIs,
so we strive for giving ample warning on any upcoming changes through a "deprecation cycle".
How to deprecate an API:
* Add a `@deprecated` item to the docblock tag, with a `{@link <class>}` item pointing to the new API to use.
* Update the deprecated code to throw an `E_USER_NOTICE` error, with a message starting with the string 'DEPRECATED:'.
In time, we may use that string to identify deprecation errors, so please ensure that you add this string to the notice level error.
* Make sure that the old deprecated function works by calling the new function - don't have duplicated code!
* Mark in which release the function was deprecated (find out next release in the [roadmap](http://open.silverstripe.com/roadmap)), so we can determine when to finally remove it.
Here's an example for replacing `Director::isDev()` with a (theoretical) `Env::is_dev()`:
:::php
/**
* Returns true if your are in development mode
* @deprecated (since 2.2.2) Use {@link Env::is_dev()} instead.
*/
function isDev() {
user_error("DEPRECATED: Use Env::is_dev() instead.", E_USER_NOTICE);
return Env::is_dev();
}
* Deprecated APIs can be removed after developers had a chance to react to the changes. As a rule of thumb, leave the code with the deprecation warning in for at least three micro releases. Only remove code in a minor or major release. For example:
* Deprecated as of in 2.2.2
* Still deprecated in 2.2.3
* Still deprecated in 2.2.4
* Removed from 2.3.0

113
docs/en/misc/ss-markdown.md Normal file
View File

@ -0,0 +1,113 @@
# SilverStripe Markdown Syntax
As Markdown by default is quite limited and not well suited for technical documentation,
the SilverStripe project relies on certain syntax additions. As a base syntax, we use
the [Markdown Extra](http://michelf.com/projects/php-markdown/extra/) format, which provides us
with support for tables, definition lists, code blocks and inline HTML.
**Please read the [Markdown](http://daringfireball.net/projects/markdown/syntax) and
[Markdown Extra](http://michelf.com/projects/php-markdown/extra/) documentation for a syntax overview**
On top of that, we have added syntax that is only resolved by our custom parser.
The goal is to keep the customization to a necessary minimum,
and HTML output should still be readable with our custom markup unparsed.
## Rendering
While most of the Markdown syntax is parseable by all common implementations,
the special syntax is relying on a custom SilverStripe project that powers `http://doc.silverstripe.org`.
The website a standard SilverStripe installation with the [sapphiredocs](http://open.silverstripe.org/browser/modules/sapphiredocs/trunk)
module installed (see module [README](http://open.silverstripe.org/browser/modules/sapphiredocs/trunk/README.md) and
[documentation](http://open.silverstripe.org/browser/modules/sapphiredocs/trunk/docs/en)).
## Syntax
### Relative Links
Relative links can point to other markdown pages in the same module.
They are always referred to **without** the `.md` file extension.
"Absolute" links relate to the root of a certain module,
not the webroot of the renderer project or the filesystem root.
* link to folder on same level: `[title](sibling/)`
* link to page on same level: `[title](sibling)`
* link to parent folder: `[title](../parent/)`
* link to page in parent folder: `[title](../parent/page)`
* link to root folder: `[title](/)`
* link to root page: `[title](/rootpage)`
Don't forget the trailing slash for directory links,
it is important to distinguish files from directories.
Note: It is recommended to use absolute links over relative links
to make files easier to move around without changing all links.
### API Links
You can link to API documentation from within the markup by pseudo-links.
These are automatically resolved to the right URL on `http://api.silverstripe.org`.
API links are automatically wrapped in `<code>` blocks by the formatter.
* Link to class: `[api:DataObject]`
* Link to static method: `[api:DataObject::has_one()]`
* Link to instance method: `[api:DataObject->write()]`
* Link to static property: `[api:DataObject::$searchable_fields]`
* Link to instance property: `[api:DataObject->changedFields]`
* Custom titles: `[my title](api:DataObject)`
There's some gotchas:
* This notation can't be used in code blocks.
* If you want to use API links to other modules or versions of the same module, you'll have to use the full `http://` URL.
* You can't mark API links in backticks to trigger `<pre>` formatting, as it will stop the link parsing.
The backticks are automatically added by the parser.
### Code Blocks with Highlighting
Code blocks can optionally contain language hints that a syntax highlighter can
pick up. Use the first line in the block to add a language identifier, prefixed by three colons (`:::`), for example `:::php`.
We're currently using the [syntaxhighlighter](http://code.google.com/p/syntaxhighlighter/) JavaScript implementation.
See a [list of supported languages](http://code.google.com/p/syntaxhighlighter/wiki/Languages).
Example for PHP:
:::php
class Page extends SiteTree {
function myFunction() {
// ...
}
}
For SilverStripe templates, please use `:::ss` as a brush.
### Images
As a convention, referenced images in a Markdown formatted page should always be stored
in an `_images/` folder on the same level as the page itself. Try to keep the image size
small, as we typically package the documentation with the source code download, and
need to keep the file size small.
You can link to absolute image URLs as well, of course.
## FAQs
### How do I preview my own SS Markdown?
Thats only possible with the `sapphiredocs` module - we don't have a standalone parser.
### Can I run my own documentation server?
Yes, the `sapphiredocs` module just requires a default SilverStripe installation (2.4+).
### Can I generate SS Markdown other formats?
Currently this is not supported, as all HTML is generated on the fly.
### Can I contribute to the parser and rendering project?
Of course, the `sapphiredocs` code is BSD licensed - we're looking forward to your contributions!
## Related ##
* [contributing](contributing#writing-documentation): The doc.silverstripe.org website has certain styling and writing conventions

175
docs/en/misc/subversion.md Normal file
View File

@ -0,0 +1,175 @@
## Subversion
Subversion [website](http://subversion.tigris.org) is a **version control system**.
You can browse our Subversion "code repository" [here](http://open.silverstripe.com/browser), however we now use GIT to
manage our modules (see [Contributing](contributing)).
This page only describes SilverStripe-specific information on how to handle subversion. For a general introduction,
please read the [Official Subversion Book](http://svnbook.red-bean.com/) (available free online).
Start with the ["Basic Usage" chapter](http://svnbook.red-bean.com/en/1.5/svn.tour.html).
### Clients
Make sure you have an updated [subversion client](http://subversion.tigris.org/links.html#clients) installed.
Subversion 1.5 or higher is required for features such as relative externals and merge tracking.
### Checkout / Download
See [Download SilverStripe](http://silverstripe.org/download) and the
["Update your working copy" chapter](http://svnbook.red-bean.com/en/1.5/svn.tour.cycle.html#svn.tour.cycle.update).
### Committing
The SilverStripe core and modules require permission to commit code.
Please have a look at our [contributors guidelines](contributing) to find out how you can gain access.
### Configuring subversion for correct newline handling
You should configure your subversion client to set the ''svn:eol-style'' property to ''native'' on all text files checked into the system. This will ensure that we don't run into troubles, getting non-unix newlines inside our repository.
To do this, edit your ''~/.subversion/config'' file on your development machine, and add the following settings. Note that if you already have ''[miscellany]'' and ''[auto-props]'' sections, you should combine these settings with the existing sections, rather than doing a blind copy & paste to the end of the file.
:::php
[miscellany]
enable-auto-props = yes
// Section for configuring automatic properties.
[auto-props]
*.js = svn:eol-style=native
*.html = svn:eol-style=native
*.inc = svn:eol-style=native
*.css = svn:eol-style=native
*.php = svn:eol-style=native
*.xml = svn:eol-style=native
*.csv = svn:eol-style=native
*.htm = svn:eol-style=native
*.ini = svn:eol-style=native
*.json = svn:eol-style=native
*.php5 = svn:eol-style=native
*.py = svn:eol-style=native
*.ss = svn:eol-style=native
*.yml = svn:eol-style=native
*.yaml = svn:eol-style=native
*.xhtml = svn:eol-style=native
Note that if the repository gets out of whack, the following commands run on a linux box will correct things in the current working copy:
find | grep -v \._ | \
grep "\.\(js\|php\|css\|inc\|html\|html\|php5\|py\|json\|ini\|xml\|csv\)"\$ | \
xargs svn propset svn:eol-style native
find | grep -v \._ | \
grep "\.\(js\|php\|css\|inc\|html\|html\|php5\|py\|json\|ini\|xml\|csv\)"\$ | \
xargs dos2unix
### Feature Branches
For more complicated bugfixes or longer-term development, you may want to create a Feature Branch. For example, you might want
to add support for other rich-text-editors within the CMS - a complex task which can't be contained in a single patch.
Feature branches are a copy of trunk, and usually have a short lifetime in which active development happens.
**The feature branch maintainer is responsible for keeping his branch in sync with trunk and reintegrate when development
is complete.**
More information about ["Feature Branches"](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.commonpatterns.html#svn.branchmerge.commonpatterns.feature),
[merging changes](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.html) and [resolving conflicts](http://svnbook.red-bean.com/en/1.5/svn.tour.cycle.html#svn.tour.cycle.resolve).
#### Example: The 'nestedurls' branch
Example for a feature branch for the ''sapphire'' module called ''nestedurls''.
Creating the branch is a simple matter of running the ''svn cp'' command (see [SVN Book: "Creating a Branch"](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.using.html#svn.branchmerge.using.create)).
svn cp http://svn.silverstripe.com/open/modules/sapphire/trunk http://svn.silverstripe.com/open/modules/sapphire/branches/nestedurls
After creating a feature branch, you commit your changes as usual, but also merge in any new changes from trunk
(see [SVN Book: "Keeping your Branch in Sync"](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.basicmerging.html#svn.branchemerge.basicmerging.stayinsync)).
cd /your/nestedurls/working/copy
svn merge http://svn.silverstripe.com/open/modules/sapphire/trunk
Once you've finished your feature development (usually a timeframe around 4-8 weeks), you "reintegrate" your branch with the
trunk repository. This activity happens only once, and the feature branch has to be removed afterwards.
cd /your/trunk/working/copy
svn merge --reintegrate http://svn.silverstripe.com/open/modules/sapphire/branches/nestedurls
You can get information about the merge process (see
[SVN Book: "Mergeinfo and Previews"](http://svnbook.red-bean.com/en/1.5/svn.branchmerge.basicmerging.html#svn.branchmerge.basicmerging.mergeinfo)).
cd /your/nestedurls/working/copy
# revisions which are you still have to merge from trunk to your branch
svn mergeinfo http://svn.silverstripe.com/open/modules/sapphire/trunk --show-revs eligible
# revisions which are already merged from trunk to your branch
svn mergeinfo http://svn.silverstripe.com/open/modules/sapphire/trunk
### Troubleshooting
#### SVN for your own websites
Here is a step-by-step guide on how to work with SVN on your own site. It oversimplifies some aspects, but it is a good
introduction. NOTE: you will need SSH and SVN installed and available on your server.
* Install LAMP / WAMP and an SVN application (Tortoise SVN on Windows)
* Buy an SVN repository: http://www.SVNrepository.com/ OR set one up on your own server or look at freeby alternatives.
* Go to your SVN repository server and create a new repository - I would recommend to name it after the site you are about to setup, e.g. myfirstsite.com.
* Create / go to web folder on local LAMP/WAMP
* SVN "checkout" your empty repository (e.g. http://sunny.SVNrepository.com/SVN/myaccountname/myfirstsite.com).
* SVN "propedit" SVN:externals, add the following SVN property to the root directory:
SVN:externals (also add your own general modules here, etc... etc... this should be a long list):
cms http://SVN.silverstripe.com/open/modules/cms/branches/2.4
sapphire http://SVN.silverstripe.com/open/modules/sapphire/branches/2.4
* SVN "update" your project. All the various files should be imported now.
* SVN "commit" your externals.
* In the root directory, create the following files: _ss_environment.php.sample, .htacess.sample and "commit" these to your repository.
* Copy in local LAMP / WAMP environment: _ss_environment.php.sample to _ss_environment.php; and .htacess.sample to .htacess
* Make sure that .htaccess and _ss_environment.php files are excluded from any commits. This is another SVN property attached to the root directory:
SVN:ignore:
.htaccess
_ss_environment.php
assets
* Create assets folder in root directory
* Your site should now be ready on your local WAMP / LAMP. You can now create a mysite and themes folder, add all your files, edit, bla bla until your site is ready. Then SVN "add" and SVN "commit" all your files to your repository (usually, you do many commits)
* Once you have created the site locally and committed it to your repository you should SSH to your web server (recommended application for windows is PUTTY)
* Once logged in to your web server, browse to the root web folder
* Make sure SVN is installed on the server (just type SVN help or something to check).
* SSH prompt, type:
SVN checkout http://sunny.SVNrepository.com/SVN/myaccountname/myfirstsite.com .
<div class="hint" markdown="1">
DOT at the end to check out files to current directory
</div>
* You should now have all your files on your webserver
* Copy on the server (using SSH)
cp _ss_environment.php.sample _ss_environment.php
cp .htacess.sample .htacess
* Edit these files: _ss_environment.php.sample , .htacess.sample, using the following SSH commands (if the nano application is not available then try pico):
nano _ss_environment.php.sample
nano .htacess.sample
* Create a folder called assets and make sure permissions are set correctly
* Website should now be up and running. (run dev/build to start).
#### A few point additional points:
* The whole concept of tags and branches have been left out, just to simplify.
* We have also left out the idea of a test and live site. The instructions here can be used to setup a test site. Once you are happy with a test site you can move the code to a live site using the SVN "merge" command. In principle, this is how it works: open SSH and go to the root directory of the live site. Then type:
svn merge http://mysvnrepository/branches/live/ http://mysvnrepository/branches/test/
* If you want to update a repository, but you want the repository on the webserver to be locked to a version then you need set the svn:externals as follows:
cms -r1234567 http://svn.silverstripe.com/open/modules/cms/branches/2.4
where 1234567 is the revision of your repository that you want to use
* If you want to get a better understanding of what is going on in a repository then use the following SVN commands: SVN "status" and SVN "info".
* You can not and should not make any changes to any of the core modules and other modules added with svn:externals
### Related
* [contributing](contributing)
* [release process](release-process)

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,413 @@
# Advanced Template Syntax
The following control codes are available. For a more details list see [built-in-page-controls](/reference/built-in-page-controls):
### Variables
:::ss
$Property
$Property(param)
$Property.SubProperty
These **variables** will call a method/field on the object and insert the returned value as a string into the template.
* `$Property` will call `$obj->Property()` (or the field `$obj->Property`)
* `$Property(param)` will call `$obj->Property("param")`
* `$Property.SubProperty` will call `$obj->Property()->SubProperty()` (or field equivalents)
If a variable returns a string, that string will be inserted into the template. If the variable returns an object, then
the system will attempt to render the object through its forTemplate() method. If the `forTemplate()` method has not been
defined, the system will return an error.
Note you also cannot past a variable into a variable, so using `$Property($Value)` within your template will not work
### Includes
Within SilverStripe templates we have the ability to include other templates from the Includes directory using the SS
'include' tag. For example, the following code would include the `Includes/SideBar.ss` code:
:::ss
<% include SideBar %>
The "include" tag can be particularly helpful for nested functionality. In this example, the include only happens if
a variable is true
:::ss
<% if CurrentMember %>
<% include MembersOnlyInclude %>
<% end_if %>
You can also perform includes using the Requirements Class via the template controls. See the section on
[Includes in Templates](requirements#including_inside_template_files) for more details and examples.
:::ss
<% require themedCSS(LeftNavMenu) %>
### Controls
:::ss
<% control Property %>
... content ...
<% end_control %>
<% control Property.SubProperty %>
... content ...
<% end_control %>
<% control Property(param) %>
... content ...
<% end_control %>
Control blocks reference the same methods / fields as variables. Think of it as a foreach loop in PHP or other template
languages. `<% control Property %>` gets the same data as `$Property`. However, instead of interpreting the result as a
string, control blocks interpret the result as an object or a array of objects. The content between `<% control %>` and
`<% end_control %>` acts as a sub-template that is used to render the object returned.
In this example, `$A` and `$B` refer to `$obj->Property()->A()` and `$obj->Property()->B()`.
:::ss
<% control Property %>
<span>$A</span>
<span>$B</span>
<% end_control %>
If the method/field returned is an iterator such as a `[api:DataObject]`, then the control block will be repeated for
each element of that iterator. This is the cornerstone of all menu and list generation in SilverStripe.
In this example, `Menu(1)` returns a `[api:DataObjectSet]` listing each top level main menu item (for more info on `Menu(1)`:
[Making a Navigation System](/tutorials/1-building-a-basic-site#Making-a-Navigation-System)). The `<a>`
tag is repeated once for each main menu item, and the `$Link` and `$Title` values for each menu item is substituted in.
:::ss
<% control Menu(1) %>
<a href="$Link">$Title</a>
<% end_control %>
### If blocks
:::ss
<% if Property %>
... optional content ...
<% else_if OtherProperty %>
... alternative content ...
<% else %>
... alternative content ...
<% end_if %>
<% if Property == value %>
<% else %>
<% end_if %>
<% if Property != value %>
<% end_if %>
<% if Property && Property2 %>
<% end_if %>
<% if Property || Property2 %>
<% end_if %>
If blocks let you mark off optional content in your template. The optional content will only be shown if the requested
field / method returns a nonzero value. In the second syntax, the optional content will only be shown if the requested
field / method returns the value you specify. You should **not** include quotes around the value.
The `<% else %>` blocks perform as you would expect - content between `<% else %>` and `<% end_if %>` is shown if the first
block fails. `<% else %>` is an optional part of the syntax - you can just use `<% if %>` and `<% end_if %>` if that's
appropriate.
### Modulus and MultipleOf
New in 2.4 you can use 2 new controls $Modulus and $MultipleOf to help build column layouts.
:::ss
$Modulus(value, offset) // returns an int
$MultipleOf(factor, offset) // returns a boolean.
The following example demonstrates how you can use $Modulus(4) to generate custom column names based on your control statement. Note that this works for any control statement (not just children)
:::ss
<% control Children %>
<div class="column-{$Modulus(4)}">
...
</div>
<% end_control %>
Will return you column-3, column-2, column-1, column-0, column-3 etc. You can use these as styling hooks to float, position as you need.
You can also use $MultipleOf(value, offset) to help build columned layouts. In this case we want to add a <br> after every 3th item
:::ss
<% control Children %>
<% if MultipleOf(3) %>
<br>
<% end_if %>
<% end_control %>
### Comments
Using standard HTML comments is supported. These comments will be included in the published site.
:::ss
$EditForm <!-- Some Comment About the Edit Form -->
However you can also use special SilverStripe comments which will be stripped out of the published site. This is useful
for adding notes for other developers but for things you don't want published in the public html.
:::ss
$EditForm <%-- This is Located in MemberEditForm.php --%>
### Formatting Template Values
The following example takes the Title field of our object, casts it to a `[api:Varchar]` object, and then calls
the `$XML` object on that Varchar object.
:::ss
<% control Title %>
$XML
<% end_control %>
Note that this code can be more concisely represented as follows:
:::ss
$Title.XML
See [data-types](/topics/data-types) for more information.
### Escaping
Sometimes you will have template tags which need to roll into one another. This can often result in SilverStripe looking
for a "FooBar" value rather than a "Foo" and then "Bar" value or when you have a string directly before or after the
variable you will need to escape the specific variable. In the following example `$Foo` is `3`.
:::ss
$Foopx // returns "" (as it looks for a Foopx value)
{$Foo}px // returns "3px" (CORRECT)
Or when having a `$` sign in front of the variable
:::ss
$$Foo // returns ""
${$Foo} // returns "$3"
### Partial Caching
From SilverStripe 2.4 you can specify a block to cache between requests
:::ss
<% cacheblock 'slowoperation', LastEdited %>
$SlowOperation
<% end_cacheblock %>
See [partial-caching](/reference/partial-caching) for more information.
## Built In Template Variables and Controls
Out of the box, the template engine gives you lots of neat little variables and controls which you will find useful. For
a list of all the controls see [built-in-page-controls](/reference/built-in-page-controls).
## Creating your own Template Variables and Controls
There are two ways you can extend the template variables you have available. You can create a new database field in your
`$db` or if you do not need the variable to be editable in the cms you can create a function which returns a value in your
`Page.php` class.
:::php
**mysite/code/Page.php**
...
function MyCustomValue() {
return "Hi, this is my site";
}
Will give you the ability to call `$MyCustomValue` from anywhere in your template.
:::ss
I've got one thing to say to you: <i>$MyCustomValue</i>
// output "I've got one thing to say to you: <i>Hi, this is my site</i>"
Your function could return a single value as above or it could be a subclass of `[api:ArrayData]` for example a
`[api:DataObject]` with many values then each of these could be accessible via a control loop
:::php
..
function MyCustomValues() {
return new ArrayData(array("Hi" => "Kia Ora", "Name" => "John Smith"));
}
And now you could call these values by using
:::ss
<% control MyCustomValues %>
$Hi , $Name
<% end_control %>
// output "Kia Ora , John Smith"
Or by using the dot notation you would have
:::ss
$MyCustomValues.Hi , $MyCustomValues.Name
// output "Kia Ora , John Smith"
### Side effects
All functions that provide data to templates must have no side effects, as the value is cached after first access.
For example, this Controller method
:::php
private $counter = 0;
function Counter() {
$this->counter += 1;
return $this->counter;
}
and this template
:::ss
$Counter, $Counter, $Counter
will give "1, 1, 1", not "1, 2, 3"
## Calling templates from PHP code
This is all very well and good, but how do the templates actually get called?
Templates do nothing on their own. Rather, they are used to render *a particular object*. All of the `<% if %>`, `<%control %>`,
and variable codes are methods or parameters that are called *on that object*. All that is necessary is
that the object is an instance of `[api:ViewableData]` (or one of its subclasses).
The key is `[api:ViewableData::renderWith()]`. This method is passed a For example, within the controller's default action,
there is an instruction of the following sort:
:::php
$controller->renderWith("TemplateName");
Here's what this line does:
* First `renderWith()` constructs a new object: `$template = new SSViewer("TemplateName");`
* `[api:SSViewer]` will take the content of `TemplateName.ss`, and turn it into PHP code.
* Then `renderWith()` passes the controller to `$template->process($controller);`
* `SSViewer::process()` will execute the PHP code generated from `TemplateName.ss` and return the results.
`renderWith()` returns a string - the populated template. In essence, it uses a template to cast an object to a string.
`renderWith()` can also be passed an array of template names. If this is done, then `renderWith()` will use the first
available template name.
Below is an example of how to implement renderWith. In the example below the page is rendered using the myAjaxTemplate
if the page is called by an ajax function (using `[api:Director::is_ajax()]`). Note that the index function is called by
default if it exists and there is no action in the url parameters.
:::php
class MyPage_Controller extends Page_Controller {
function init(){
parent::init();
}
function index() {
if(Director::is_ajax()) {
return $this->renderWith("myAjaxTemplate");
}
else {
return Array();// execution as usual in this case...
}
}
}
### How does ViewableData work?
ViewableData provides two methods that perform the casting necessary for templates to work as we have described.
* `obj("Parameter")` - Return the given field / method as an object, casting if necessary
* `XML_val("Parameter)` - Return the given field / method as a scalar, converting to an XML-safe format and casting if
necessary
These methods work as described in the syntax section above. SSViewer calls these methods when processing templates.
However, if you want, you can call `obj()` and `val()` yourself.
## Fragment Link rewriting
Fragment links are links with a "#" in them. A frequent use-case is to use fragment links to point to different
sections of the current page. For example, we might have this in our template.
For, example, we might have this on http://www.example.com/my-long-page/
:::ss
<ul>
<li><a href="#section1">Section 1</a></li>
<li><a href="#section2">Section 2</a></li>
</ul>
So far, so obvious. However, things get tricky because of we have set our `<base>` tag to point to the root of your
site. So, when you click the first link you will be sent to http://www.example.com/#section1 instead of
http://www.example.com/my-long-page/#section1
In order to prevent this situation, the SSViewer template renderer will automatically rewrite any fragment link that
doesn't specify a URL before the fragment, prefixing the URL of the current page. For our example above, the following
would be created:
:::ss
<ul>
<li><a href="my-long-page/#section1">Section 1</a></li>
<li><a href="my-long-page/#section2">Section 2</a></li>
</ul>
There are cases where this can be unhelpful. HTML fragments created from Ajax responses are the most common. In these
situations, you can disable fragment link rewriting like so:
:::php
SSViewer::setOption('rewriteHashlinks', false);
## Casting and Escaping
Method and variables names that deal with strings or arrays of strings should have one of the following 5 prefixes:
* **RAW_** Raw plain text, as a user would like to see it, without any HTML tags
* **XML_** Text suitable for insertion into an HTML or XML data-set. This may contain HTML content, for example if the
content came from a WYSIWYG editor.
* **JS_** Data that can safely be inserted into JavaScript code.
* **ATT_** Data that can safely be inserted into an XML or HTML attribute.
The same prefixes are used for both strings and arrays of strings. We did this to keep things simple: passing a string
with the wrong encoding is a far subtler a problem than passing an array instead of a string, and therefore much harder
to debug.
## Related
* [Templates](/topics/templates)
* [Themes](/topics/themes)
* [Developing Themes](theme-development)
* [Widgets](/topics/widgets)
* [Images](/reference/image)
* [Built in page controls](/reference/built-in-page-controls)
* [Including Templates](/reference/requirements)

View File

@ -0,0 +1,36 @@
# BBcode support
A bbcode tags help box shows when the "BBCode help" link is clicked. Javascript is required for this to work.
It has been encorporated as a modified version of PEAR's [HTML_BBCodeParser](http://pear.php.net/package/HTML_BBCodeParser)
BBCode is used by default in the [blog](http://silverstripe.org/blog-module) and
[forum](http://silverstripe.org/forum-module) modules.
## Usage
To add bbcode parsing to a template, instead of $Content use:
:::php
$Content.Parse(BBCodeParser)
BBCode can be enabled in comments by adding the following to _config.php
:::php
PageComment::enableBBCode();
## Supported Tags
- [b]Bold[/b]
- [i]Italics[/i]
- [u]Underlined[/u]
- [s]Struck-out[/s]
- [color=blue]blue text[/color]
- [align=right]right aligned[/align]
- [code]Code block[/code]
- [email]you@yoursite.com[/email]
- [email=you@yoursite.com]Email[/email]
- [ulist][*]unordered item 1[/ulist]
- [img]http://www.website.com/image.jpg[/img]
- [url]http://www.website.com/[/url]
- [url=http://www.website.com/]Website[/url]

View File

@ -0,0 +1,345 @@
# Built-in Page Controls
Ever wonder when you use `$Title` and `<% Control Children %>` what else you can call in the templates?. This page is
here to help with a guide on what template controls you can call.
**Note for advanced users:** These built-in page controls are defined in the `[api:SiteTree]` classes, which are the
'root' data-object and controller classes for all the sites. So if you're dealing with something that isn't a sub-class
of one of these, our handy reference to 'built-in page controls' won't be so relevant.
## Page controls that can't be nested
These page controls are defined on the **controller** which means they can only be used at a top level, not nested
within another page control.
### Controlling Menus Datafeeds
#### <% control Menu(1) %>, <% control Menu(2) %>, ...
Returns a fixed level menu. Because this only works in the top level, you can't use it for nested menus. Used <%
control Children %> instead. You can nest `<% control Children %>`.
#### <% control ChildrenOf(page-url) %>
This will create a datafeed of the children of the given page. Handy if you want a list of the subpages under staff (eg
the staff) on the homepage etc
### Controlling Certain Pages
#### <% control Level(1) %>, <% control Level(2) %>, $Level(1).Title, $Level(2).Content, etc
Returns the current section of the site that we're in, at the level specified by the numbers. For example, imagine
you're on the page __about us > staff > bob marley__:
* `<% control Level(1) %>` would return the about us page
* `<% control Level(2) %>` would return the staff page
* `<% control Level(3) %>` would return the bob marley page
#### <% control Page(my-page) %>$Title<% end_control %>
"Page" will return a single page from the site tree, looking it up by URL. You can use it in the `<% control %>` format.
Can't be called using $Page(my-page).Title.
## Page controls that can be used anywhere
These are defined in the data-object and so can be used as nested page controls. Lucky us! we can control Children of
Children of Children for example.
### Conditional Logic
SilverStripe supports a simple set of conditional logic
:::ss
<% if Foo %>
// if Foo is true or an object do this
<% else_if Bar %>
// if Bar is true or an object do this
<% else %>
// then do this by default
<% end_if %>
See more information on conditional logic on [templates](templates).
### Site wide settings
Since 2.4.0, SilverStripe provides a generic interface for accessing global properties such as *Site name* or *Site tag
line*. This interface is implemented by the [api:SiteConfig] class.
### Controlling Parents and Children
#### <% control Children %>
This will return the children of the current page as a nested datafeed. Useful for nested navigations such as pop-out
menus.
#### <% control AllChildren %>
This will show all children of a page even if the option 'show in menus?' is unchecked in the tab panel behaviour.
#### <% control Parent %> or $Parent.Title, $Parent.Content, etc
This will return the parent page. The $ variable format lets us reference an attribute of the parent page directly.
### Site Navigation - Breadcrumbs
#### <% control Breadcrumbs %>
This will return a breadcrumbs widgets for the given page. You can call this on any data-object, so, for example, you
could display the breadcrumbs of every search result if you wanted. It has a few options.
#### <% control Breadcrumbs(3) %>
Will return a maximum of 3 pages in the breadcrumb list, this can be handy if you're wanting to put breadcrumbs in a
place without spilling
#### <% control Breadcrumbs(3, true) %>
Will return the same, but without any links. This is handy if you're wanting to put the breadcrumb list into another
link tag.
### Links and Classes
#### $LinkingMode, $LinkOrCurrent and $LinkOrSection
These return different linking modes. $LinkingMode provides the greatest control, outputting 3 different strings:
* link: Neither this page nor any of its children are current open.
* section: A child of this page is currently open, which means that we're currently in this section of the site.
* current: This page is currently open.
A useful way of using this is in your menus. You can use the following code below to generate an class="current" or
class="section" on your links. Take the following code
:::ss
<li><a href="$Link" class="$LinkingMode">$Title</a></li>
When viewed on the Home page it will render like this
:::ss
<li><a href="home/" class="current">Home</a></li>
$LinkOrCurrent ignores the section status, returning link instead. $LinkOrSection ingores the current status, returning
section instead. Both of these options can simplify your CSS when you only have 2 different cases to consider.
#### <% if LinkOrCurrent = current %>
This is an alternative way to set up your menus - if you want different HTML for the current menu item, you can do
something like this:
:::ss
<% if LinkOrCurrent = current %>
<strong>$Title</strong>
<% else %>
<a href="$Link">$Title</a>
<% end_if %>
#### <% if LinkOrSection = section %>
Will return true if you are on the current page OR a child page of the page. Useful for menus which you only want to
show a second level menu when you are on that page or a child of it
#### <% if InSection(page-url) %>
This if block will pass if we're currently on the page-url page or one of its children.
### Titles and CMS Defined Options
#### $MetaTags
This returns a segment of HTML appropriate for putting into the `<head>` tag. It will set up title, keywords and
description meta-tags, based on the CMS content. If you don't want to include the title-tag (for custom templating), use
**$MetaTags(false)**.
#### $MenuTitle
This is the title that you should put into navigation menus. CMS authors can choose to put a different menu title from
the main page title.
#### $Title
This is the title of the page which displays in the browser window and usually is the title of the page.
:::ss
<h1>$Title</h1>
#### $URLSegment
This returns the part of the URL of the page you're currently on. Could be handy to use as an id on your body-tag. (
when doing this, watch out that it doesn't create invalid id-attributes though.). This is useful for adding a class to
the body so you can target certain pages. Watch out for pages named clear or anything you might have used in your CSS
file
:::ss
<body class="$URLSegment">
#### $ClassName
Returns the ClassName of the PHP object. Eg if you have a custom HomePage page type with $ClassName in the template, it
will return "HomePage"
#### $BaseHref
Returns the base URL for the current site. This is used to populate the `<base>` tag by default, so if you want to
override `<% base_tag %>` with a specific piece of HTML, you can do something like `<base href="$BaseHref">``</base>`
### Controlling Members and Visitors Data
#### <% control CurrentMember %>, <% if CurrentMember %> or $CurrentMember.FirstName
CurrentMember returns the currently logged in member, if there is one. All of their details or any special Member page
controls can be called on this. Alternately, you can use `<% if CurrentMember %>` to detect whether someone has logged
in. To Display a welcome message you can do
:::ss
<% if CurrentMember %>
Welcome Back, $CurrentMember.FirstName
<% end_if %>
If the user is logged in this will print out
:::ss
Welcome Back, Admin
#### <% if PastMember %>, <% if PastVisitor %>
These controls detect the visitor's previous experience with the site:
* $PastVisitor will return true if the visitor has been to the site before
* $PastMember will return true if the visitor has signed up or logged in on the site before
### Date and Time
#### $Now.Nice, $Now.Year
$Now returns the current date. You can call any of the methods from the `[api:Date]` class on
it.
#### $Created.Nice, $Created.Ago
$Created returns the time the page was created, $Created.Ago returns how long ago the page was created. You can also
call any of methods of the `[api:Date]` class on it.
#### $LastEdited.Nice, $LastEdited.Ago
$LastEdited returns the time the page was modified, $LastEdited.Ago returns how long ago the page was modified.You can also
call any of methods of the `[api:Date]` class on it.
### DataObjectSet Options
If you are using a DataObjectSet you have a wide range of methods you can call on it from the templates
#### <% if Even %>, <% if Odd %>, $EvenOdd
These controls can be used to do zebra-striping. $EvenOdd will return 'even' or 'odd' as appropriate.
#### <% if First %>, <% if Last %>, <% if Middle %>, $FirstLast
These controls can be used to set up special behaviour for the first and last records of a datafeed. `<% if Middle %>` is
set when neither first not last are set. $FirstLast will be 'first', 'last', or ''
#### $Pos, $TotalItems
$TotalItems will return the number of items on this page of the datafeed, and Pos will return a counter starting at 1.
#### $Top
When you're inside a control loop in your template, and want to reference methods on the current controller you're on,
breaking out of the loop to get it, you can use $Top to do so. For example:
:::ss
$URLSegment
<% control News %>
$URLSegment <!-- may not return anything, as you're requesting URLSegment on the News objects -->
$Top.URLSegment <!-- returns the same as $URLSegment above -->
<% end_control %>
## Properties of a datafeed itself, rather than one of its items
If we have a control such as `<% control SearchResults %>`, there are some properties, such as $SearchResults.NextLink,
that aren't accessible within `<% control SearchResults %>`. These can be used on any datafeed.
### Search Results
#### <% if SearchResults.MoreThanOnePage %>
Returns true when we have a multi-page datafeed, restricted with a limit.
#### $SearchResults.NextLink, $SearchResults.PrevLink
This returns links to the next and previous page in a multi-page datafeed. They will return blank if there's no
appropriate page to go to, so $PrevLink will return blank when you're on the first page. You can therefore use <% if
PrevLink %> to keep your template tidy.
#### $SearchResults.CurrentPage, $SearchResults.TotalPages
CurrentPage returns the number of the page you're currently on, and TotalPages returns the total number of pages.
#### $SearchResults.TotalItems
This returns the total number of items across all pages.
#### <% control SearchResults.First %>, <% control SearchResults.Last %>
These controls return the first and last item on the current page of the datafeed.
#### <% control SearchResults.Pages %>
This will return another datafeed, listing all of the pages in this datafeed. It will have the following data
available:
* **$PageNum:** page number, starting at 1
* **$Link:** a link straight to that page
* `<% if CurrentBool %>`:** returns true if you're currently on that page
`<% control SearchResults.Pages(30) %>` will show a maximum of 30 pages, useful in situations where you could get 100s of
pages returned.
#### $SearchResults.UL
This is a quick way of generating a `<ul>` containing an `<li>` and `<a>` for each item in the datafeed. Usually too
restricted to use in a final application, but handy for debugging stuff.
## Quick Reference
Below is a list of fields and methods that are typically available for templates (grouped by their source) - use this as
a quick reference (not all of them are described above):
### All methods available in Page_Controller
$NexPageLink, $Link, $RelativeLink, $ChildrenOf, $Page, $Level, $Menu, $Section2, $LoginForm, $SilverStripeNavigator,
$PageComments, $Now, $LinkTo, $AbsoluteLink, $CurrentMember, $PastVisitor, $PastMember, $XML_val, $RAW_val, $SQL_val,
$JS_val, $ATT_val, $First, $Last, $FirstLast, $MiddleString, $Middle, $Even, $Odd, $EvenOdd, $Pos, $TotalItems,
$BaseHref, $Debug, $CurrentPage, $Top
### All fields available in Page_Controller
$ID, $ClassName, $Created, $LastEdited, $URLSegment, $Title, $MenuTitle, $Content, $MetaTitle, $MetaDescription,
$MetaKeywords, $ShowInMenus, $ShowInSearch, $HomepageForDomain, $ProvideComments, $Sort, $LegacyURL, $HasBrokenFile,
$HasBrokenLink, $Status, $ReportClass, $ParentID, $Version, $EmailTo, $EmailOnSubmit, $SubmitButtonText,
$OnCompleteMessage, $Subscribe, $AllNewsletters, $Subject, $ErrorCode, $LinkedPageID, $RedirectionType, $ExternalURL,
$LinkToID, $VersionID, $CopyContentFromID, $RecordClassName
### All methods available in Page
$Link, $LinkOrCurrent, $LinkOrSection, $LinkingMode, $ElementName, $InSection, $Comments, $Breadcrumbs, $NestedTitle,
$MetaTags, $ContentSource, $MultipleParents, $TreeTitle, $CMSTreeClasses, $Now, $LinkTo, $AbsoluteLink, $CurrentMember,
$PastVisitor, $PastMember, $XML_val, $RAW_val, $SQL_val, $JS_val, $ATT_val, $First, $Last, $FirstLast, $MiddleString,
$Middle, $Even, $Odd, $EvenOdd, $Pos, $TotalItems, $BaseHref, $CurrentPage, $Top
### All fields available in Page
$ID, $ClassName, $Created, $LastEdited, $URLSegment, $Title, $MenuTitle, $Content, $MetaTitle, $MetaDescription,
$MetaKeywords, $ShowInMenus, $ShowInSearch, $HomepageForDomain, $ProvideComments, $Sort, $LegacyURL, $HasBrokenFile,
$HasBrokenLink, $Status, $ReportClass, $ParentID, $Version, $EmailTo, $EmailOnSubmit, $SubmitButtonText,
$OnCompleteMessage, $Subscribe, $AllNewsletters, $Subject, $ErrorCode, $LinkedPageID, $RedirectionType, $ExternalURL,
$LinkToID, $VersionID, $CopyContentFromID, $RecordClassName

View File

@ -0,0 +1,150 @@
# Complex Table Field
## Introduction
Shows a group of DataObjects as a (readonly) tabular list (similiar to `[api:TableListField]`.)
You can specify limits and filters for the resultset by customizing query-settings (mostly the ID-field on the other
side of a one-to-many-relationship).
See `[api:TableListField]` for more documentation on the base-class
## Source Input
See `[api:TableListField]`.
## Setting Parent/Child-Relations
ComplexTableField tries to determine the parent-relation automatically by looking at the $has_one property on the listed
child, or the record loaded into the surrounding form (see getParentClass() and getParentIdName()). You can force a
specific parent relation:
:::php
$myCTF->setParentClass('ProductGroup');
## Customizing Popup
By default, getCMSFields() is called on the listed DataObject.
You can override this behaviour in various ways:
:::php
// option 1: implicit (left out of the constructor), chooses based on Object::useCustomClass or specific instance
$myCTF = new ComplexTableField(
$this,
'MyName',
'Product',
array('Price','Code')
)
// option 2: constructor
$myCTF = new ComplexTableField(
$this,
'MyName',
'Product',
array('Price','Code'),
new FieldSet(
new TextField('Price')
)
)
// option 3: constructor function
$myCTF = new ComplexTableField(
$this,
'MyName',
'Product',
array('Price','Code'),
'getCustomCMSFields'
)
## Customizing Display & Functionality
If you don't want several functions to appear (e.g. no add-link), there's several ways:
* Use ComplexTableField->setPermissions(array("show","edit")) to limit the functionality without touching the template
(more secure). Possible values are "show","edit", "delete" and "add".
* Subclass ComplexTableField and override the rendering-mechanism
* Use ComplexTableField->setTemplate() and ComplexTableField->setTemplatePopup() to provide custom templates
### Customising fields and Requirements in the popup
There are several ways to customise the fields in the popup. Often you would want to display more information in the
popup as there is more real-estate for you to play with.
ComplexTableField gives you several options to do this. You can either
* Pass a FieldSet in the constructor.
* Pass a String in the constructor.
The first will simply add the fieldset to the form, and populate it with the source class.
The second will call the String as a method on the source class (Which should return a FieldSet) of fields for the
Popup.
You can also customise Javascript which is loaded for the Lightbox. As Requirements::clear() is called when the popup is
instantiated, ComplexTableField will look for a function to gather any specific requirements that you might need on your
source class. (e.g. Inline Javascript or styling).
For this, create a function called "getRequirementsForPopup".
## Getting it working on the front end (not the CMS)
Sometimes you'll want to have a nice table on the front end, so you can move away from relying on the CMS for maintaing
parts of your site.
You'll have to do something like this in your form:
:::php
$tableField = new ComplexTableField(
$controller,
'Works',
'Work',
array(
'MyField' => 'My awesome field name'
),
'getPopupFields'
);
$tableField->setParentClass(false);
$fields = new FieldSet(
new HiddenField('ID', ''),
$tableField
);
You have to hack in an ID on the form, as the CMS forms have this, and front end forms usually do not.
It's not a perfect solution, but it works relatively well to get a simple ComplexTableField up and running on the front
end.
To come: Make it a lot more flexible so tables can be easily used on the front end. It also needs to be flexible enough
to use a popup as well, out of the box.
## Subclassing
Most of the time, you need to override the following methods:
* ComplexTableField->sourceItems() - querying
* ComplexTableField->DetailForm() - form output
* ComplexTableField_Popup->saveComplexTableField() - saving
### Examples
* `[api:AssetTableField]`
* `[api:MemberTableField]`
## API Documentation
`[api:ComplexTableField]`
## Todo
* Find a less fragile solution for accessing this field through the main controller and ReferencedField, e.g. build a
seperate CTF-instance (doesn't necessarly have to be connected to the original by ReferencedField)
* Control width/height of popup by constructor (hardcoded at the moment)
* Integrate search from MemberTableField.php directly on ComplexTableField
* Less performance-hungry implementation of detail-view paging (don't return all items on a single view)
* Use automatic has-many and many-many functions to return a ComponentSet rather than building the join manually
* Javascript/Ajax-Sorting (see http://www.activewidgets.com/grid/ and http://openrico.org/rico/livegrid.page)

View File

@ -0,0 +1,129 @@
# Database Structure
SilverStripe is currently hard-coded to use a fix mapping between data-objects and the underlying database structure -
opting for "convention over configuration". This page details what that database structure is.
## Base tables
Each direct sub-class of DataObject will have its own table.
The following fields are always created.
* ID: Primary Key
* ClassName: An enumeration listing this data-class and all of its subclasses.
* Created: A date/time field set to the creation date of this record
* LastEdited: A date/time field set to the date this record was last edited
Every object of this class **or any of its subclasses** will have an entry in this table
### Extra Fields
* Every field listed in the data object's **$db** array will be included in this table.
* For every relationship listed in the data object's **$has_one** array, there will be an integer field included in the
table. This will contain the ID of the data-object being linked to. The database field name will be of the form
"(relationship-name)ID", for example, ParentID.
### ID Generation
When a new record is created, we don't use the database's built-in auto-numbering system. Instead, we generate a new ID
by adding 1 to the current maximum ID.
## Subclass tables
At SilverStripe's heart is an object-relational model. And a component of object-oriented data is **inheritance**.
Unfortunately, there is no native way of representing inheritance in a relational database. What we do is store the
data sub-classed objects across **multiple tables**.
For example, suppose we have the following set of classes:
* Class SiteTree extends DataObject: Title, Content fields
* Class Page extends SiteTree: Abstract field
* Class NewsSection extends SiteTree: *No special fields*
* Class NewsArticle extend Page: ArticleDate field
The data for the following classes would be stored across the following tables:
* SiteTree
* ID: Int
* ClassName: Enum('SiteTree', 'Page', 'NewsArticle')
* Created: Datetime
* LastEdited: Datetime
* Title: Varchar
* Content: Text
* Page
* ID: Int
* Abstract: Text
* NewsArticle
* ID: Int
* ArticleDate: Date
The way it works is this:
* "Base classes" are direct sub-classes of DataObject. They are always given a table, whether or not they have special
fields. This is called the "base table"
* The base table's ClassName field is set to class of the given record. It's an enumeration of all possible
sub-classes of the base class (including the base class itself)
* Each sub-class of the base object will also be given its own table, *as long as it has custom fields*. In the
example above, NewsSection didn't have its own data and so an extra table would be redundant.
* In all the tables, ID is the primary key. A matching ID number is used for all parts of a particular record:
record #2 in Page refers to the same object as record #2 in SiteTree.
To retrieve a news article, SilverStripe joins the SiteTree, Page and NewsArticle tables by their ID fields. We use a
left-join for robustness; if there is no matching record in Page, we can return a record with a blank Article field.
## Staging and versioning
[todo]
## Schema auto-generation
SilverStripe has a powerful tool for automatically building database schemas. We've designed it so that you should never have to build them manually.
To access it, visit (site-root)/dev/build?flush=1. This script will analyze the existing schema, compare it to what's required by your data classes, and alter the schema as required.
Put the ?flush=1 on the end if you've added PHP files, so that the rest of the system will find these new classes.
It will perform the following changes:
* Create any missing tables
* Create any missing fields
* Create any missing indexes
* Alter the field type of any existing fields
* Rename any obsolete tables that it previously created to _obsolete_(tablename)
It **won't** do any of the following
* Deleting tables
* Deleting fields
* Rename any tables that it doesn't recognize - so other applications can co-exist in the same database, as long as their table names don't match a SilverStripe data class.
## Related code
The information documented in this page is reflected in a few places in the code:
* `[api:DataObject]`
* requireTable() is responsible for specifying the required database schema
* instance_get() and instance_get_one() are responsible for generating the database queries for selecting data.
* write() is responsible for generating the database queries for writing data.
* `[api:Versioned]`
* augmentWrite() is responsible for altering the normal database writing operation to handle versions.
* augmentQuery() is responsible for altering the normal data selection queries to support versions.
* augmentDatabase() is responsible for specifying the altered database schema to support versions.
* `[api:MySQLDatabase]`: getNextID() is used when creating new objects; it also handles the mechanics of
updating the database to have the required schema.
## Future work
* We realise that a fixed mapping between the database and object-model isn't appropriate in all cases. In particular,
it could be beneficial to set up a SilverStripe data-object as an interface layer to the databases of other
applications. This kind of configuration support is on the cards for development once we start looking more seriously
at providing avenues for clean integration between systems.
* Some developers have commented that the the database layer could be used to maintain the relational integrity of this
database structure. I don't know whether MySQL supports this or not, but in any case, this stuff would be available in
other database platforms if we chose to support them.
* We'd like to support more than just MySQL, however, there needs to be a pretty good reason for doing so since it will
become something that needs to be supported for the rest of SilverStripe's life and could easily become an albatross.
On the cards are MS SQL, PostgreSQL and SQLite.
* It could be desireable to implement a non-repeating auto-numbering system.

View File

@ -0,0 +1,196 @@
# DataObject
## Introduction
A single database record & abstract class for the data-access-model.
## Usage
* [datamodel](/topics/datamodel): The basic pricinples
* [data-types](/topics/data-types): Casting and special property-parsing
* `[api:DataObject]`: A "container" for DataObjects
## Basics
The call to `DataObject->getCMSFields()` is the centerpiece of every data administration interface in Silverstripe,
which returns a `[api:FieldSet]`''.
:::php
class MyPage extends Page {
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Content',new CheckboxField('CustomProperty'));
return $fields;
}
}
## Scaffolding Formfields
These calls retrieve a `[api:FieldSet]` for the area where you intend to work with the scaffolded form.
### For the CMS
* Requirements: SilverStripe 2.3.*
// bla
:::php
$fields = singleton('MyDataObject')->getCMSFields();
### For the Frontend
Used for simple frontend forms without relation editing or `[api:TabSet] behaviour. Uses `scaffoldFormFields()` by
default. To customize, either overload this method in your subclass, or decorate it by `DataObjectDecorator->updateFormFields()`.
* Requirements: SilverStripe 2.3.*
:::php
$fields = singleton('MyDataObject')->getFrontEndFields();
## Customizing Scaffolded Fields
* Requirements: SilverStripe 2.3.*
This section covers how to enhance the default scaffolded form fields from above. It is particularly useful when used
in conjunction with the `[api:ModelAdmin]` in the CMS to make relevant data administration interfaces.
### Searchable Fields
* Requirements: SilverStripe 2.3.*
The `$searchable_fields` property uses a mixed array format that can be used to further customize your generated admin
system. The default is a set of array values listing the fields.
Example: Getting predefined searchable fields
:::php
$fields = singleton('MyDataObject')->searchableFields();
Example: Simple Definition
:::php
class MyDataObject extends DataObject {
static $searchable_fields = array(
'Name',
'ProductCode'
);
}
Searchable fields will be appear in the search interface with a default form field (usually a TextField) and a default
search filter assigned (usually an ExactMatchFilter). To override these defaults, you can specify additional information
on `$searchable_fields`:
:::php
class MyDataObject extends DataObject {
static $searchable_fields = array(
'Name' => 'PartialMatchFilter',
'ProductCode' => 'NumericField'
);
}
If you assign a single string value, you can set it to be either a FormField or SearchFilter. To specify both, you can
assign an array:
:::php
class MyDataObject extends DataObject {
static $searchable_fields = array(
'Name' => array(
'field' => 'TextField',
'filter' => 'PartialMatchFilter',
),
'ProductCode' => array(
'title' => 'Product code #',
'field' => 'NumericField',
'filter' => 'PartialMatchFilter',
),
);
}
To include relations (''$has_one'', `$has_many` and `$many_many`) in your search, you can use a dot-notation.
:::php
class Team extends DataObject {
static $db = array(
'Title' => 'Varchar'
);
static $many_many = array(
'Players' => 'Player'
);
static $searchable_fields = array(
'Title',
'Players.Name',
);
}
class Player extends DataObject {
static $db = array(
'Name' => 'Varchar',
'Birthday' => 'Date'
);
static $belongs_many_many = array(
'Teams' => 'Team'
);
}
### Summary Fields
* Requirements: SilverStripe 2.3.*
Summary fields can be used to show a quick overview of the data for a specific DataObject record. Most common use is
their display as table columns, e.g. in the search results of a `[api:ModelAdmin]` CMS interface.
Example: Getting predefined summary fields
:::php
$fields = singleton('MyDataObject')->summaryFields();
Example: Simple Definition
:::php
class MyDataObject extends DataObject {
static $db = array(
'Name' => 'Text',
'OtherProperty' => 'Text',
'ProductCode' => 'Int',
);
static $summary_fields = array(
'Name',
'ProductCode'
);
}
To include relations in your summaries, you can use a dot-notation.
:::php
class OtherObject extends DataObject {
static $db = array(
'Title' => 'Varchar'
);
}
class MyDataObject extends DataObject {
static $db = array(
'Name' => 'Text'
);
static $has_one = array(
'OtherObject' => 'OtherObject'
);
static $summary_fields = array(
'Name',
'OtherObject.Title'
);
}
## API Documentation
`[api:DataObject]`

View File

@ -0,0 +1,172 @@
# DataObjectDecorator
## Introduction
Extensions (also referred to as decorators) allow for adding additional functionality to a `[api:DataObject]`.
In some cases, it can be easier to completely replace the used class throughout the core with your custom
implementation. Have a look at `[api:Object->useCustomClass()]`.
## Usage
Your Decorator will nee to be a subclass of DataObjectDecorator or the Extension class.
:::php
<?php
// mysite/code/CustomMember.php
class CustomMember extends DataObjectDecorator {
}
This defines your own extension where you can add your own functions, database fields or other properties you want.
After you create this extension however it does not yet apply it to your object. Next you need to tell SilverStripe what
class you want to extend.
### Adding a decorator to a built-in class
Sometimes you will want to add decorators to classes that you didn't make. For example, you might want to add the
ForumRole decorator to the Member object.
:::php
Object::add_extension('Class You Want To Override', 'Your Class Name');
For example above we want to override Member with a Custom Member so we would write the following
:::php
// add to mysite/_config.php
Object::add_extension('Member', 'CustomMember');</code>
## Implementation
### Adding extra database fields
Extra database fields can be added with a decorator by defining an **extraStatics()** method. These will be added to the table of the base object - the decorator will actually edit the $db, $has_one, etc static variables on load.
The function should return a map where the keys are the names of the static variables to update:
:::php
class CustomMember extends DataObjectDecorator {
function extraStatics() {
return array(
'db' => array(
'AvatarURL' => 'Varchar',
),
'has_one' => array(
'RelatedMember' => 'Member',
),
);
}
}
*NOTE*
If you want to add has_one or db items to a particular class, then that class **must** have that static variable
explicitly defined, even if it's just a blank array. For example, the decorator method above wouldn't work if you added
to a class that didn't have static $has_one explicitly declared on the object. This is because of PHP's crappy support
for statics.
### Modifying CMS Fields
The member class demonstrates an extension that allows you to update the default CMS fields for an object in a
decorator:
:::php
public function getCMSFields() {
...
$this->extend('updateCMSFields', $fields);
return $fields;
}
The $fields parameter is passed by reference, as it is an object.
:::php
public function updateCMSFields(FieldSet $fields) {
$fields->push(new TextField('Position', 'Position Title'));
$fields->push(new ImageField('Image', 'Profile Image'));
}
### Custom database generation
Some decorators are designed to transparently add more sophisticated data-collection capabilities to your data object.
For example, Versioned adds version tracking and staging to any data object that it is applied to. To do this, you need
to be able to create additional database tables and fields to keep your state stored in.
To do this, define an **augmentDatabase()** method on your decorator. This will be called when db/build is visited.
* You can query $this->owner for information about the data object, such as the fields it has
* You can use **DB::requireTable($tableName, $fieldList, $indexList)** to set up your new tables. This function takes
care of creating, modifying, or leaving tables as required, based on your desired schema.
### Custom write queries
If you have customised the generated database, then you probably want to change the way that writes happen. This is
used by Versioned to get an entry written in ClassName_versions whenever an insert/update happens.
To do this, define the **augmentWrite(&$manipulation)** method. This method is passed a manipulation array representing
the write about to happen, and is able to amend this as desired, since it is passed by reference.
### Custom relation queries
The other queries that you will want to customise are the selection queries, called by get & get_one. For example, the
Versioned object has code to redirect every request to ClassName_live, if you are browsing the live site.
To do this, define the **augmentSQL(SQLQuery &$query)** method. Again, the $query object is passed by reference and can
be modified as needed by your method. Instead of a manipulation array, we have a `[api:SQLQuery]` object.
### Additional methods
The other thing you may want to do with a decorator is provide a method that can be called on the DataObject that is
being decorated. For instance, you may add a publish() method to every DataObject that is decorated with Versioned.
This is as simple as defining a method called publish() on your decorator. Bear in mind, however, that instead of
$this, you should be referring to $this->owner.
* $this = The DataObjectDecorator object.
* $this->owner = The related DataObject object.
If you want to add your own internal properties, you can add this to the DataObjectDecorator, and these will be referred
to as $this->propertyName. Every DataObject has an associated DataObjectDecorator instance for each class that it is
decorated by.
:::php
class Customer extends DataObject {
static $has_one = array('Account'=>'Account');
static $extensions = array(
'CustomerWorkflow'
);
}
class Account extends DataObject {
static $db = array(
'IsMarkedForDeletion'=>'Boolean'
);
static $has_many = array('Customers'=>'Customer');
}
class CustomerWorkflow extends DataObjectDecorator {
function IsMarkedForDeletion() {
return ($this->owner->Account()->IsMarkedForDeletion == 1) ? true : false;
}
}
## API Documentation
`[api:DataObjectDecorator]`

View File

@ -0,0 +1,98 @@
# DataObjectSet
## Introduction
This class represents a set of `[api:DataObject]`s, such as the results of a query. It is the base for all
[datamodel](/topics/datamodel)-related querying. It implements the [Iterator
interface](http://php.net/manual/en/language.oop5.iterations.php) introduced in PHP5.
Relations (`has_many`/`many_many`) are described in `[api:ComponentSet]`, a subclass of DataObjectSet.
## Usage
### Getting the size
:::php
$mySet->Count();
### Getting an single element
:::php
$myFirstDataObject = $mySet->First();
$myLastDataObject = $mySet->Last();
### Getting multiple elements
:::php
$mySpecialDataObjects = $mySet->find('Status', 'special');
$startingFromTen = $mySet->getOffset(10);
$tenToTwenty = $mySet->getRange(10, 10);
### Getting one property
:::php
$myIDArray = $mySet->column('ID');
### Grouping
You can group a set by a specific column. Consider using `[api:SQLQuery]` with a *GROUP BY* statement for enhanced
performance.
:::php
$groupedSet = $mySet->groupBy('Lastname');
### Sorting
Sort a set by a specific column.
:::php
$mySet->sort('Lastname'); //ascending
$mySet->sort('Lastname', 'DESC'); //descending
This works on the object itself, so do NOT do something like this:
:::php
$sortedSet = $mySet->sort('Lastname'); //ascending
## Merge with other DataObjectSets
:::php
$myFirstSet->merge($mySecondSet);
// $myFirstSet now contains all combined values
### Mapping for Dropdowns
When using `[api:DropdownField]` and its numerous subclasses to select a value from a set, you can easily map
the records to a compatible array:
:::php
$map = $mySet->toDropDownMap('ID', 'Title');
$dropdownField = new DropdownField('myField', 'my label', $map);
### Converting to array
:::php
$myArray = $mySet->toArray();
### Checking for existence
It is good practice to check for empty sets before doing any iteration.
:::php
$mySet = DataObject::get('Players');
if($mySet->exists()) foreach($mySet as $player)
### Paging
DataObjects have native support for dealing with **pagination**.
See *setPageLimits*, *setPageLength*, etc.
FIXME Complete pagination documentation
## API Documentation
`[api:DataObjectSet]`

View File

@ -0,0 +1,63 @@
# Director
## Introduction
Director is the first step in the "execution pipeline". It parses the URL, matching it to one of a number of patterns,
and determines the controller, action and any argument to be used. It then runs the controller, which will finally run
the viewer and/or perform processing steps.
## Best Practices
* Checking for an Ajax-Request: Use Director::is_ajax() instead of checking for $_REQUEST['ajax'].
## Redirection
The Director class has a number of methods to facilitate 301 and 302 HTTP redirection.
* **Director::redirect("action-name")**: If there's no slash in the URL passed to redirect, then it is assumed that you
want to go to a different action on the current controller.
* **Director::redirect("relative/url")**: If there is a slash in the URL, it's taken to be a normal URL. Relative URLs
will are assumed to be relative to the site-root; so Director::redirect("home/") will work no matter what the current
URL is.
* **Director::redirect("http://www.absoluteurl.com")**: Of course, you can pass redirect() absolute URL s too.
* **Director::redirectPerm("any-url")**: redirectPerm takes the same arguments as redirect, but it will send a 301
(permanent) instead of a 302 (temporary) header. It improves search rankings, so this should be used whenever the
following two conditions are true:
* Nothing happens server-side prior to the redirection
* The redirection will always occur
* **Director::redirectBack()**: This will return you to the previous page. There's no permanent version of
redirectBack().
## Custom Rewrite Rules
You can influence the way URLs are resolved one of 2 ways
1. Adding rules to Director in `<yourproject>/_config.php` (See Default Rewrite Rules below for examples)
2. Adding rules in your extended Controller class via the *$url_handlers* static variable
See [controller](/topics/controller) for examples and explanations on how the rules get processed for both 1 and 2 above.
* Static redirect for specific URL
:::php
Director::addRules(100, array(
'myPermanentRedirect' => 'redirect:http://www.mysite.com'
));
## Default Rewrite Rules
SilverStripe comes with certain rewrite rules (e.g. for *admin/assets*).
* [sapphire/_config.php](http://open.silverstripe.org/browser/modules/sapphire/trunk/_config.php)
* [cms/_config.php](http://open.silverstripe.org/browser/modules/cms/trunk/_config.php)
## Links
* See ModelAsController class for details on controller/model-coupling
* See [execution-pipeline](/reference/execution-pipeline) for custom routing
## API Documentation
`[api:Director]`

View File

@ -0,0 +1,93 @@
# Execution Pipeline
## Introduction
This page documents all the steps from an URL request to the delivered page.
## .htaccess and RewriteRule
Silverstripe uses **[mod_rewrite](http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html)** to deal with page requests.
So instead of having your normal everyday `index.php` file which tells all, you need to look elsewhere.
The basic .htaccess file after installing SilverStripe look like this:
<file>
### SILVERSTRIPE START ###
<Files *.ss>
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Files>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !(\.gif$)|(\.jpg$)|(\.png$)|(\.css$)|(\.js$)
RewriteCond %{REQUEST_URI} ^(.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* sapphire/main.php?url=%1&%{QUERY_STRING} [L]
</IfModule>
### SILVERSTRIPE END ###
</file>
The `<Files>` section denies direct access to the template files from anywhere but the server itself.
The next section enables the rewriting engine and rewrites requests to `sapphire/main.php` if they meet the following
criteria:
* URI doesn't end in .gif, .jpg, .png, .css, or .js
* The requested file doesn't exist on the filesystem `sapphire/main.php` is called with the REQUEST_FILENAME (%1) as the `url` parameter and also appends the original
QUERY_STRING.
See the [mod_rewrite documentation](http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html) for more information on how
mod_rewrite works.
## main.php
All requests go through main.php, which sets up the environment and then hands control over to Director.
**See:** The API documentation of `[api:Main]` for information about how main.php processes requests.
## Director and URL patterns
main.php relies on Director to work out which controller should handle this request. Director will instantiate that
controller object and then call `[api:Controller::run()]`.
**See:** The API documentation of `[api:Director]` for information about how Director parses URLs and hands control over to a controller object.
In general, the URL is build up as follows: page/action/ID/otherID - e.g. http://www.mysite.com/mypage/addToCart/12.
This will add an object with ID 12 to the cart.
When you create a function, you can access the ID like this:
:::php
function addToCart ($request) {
$param = $r->allParams();
echo "my ID = ".$param["ID"];
$obj = DataObject::get("myProduct", $param["ID"]);
$obj->addNow();
}
## Controllers and actions
Controllers are the building blocks of your application.
**See:** The API documentation for `[api:Controller]`
You can access the following controller-method with /team/signup
:::php
class Team extends DataObject {}
class Team_Controller extends Controller {
function signup($id, $otherId) {
return $this->renderWith('MyTemplate');
}
}
## SSViewer template rendering
See [templates](/topics/templates) for information on the SSViewer template system.

View File

@ -0,0 +1,85 @@
# Form Field Types
This is a highlevel overview of available `[apiFormField]` subclasses. An automatically generated list is available through our [API](api:FormField)
## Formatted Input
* `[AjaxUniqueTextField](api:AjaxUniqueTextField)`: Text field that automatically checks that the value entered is unique for
the given set of fields in a given set of tables
* `[AutocompleteTextField](api:AutocompleteTextField)`
* `[ConfirmedPasswordField](api:ConfirmedPasswordField)`: Shows two password-fields, and checks for matching passwords.
* `[CreditCardField](api:CreditCardField)`
* `[CurrencyField](api:CurrencyField)`
* `[EmailField](api:EmailField)`
* `[HTMLEditorField](api:HTMLEditorField)`: A WYSIWYG editor field, powered by tinymce.
* `[NumericField](api:NumericField)`: A Single Numeric field extending a typical TextField but with validation.
* `[PasswordField](api:PasswordField)`
* `[UniqueRestrictedTextField](api:UniqueRestrictedTextField)`: Text field that automatically checks that the value entered
is unique for the given set of fields in a given set of tables
* `[UniqueTextField](api:UniqueTextField)`: Text field that automatically checks that the value entered is unique for the
given set of fields in a given set of tables
## Date/Time
* `[DateField](api:DateField)`: Represents a date in a textfield (New Zealand)
* `[DatetimeField](api:DatetimeField)`: Combined date- and time field
* `[TimeField](api:TimeField)`: Represents time in a textfield (New Zealand)
## Structure
* `[CompositeField](api:CompositeField)`: Base class for all fields that contain other fields. Uses `<div>` in template, but
doesn't necessarily have any visible styling.
* `[FieldGroup](api:FieldGroup)`: Same as CompositeField, but has default styling (indentation) attached in CMS-context.
* `[api:FieldSet]`: Basic container for sequential fields, or nested fields through CompositeField. Does NOT render a
`<fieldgroup>`.
* `[TabSet](api:TabSet)`
* `[Tab](api:Tab)`
## Actions
* `[api:Form]` for more info
* `[InlineFormAction](api:InlineFormAction)`: Render a button that will act as If you want to add custom behaviour, please
set {inlcudeDefaultJS} to false and work with behaviour.js.
* `[api:Image]`: Action that uses an image instead of a button
* `[InlineFormAction](api:InlineFormAction)`: Prevents placement of a button in the CMS-button-bar.
## Files
* `[FileField](api:FileField)`: Simple file upload dialog.
* `[FileIFrameField](api:FileIFrameField)`: File uploads through an iframe
* `[api:Image]`: Image upload through an iframe, with thumbnails and file-selection from existing assets
* `[SimpleImageField](api:SimpleImageField)`: SimpleImageField provides an easy way of uploading images to Image has_one
relationships. Unlike ImageField, it doesn't use an iframe.
## Relations
* `[ComplexTableField](api:ComplexTableField)`: Provides a tabuar list in your form with view/edit/add/delete links to modify
records with a "has-one"-relationship (in a lightbox-popup).
* `[HasManyComplexTableField](api:HasManyComplexTableField)`
* `[HasOneComplexTableField](api:HasOneComplexTableField)`
* `[LanguageDropdownField](api:LanguageDropdownField)`: An extension to dropdown field, pre-configured to list languages.
Tied into i18n.
* `[ManyManyComplexTableField](api:ManyManyComplexTableField)`
* `[TableField](api:TableField)`
* `[api:TableListField]`
* `[TreeDropdownField](api:TreeDropdownField)`
* `[TreeMultiselectField](api:TreeMultiselectField)`: represents many-many joins using a tree selector shown in a
dropdown-like element
* `[api:WidgetArea]`
## Dataless/Utility
* `[DatalessField](api:DatalessField)` - Base class for fields which add some HTML to the form but don't submit any data or
save it to the database
* `[HeaderField](api:HeaderField)`: Renders a simple `<h1>`-`<h6>` header
* `[HiddenField](api:HiddenField)`
* `[LabelField](api:LabelField)`
* `[LiteralField](api:LiteralField)`: Renders arbitrary HTML into a form.
## CMS Field Editor
Please see `[api:HTMLEditorField]` for in-depth documentation about custom forms created through a GUI in the CMS.

118
docs/en/reference/image.md Normal file
View File

@ -0,0 +1,118 @@
# Image
## Introduction
Represents an image object, inheriting all base functionality from the [file](api:file) class with extra functionality
including resizing.
## Usage
### Form Fields
* `[api:Image]`. Designed to provide a complex image uploader for the CMS.
* `[api:SimpleImageField]`. A Simple Image Upload Form
### Resizing Images in PHP
The following are methods defined on the GD class which you can call on Image Objects. Note to get the following to work
you need to have GD2 support in your PHP installation and because these generate files you must have write access to
your tmp folder.
:::php
// manipulation functions
$image->resize(width,height); // Basic resize, just skews the image
$image->resizeRatio(width,height) // Resizes an image with max width and height
$image->paddedResize(width,height) // Adds padding after resizing to width or height.
$image->croppedResize(width,height) // Crops the image from the centre, to given values.
$image->resizeByHeight(height) // Maximum height the image resizes to, keeps proportion
$image->resizeByWidth(width) // Maximum width the image resizes to, keeps proportion
$image->greyscale(r,g,b) // alters image channels ===
// values
$image->getHeight() // Returns the height of the image.
$image->getWidth() // Returns the width of the image
$image->getOrienation() // Returns a class constant: ORIENTATION_SQUARE or ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE
You can also create your own functions by extending the image class, for example
:::php
class MyImage extends Image {
public function generateRotateClockwise(GD $gd) {
return $gd->rotate(90);
}
public function generateRotateCounterClockwise(GD $gd) {
return $gd->rotate(270);
}
public function clearResampledImages() {
$files = glob(Director::baseFolder().'/'.$this->Parent()->Filename."_resampled/*-$this->Name");
foreach($files as $file) {unlink($file);}
}
public function Landscape() {
return $this->getWidth() > $this->getHeight();
}
public function Portrait() {
return $this->getWidth() < $this->getHeight();
}
function generatePaddedImageByWidth(GD $gd,$width=600,$color="fff"){
return $gd->paddedResize($width, round($gd->getHeight()/($gd->getWidth()/$width),0),$color);
}
public function Exif(){
//http://www.v-nessa.net/2010/08/02/using-php-to-extract-image-exif-data
$image = $this->AbsoluteURL;
$d=new DataObjectSet();
$exif = exif_read_data($image, 0, true);
foreach ($exif as $key => $section) {
$a=new DataObjectSet();
foreach ($section as $name => $val)
$a->push(new ArrayData(array("Title"=>$name,"Content"=>$val)));
$d->push(new ArrayData(array("Title"=>strtolower($key),"Content"=>$a)));
}
return $d;
}
}
### Resizing in Templates
You can call certain resize functions directly from the template, to use the inbuilt GD functions as the template parser
supports these, for example SetWidth() or SetHeight().
For output of an image tag with the image automatically resized to 80px width, you can use:
:::php
$Image.SetWidth(80) // returns a image 80px wide, ratio kept the same
$Image.SetHeight(80) // returns a image 80px tall, ration kept the same
$Image.SetSize(80,80) // returns a 80x80px padded image
$Image.SetRatioSize(80,80) // **New in 2.4** returns an image scaled proportional, with its greatest diameter scaled to 80px
$Image.PaddedImage(80, 80) // Returns an 80x80 image. Unused space is padded white. No crop. No stretching
$Image.Width // returns width of image
$Image.Height // returns height of image
$Image.Orientation // returns Orientation
$Image.Filename // returns filename
$Image.URL // returns filename
### Form Upload
For usage on a website form, see `[api:SimpleImageField]`.
If you want to upload images within the CMS, see `[api:ImageField]`.
### Clearing Thumbnail Cache
Images are (like all other Files) synchronized with the SilverStripe database.
This syncing happens whenever you load the "Files & Images" interface,
and whenever you upload or modify an Image through SilverStripe.
If you encounter problems with images not appearing, or have mysteriously disappeared, you can try manually flushing the
image cache.
http://www.mysite.com/images/flush
## API Documentation
`[api:Image]`

View File

@ -0,0 +1,39 @@
# Reference #
Reference articles complement our auto-generated [API docs](http://api.silverstripe.org) in providing deeper introduction into a specific API.
* [BBCode](bbcode): Extensible shortcode syntax
* [Built-in page controls](built-in-page-controls): Explains the template syntax and available variables/placeholders
* [ComplexTableField](complextablefield): Manage records and their relations inside the CMS
* [Database Structure](database-structure): Conventions and best practices for database tables and fields
* [DataObject](dataobject): Base class for database records
* [DataObjectDecorator](dataobjectdecorator): A "mixin" system allowing to extend core classes
* [DataObjectSet](dataobjectset): The base collection of database records in the ORM
* [Director](director): Routes URLs and handles HTTP requests
* [Execution Pipeline](execution-pipeline): Detailed look on the way an HTTP request takes through the system
* [Form Field Types](form-field-types): Highlevel overview of field classes
* [Image](image): Represents an image object in templates and PHP code
* [LeftAndMain](leftandmain): Base class for the CMS interface
* [Member](member): The "user" object forms the base for our security/permission moel
* [ModelAdmin](modeladmin): Manage arbitrary data in a simple CRUD (create/read/update/delete) interface
* [Partial Caching](partial-caching): Cache complex parts of templates for better performance
* [Permission](permission): Database-backed permission model
* [Requirements](requirements): Include CSS and JavaScript files in templates and controllers
* [RestfulService](restfulservice): Consume Restful APIs with this client
* [RSSFeed](rssfeed): Expose any database records as an RSS feed
* [SearchContext](searchcontext): Wraps search queries and forms into an object
* [Site Reports](site-reports): Tabular reports in a specialized CMS interface
* [SiteConfig](siteconfig): Global configuration stored in the database
* [SiteTree](sitetree): Base class for a "page" in the CMS
* [SQLQuery](sqlquery): Wrapper around a SQL query allowing modification before execution
* [StaticPublisher](staticpublisher): Export a page tree as static HTML for better performance and portability
* [TableField](tablefield): Add and edit records with inline edits in this form field
* [TableListField](tablelistfield): View and delete records in the CMS
* [Templates](templates): Process our data for output in HTML and other formats
* [Typography](typography): CSS file to enable WYSIWYG previews in the CMS
* [urlvariabletools](urlvariabletools): Debug and maintenance switches
* [Versioned](versioned): Extension for SiteTree and other classes to store old versions and provide "staging"
## Feedback
If you have a topic you would like covered in these section please ask for it on our [Bug Tracker](http://open.silverstripe.org)

View File

@ -0,0 +1,193 @@
# LeftAndMain
## Introduction
LeftAndMain is the base class of all the admin area controllers.
## Best Practices
### Refreshing
Please use LeftAndMain::ForceReload to reload the whole form-area after an Ajax-Request. If you just need to refresh
parts of the form, please use javascript-replacement in the response of the original Ajax-Request. Consider using
`[api:Form]` for compiling Ajax-Responses and automatic detection of Ajax/Non-Ajax-Calls.
### Custom Access Checking
You can customize access control in `[api:LeftAndMain]`.
:::php
// mysite/_config.php
LeftAndMain::add_extension('MyLeftAndMain');
// MyLeftAndMain.php
class MyLeftAndMain extends Extension {
function augumentInit() {
// add custom requirements etc.
}
function alternateAccessCheck() {
// custom permission checks, e.g. to check for an SSL-connection, or an LDAP-group-membership
}
}
## Subclassing
There are a few steps in creating a subclass of LeftAndMain.
### MyAdmin.php
The PHP file defining your new subclass is the first step in the process. This provides a good starting point:
:::php
class MyAdmin extends LeftAndMain {
static $url_segment = 'myadmin';
static $url_rule = '$Action/$ID';
static $menu_title = 'My Admin';
static $menu_priority = 60;
/**
* Initialisation method called before accessing any functionality that BulkLoaderAdmin has to offer
*/
public function init() {
Requirements::javascript('cms/javascript/MyAdmin.js');
parent::init();
}
/**
* Form that will be shown when we open one of the items
*/
public function getEditForm($id = null) {
return new Form($this, "EditForm",
new FieldSet(
new ReadonlyField('id #',$id)
),
new FieldSet(
new FormAction('go')
)
);
}
}
### Templates
Next, create templates, (classname)_left.ss and (classname)_right.ss. Again, here are a couple of starting points:
* On the left, we're using the tree as a way of providing navigation. The left and side could be replaced with
anything but LeftAndMain has built-in support for trees.
* On the right, we have the skeleton that the form will be loaded into.
MyAdmin_left.ss
:::ss
<div class="title"><div>Functions</div></div>
<div id="treepanes">
<div id="sitetree_holder" style="overflow:auto">
<% if Items %>
<ul id="sitetree" class="tree unformatted">
<li id="$ID" class="root Root"><a>Items</a>
<ul>
<% control Items %>
<li id="record-$class">
<a href="admin/my/show/$ID">$Title</a>
</li>
<% end_control %>
</ul>
</li>
</ul>
<% end_if %>
</div>
</div>
MyAdmin_right.ss
:::ss
<div class="title"><div>My admin</div></div>
<% if EditForm %>
$EditForm
<% else %>
<form id="Form_EditForm" action="admin/my?executeForm=EditForm" method="post" enctype="multipart/form-data">
<p>Welcome to my $ApplicationName admin section. Please choose something from the left.</p>
</form>
<% end_if %>
<p id="statusMessage" style="visibility:hidden"></p>
### Customising the main menu
*Minimum Requirement: Silverstripe 2.3*
The static variable $url_segment determines the sub url of the controller.
The static variable $url_rule has the url format for the actions performed by the class.
The static variable $menu_title is the title of the administration panel in the menu.
The static variable $menu_priority tells the CMS where to put the menu item relative to other panels.
For example:
:::php
static $url_segment = 'myadmin';
static $url_rule = '$Action/$ID';
static $menu_title = 'My Admin';
static $menu_priority = 60;
See also `[api:CMSMenu]`
### Translatable Menu Titles
Override the function getMenuTitle() to create a translated menu title name. Eg:
:::php
public function getMenuTitle() {
return _t('LeftAndMain.MYADMIN', 'My Admin', PR_HIGH, 'Menu title');
## 'onload' javascript in the CMS {#onload-javascript}
You can have custom scripting called when a Page is loaded by clicking on the Site Content Tree.
This can be used to set up event handlers, or populate dropdowns, etc.
You could insert this code using Requirements from a custom page class.
:::js
Behaviour.register({
'#Form_EditForm' : {
initialize : function() {
this.observeMethod('PageLoaded', this.adminPageHandler);
this.adminPageHandler();
},
adminPageHandler : function() {
// Place your custom code here.
}
}
});
See [Javascript in the CMS](/topics/javascript#javascript-cms)
## Related
* `[api:CMSMain]`
* `[api:AssetAdmin]`
* `[api:SecurityAdmin]`
* `[api:ModelAdmin]`
## TODO
* Explain how to build the javascript file
* Explain how the ajax button handlers work
* Explain how to create little pop-up dialogs

127
docs/en/reference/member.md Normal file
View File

@ -0,0 +1,127 @@
# Member
## Introduction
The Member class is used to represent user accounts on a SilverStripe site (including newsletter recipients).
## Testing For Logged In Users
The Member class comes with 2 static methods for getting information about the current logged in user.
**Member::currentUserID()**
Retrieves the ID (int) of the current logged in member. Returns *0* if user is not logged in. Much lighter than the
next method for testing if you just need to test.
:::php
// Is a member logged in?
if( Member::currentUserID() ) {
// Yes!
} else {
// No!
}
**Member::currentUser()**
Returns the full *Member* Object for the current user, returns *null* if user is not logged in.
:::php
if( $member = Member::currentUser() ) {
// Work with $member
} else {
// Do non-member stuff
}
## Subclassing
<div class="warning" markdown="1">
This is the least desirable way of extending the Member class. It's better to use DataObjectDecorator (see below).
</div>
You can defined subclasses of member to add extra fields or functionality to the built-in membership system.
:::php
class MyMember extends Member {
static $db = array(
"Age" => "Int",
"Address" => "Text",
);
}
To ensure that all new members are created using this class, put a call to `[api:Object::useCustomClass()]` in
(project)/_config.php:
:::php
Object::useCustomClass("Member", "MyMember");
Note that if you want to look this class-name up, you can call Object::getCustomClass("Member")
## Overloading getCMSFields()
If you overload the built-in function getCMSFields(), then you can change the form that is used to view & edit member
details in the newsletter system. This function returns a FieldSet object. You should generally start by calling
parent::getCMSFields() and manipulate the FieldSet from there.
:::php
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->insertBefore(new TextField("Age"), "HTMLEmail");
$fields->removeByName("JobTitle");
$fields->removeByName("Organisation");
return $fields;
}
## Extending Member or DataObject?
Basic rule: Class "Member" should just be extended for entities who have some kind of login.
If you have different types of Members in the system, you have to make sure that those with login-capabilities have
unique email-addresses (as this is used for login-credentials).
For persons without login-capabilities (e.g. for an address-database), you shouldn't extend member to avoid conflicts
with the Member-database. This enables us to have a different subclass of Member for an email-address with login-data,
and another subclass for the same email-address in the address-database.
## Member Role Decorator
Using inheritance to add extra behaviour or data fields to a member is limiting, because you can only inherit from 1
class. A better way is to use role decorators to add this behaviour.
:::php
DataObject::add_extension('Member', 'ForumRole');
// OR
Member::add_role('ForumRole');
A role decorator is simply a subclass of `[api:DataObjectDecorator]` that is designed to be used to add behaviour to Member.
The roles affect the entire class - all members will get the additional behaviour. However, if you want to restrict
things, you should add appropriate `[api:Permission::checkMember()]` calls to the role's methods.
:::php
class ForumRole extends DataObjectDecorator {
/**
* Modify the field set to be displayed in the CMS detail pop-up
*/
function updateCMSFields(FieldSet $currentFields) {
// Only show the additional fields on an appropriate kind of use
if(Permission::checkMember($this->owner->ID, "VIEW_FORUM")) {
// Edit the fieldset passed, adding or removing fields as necessary
}
}
function extraStatics() {
// Return an array containing keys 'db', 'has_one', 'many_many', 'belongs_many_many',
}
function somethingElse() {
// You can add any other methods you like, which you can call directly on the member object.
}
}
## API Documentation
`[api:Member]`

View File

@ -0,0 +1,115 @@
# ModelAdmin
## Introduction
*Replaces GenericDataAdmin in Silverstripe 2.3*
The ModelAdmin provides a simple way to utilize the SilverStripe CMS UI with your own custom data models. The
ModelAdmin uses the `[api:DataObject]`'s Scaffolding to create the search fields, forms, and displayed data within the
CMS.
In order to customize the ModelAdmin CMS interface you will need to understand how `[api:DataObject]` works.
## Requirements
*Requires Silverstripe 2.3*
## Usage
### Step 1
Extend ModelAdmin with a custom class for your admin area, and edit the `$managed_models` property with the list of
data objects you want to scaffold an interface for:
:::php
class MyCatalogAdmin extends ModelAdmin {
public static $managed_models = array( //since 2.3.2
'Product',
'Category'
);
static $url_segment = 'products'; // will be linked as /admin/products
static $menu_title = 'My Product Admin';
}
To add the ModelAdmin to your CMS menu, you simply need to define a couple of statics on your ModelAdmin subclass. See
`[api:LeftAndMain]` on how to make your menu title translatable.
### Step 2
Add a `$searchable_fields` (See `[api:ModelAdmin::$searchable_fields]`) property to your data
models, to define the fields and filters for the search interface:
Datamodel `Product`:
:::php
class Product extends DataObject {
static $db = array(
'Name' => 'Varchar',
'ProductCode' => 'Varchar',
'Description' => 'Text',
'Price' => 'Currency'
);
static $has_one = array(
'Category' => 'Category'
);
static $searchable_fields = array(
'Name',
'ProductCode'
);
}
Datamodel `Category`:
:::php
<?php
class Category extends DataObject {
static $db = array(
'Title' => 'Text'
);
}
?>
### Step 3
You can now log in to the main CMS admin and manage your data objects, with no extra implementation required.
![](_images/modeladmin_edit.png)
![](_images/modeladmin_results.png)
### Note about has_one
Scaffolding **has_one** relationships in your ModelAdmin relies on a column in the related model to be named **Title**
or **Name** of a string type (varchar, char, etc). These will be pulled in to the dropdown when creating a new object.
If you are seeing a list of ID#s when creating new objects, ensure you have one of those two in the related model.
## Searchable Fields
You can customize the fields which are searchable for each managed DataObject class, as well as the ways in which the
fields are searched (e.g. "partial match", "fulltext", etc.) using `$searchable_fields`.
* See `[api:DataObject]`
![](_images/modeladmin_search.png)
## Summary Fields
Summary Fields are the columns which are shown in the `[api:TableListField]` when viewing DataObjects. These can be
customized for each DataObject's search results using `$summary_fields`.
* See `[api:DataObject]`
## Related
* `[api:SearchContext]`
* [genericviews Module](http://silverstripe.org/generic-views-module)
* [Presentation about ModelAdmin at SupperHappyDevHouse Wellington](http://www.slideshare.net/chillu/modeladmin-in-silverstripe-23)

View File

@ -0,0 +1,241 @@
# Partial Caching
## Introduction
Partial caching, new in SilverStripe 2.4, is a feature that allows the caching of just a portion of a page.
As opposed to static publishing, which avoids the SilverStripe controller layer on cached pages, partial caching allows
caching for pages that contain a mix of moderately static & user specific data, and still provide full access control
and permission enforcement.
The trade-off is that it does not provide as much performance improvement as static publishing, although for data heavy
pages the speed increases can be significant.
## Basics
The way you mark a section of the template as being cached is to wrap that section in a cached tag, like so:
:::ss
<% cached %>
$DataTable
...
<% end_cached %>
Each cache block has a cache key - an unlimited number of comma separated variables (in the same form as `if` and
`control` tag variables) and quoted strings.
Every time the cache key returns a different result, the contents of the block are recalculated. If the cache key is the
same as a previous render, the cached value stored last time is used.
Since the above example contains just one argument as the cache key, a string (which will be the same every render) it
will invalidate the cache after the TTL has expired (default 10 minutes)
Here are some more complex examples:
From a block that updates every time the Page subclass it's the template for updates
:::ss
<% cached 'database', LastEdited %>
From a block that shows a login block if not logged in, or a homepage link if logged in, depending on the current member
:::ss
<% cached 'loginblock', CurrentMember.ID %>
From a block that shows a summary of the page edits if administrator, nothing if not
:::ss
<% cached 'loginblock', LastEdited, CurrentMember.isAdmin %>
## Aggregates
Often you want to invalidate a cache when any in a set of objects change, or when the objects in a relationship change.
To help do this, SilverStripe 2.4 also introduces the concept of Aggregates. These calculate and return SQL aggregates
on sets of DataObjects - the most useful for us being the Max aggregate.
For example, if we have a menu, we want that menu to update whenever _any_ page is edited, but would like to cache it
otherwise. By using aggregates, that's easy
:::ss
<% cached 'navigation', Aggregate(Page).Max(LastEdited) %>
If we have a block that shows a list of categories, we can make sure the cache updates every time a category is added or
edited
:::ss
<% cached 'categorylist', Aggregate(Category).Max(LastEdited) %>
We can also calculate aggregates on relationships. A block that shows the current member's favourites needs to update
whenever the relationship Member::$has_many = array('Favourites' => Favourite') changes.
:::ss
<% cached 'favourites', CurrentMember.ID, CurrentMember.RelationshipAggregate(Favourites).Max(LastEdited) %>
## Cache key calculated in controller
That last example is a bit large, and is complicating our template up with icky logic. Better would be to extract that
logic into the controller
:::php
function FavouriteCacheKey() {
$member = Member::currentUser();
return implode('_', array(
'favourites',
$member->ID,
$member->RelationshipAggregate('Favourites')->Max('LastEdited')
));
}
and then using that function in the cache key
:::ss
<% cached FavouriteCacheKey %>
## Cache blocks and template changes
In addition to the key elements passed as parameters to the cached control, the system automatically includes the
template name and a sha1 hash of the contents of the cache block in the key. This means that any time the template is
changed the cached contents will automatically refreshed.
## Purposely stale data
In some situations it's more important to be fast than to always be showing the latest data. By constructing the cache
key to invalidate less often than the data updates you can ensure rendering time is constant no matter how often the
data updates.
For instance, if we show some blog statistics, but are happy having them be slightly stale, we could do
:::ss
<% cached 'blogstatistics', Blog.ID %>
which will invalidate after the cache lifetime expires. If you need more control than that (cache lifetime is
configurable only on a site-wide basis), you could add a special function to your controller:
:::php
function BlogStatisticsCounter() {
return (int)(time() / 60 / 5); // Returns a new number every five minutes
}
and then use it in the cache key
:::ss
<% cached 'blogstatistics', Blog.ID, BlogStatisticsCounter %>
## Cache block conditionals
You may wish to conditionally enable or disable caching. To support this, in cached tags you may (after any key
arguments) specify 'if' or 'unless' followed by a standard template variable argument. If 'if' is used, the resultant
value must be true for that block to be cached. Conversely if 'unless' is used, the result must be false.
Following on from the previous example, you might wish to only cache slightly-stale data if the server is experiencing
heavy load:
:::ss
<% cached 'blogstatistics', Blog.ID if HighLoad %>
By adding a HighLoad function to your page controller, you could enable or disable caching dynamically.
To cache the contents of a page for all anonymous users, but dynamically calculate the contents for logged in members,
you could use something like:
:::ss
<% cached unless CurrentUser %>
As a shortcut, the template tag 'uncached' can be used - it is the exact equivilent of a cached block with an if
condition that always returns false. The key and conditionals in an uncached tag are ignored, so you can easily
temporarily disable a particular cache block by changing just the tag, leaving the key and conditional intact.
:::ss
<% uncached %>
## Nested cacheblocks
New since 2.4 beta 2 is the ability to nest independent cache blocks (with one important rule, discussed later).
Any nested cache blocks are calculated independently from their containing block, regardless of the cached state of that
container.
This allows you to wrap an entire page in a cache block on the page's LastEdited value, but still keep a member-specific
portion dynamic, without having to include any member info in the page's cache key.
An example:
:::ss
<% cached LastEdited %>
Our wonderful site
<% cached Member.ID %>
Welcome $Member.Name
<% end_cached %>
$ASlowCalculation
<% end_cached %>
This will cache the entire outer section until the next time the page is edited, but will display a different welcome
message depending on the logged in member.
Cache conditionals and the uncached tag also work in the same nested manner. Since Member.Name is fast to calculate, you
could also write the last example as:
:::ss
<% cached LastEdited %>
Our wonderful site
<% uncached %>
Welcome $Member.Name
<% end_uncached %>
$ASlowCalculation
<% end_cached %>
## The important rule
Currently cached blocks can not be contained within if or control blocks. The template engine will throw an error
letting you know if you've done this. You can often get around this using aggregates.
Failing example:
:::ss
<% cached LastEdited %>
<% control Children %>
<% cached LastEdited %>
$Name
<% end_cached %>
<% end_control %>
<% end_cached %>
Can be re-written as:
:::ss
<% cached LastEdited %>
<% cached RelationshipAggregate(Children).Max(LastEdited) %>
<% control Children %>
$Name
<% end_control %>
<% end_cached %>
<% end_cached %>

View File

@ -0,0 +1,74 @@
# User Permissions
## Introduction
This class implements SilverStripe's permission system.
## Usage
Permissions are defined on a group-by-group basis. To give a permission to a member, go to a group that contains them,
and then select the permissions tab, and add that permission to the list.
The simple usage, Permission::check("PERM_CODE") will detect if the currently logged in member has the given permission.
See the API docs for more options.
** Group ACLs **
* Call **Permission::check("MY_PERMISSION_CODE")** to see if the current user has MY_PERMISSION_CODE.
* MY_PERMISSION_CODE can be loaded into the Security admin on the appropriate group, using the "Permissions" tab.
You can use whatever codes you like, but for the sanity of developers and users, it would be worth listing the codes in
[permissions:codes](/reference/permission)
## PermissionProvider
PermissionProvider is an interface which lets you define a method *providePermissions()*. This method should return a
map of permission code names with a human readable explanation of its purpose (see
[:permission:codes](/reference/permission)).
:::php
class Page_Controller implements PermissionProvider {
function init() {
if(!Permission::check("VIEW_SITE")) Security::permissionFailure();
}
function providePermissions() {
return array(
"VIEW_SITE" => "Access the site",
);
}
}
This can then be used to add a dropdown for permission codes to the security panel. Permission::get_all_codes() will be
a helper method that will call providePermissions() on every applicable class, and collate the resuls into a single
dropdown.
## Default use
By default, permissions are used in the following way:
* The 'View' permission is checked when opening a page
* The 'View' permissions is used on **all** default datafeeds:
* If not logged in, the 'View' permissions must be 'anyone logged in' for a page to be displayed in a menu
* If logged in, you must be allowed to view a page for it to be displayed in a menu
**NOTE:** Should the canView() method on SiteTree be updated to call Permission::check("SITETREE_VIEW", $this->ID)?
Making this work well is a subtle business and should be discussed with a few developers.
## Setting up permissions
* By default, permissions are linked to groups. You define a many-many relationship called Can(permname), eg,
"CanView". Please note that group permissions are more efficient, as SQL joins are used to filter data.
* Alternatively, you can create a custom permission by defining a function called can(permname)
## Using permissions
* On an individual data record, $page->can("View", $member = null) and be called. If a member isn't passed, the
currently logged in member is assumed.
* On a request, $request->hasPermission("View", $member = null) can be called. See [datamodel](/topics/datamodel) for
information on request objects.
## API Documentation
`[api:Permission]`

View File

@ -0,0 +1,193 @@
# Requirements
## Introduction
The requirements class takes care of including CSS and JavaScript into your applications. This is preferred to
hardcoding any references in the `<head>`-tag of your template, as it enables a more flexible handling.
## Including inside PHP Code
It is common practice to include most Requirements either in the *init()*-method of your [controller](/topics/controller), or
as close to rendering as possible (e.g. in `[api:FormField]`
:::php
Requirements::javascript("cms/javascript/LeftAndMain.js");
Requirements::css("cms/css/TreeSelector.css");
If you're using the CSS method a second argument can be used. This argument defines the 'media' attribute of the `<link>`
element, so you can define 'screen' or 'print' for example.
Requirements::css("cms/css/TreeSelector.css", "screen,projection");
## Including inside Template files
If you do not want to touch the PHP (for example you are constructing a generic theme) then you can include a file via
the templates
<% require css(cms/css/TreeSelector.css) %>
<% require themedCSS(TreeSelector) %>
<% require javascript(cms/javascript/LeftAndMain.js) %>
Note that currently (as of 2.3) you cannot pass a second parameter to a function via the template parser so doing the
following will not work.
<% require css(cms/css/TreeSelector.css, 'screen,projection') %>
## Combining Files
You can concatenate several CSS or javascript files into a single dynamically generated file. This increases performance
reducing HTTP requests. Note that for debugging purposes combined files is disabled in devmode.
:::php
// supports CSS + JS
Requirements::combine_files(
'foobar.js',
array(
'mysite/javascript/foo.js',
'mysite/javascript/bar.js',
)
);
By default it stores the generated file in the assets/ folder but you can configure this by setting
:::php
// relative from the base folder
Requirements::set_combined_files_folder('folder');
If SilverStripe doesn't have permissions on your server to write these files it will default back to including them
individually .
## Custom Inline Scripts
You can also quote custom script directly. This may seem a bit ugly, but is useful when you need to transfer some kind
of 'configuration' from the database to the javascript/css. You'll need to use the "heredoc" syntax to quote JS and
CSS, this is generally speaking the best way to do these things - it clearly marks the copy as belonging to a different
language.
:::php
Requirements::customScript(<<<JS
alert("hi there");
JS
);
Requirements::customCSS(<<<CSS
.tree li.$className {
background-image: url($icon);
}
CSS
);
## Templated javascript
A variant on the inclusion of custom javascript is the inclusion of *templated* javascript. Here, you keep your
JavaScript in a separate file and instead load, via search and replace, several PHP-generated variables into that code.
:::php
$vars = array(
"EditorCSS" => "mot/css/editor.css",
)
Requirements::javascriptTemplate("cms/javascript/editor.template.js", $vars);
## Clearing
You may want to clear all of the requirements mentioned thus far. I've used this when you've put an iframe generator as
an action on the controller that uses it. The iframe has a completely different set of scripting and styling
requirements, and it's easiest to flush all the default stuff and start again.
:::php
Requirements::clear();
You can also clear specific Requirements:
:::php
Requirements::clear('jsparty/prototype.js');
Caution: Depending on where you call this command, a Requirement might be *re-included* afterwards.
## Inclusion Order
Requirements acts like a stack, where everything is rendered sequentially in the order it was included. There is no way
to change inclusion-order, other than using *Requirements::clear* and rebuilding (=guessing) the whole set of
requirements. Caution: Inclusion order is both relevant for CSS and Javascript files in terms of dependencies,
inheritance and overlays - please be careful when messing with the order of Requirements.
NOTE:
By default, SilverStripe includes all Javascript files at the bottom of the page body. If this causes problems for you,
for example if you're using animation that ends up showing everything until the bottom of the page loads, or shows
buttons before pushing them will actually work, you can change this behaviour:
In your controller's init() function, add:
:::php
Requirements::set_write_js_to_body(false);
## CMS Requirements
The Silverstripe core includes a lot of Requirements by itself. Most of these are collated in `[api:LeftAndMain]`//
first.
## Motivation
Every page requested is made up of a number of parts, and many of those parts require their own CSS or JavaScript.
Rather than force the developer to put all of those requests into the template, or the header function, you can
reference required files anywhere in your application.
This lets you create very modular units of PHP+JavaScript+CSS, which a powerful concept but must be managed carefully.
## Managing Generic CSS styling
One of the aims of this is to create units of functionality that can be reasonably easily deployed as-is, while still
giving developers the option to customise them. The logical solution to this is to create 'generic' CSS to be applied
to these things. However, we must take great care to keep the CSS selectors very nonspecific. This precludes us from
adding any CSS that would "override customisations" in the form - for example, resetting the width of a field where 100%
width isn't appropriate.
Another solution would be to include some "generic CSS" for form elements at the very high level, so that fixed widths
on forms were applied to the generic form, and could therefore be overridden by a field's generic stylesheet. Similar
to this is mandating the use of "form div.field input" to style form input tags, whether it's a generic form or a custom
one.
Perhaps we could make use of a Requirements::disallowCSS() function, with which we could prevent the standard CSS from
being included in situations where it caused problems. But the complexity could potentially balloon, and really, it's a
bit of an admission of defeat - we shouldn't need to have to do this if our generic CSS was well-designed.
## Ideas/Problems
### Ajax
The whole "include it when you need it" thing shows some weaknesses in areas such as the CMS, where Ajax is used to load
in large pieces of the application, which potentially require more CSS and JavaScript to be included. At this stage,
the only workaround is to ensure that everything you might need is included on the first page-load.
One idea is to mention the CSS and JavaScript which should be included in the header of the Ajax response, so that the
client can load up those scripts and stylesheets upon completion of the Ajax request. This could be coded quite
cleanly, but for best results we'd want to extend prototype.js with our own changes to their Ajax system, so that every
script had consistent support for this.
### Lots of files
Because everything's quite modular, it's easy to end up with a large number of small CSS and JavaScript files. This has
problems with download time, and potentially maintainability.
We don't have any easy answers here, but here are some ideas:
* Merging the required files into a single download on the server. The flip side of this is that if every page has a
slightly different JS/CSS requirements, the whole lot will be refetched.
* Better: "Tagging" each required file for different use-cases, and creating a small set of common functionalities
(e.g. everything tagged "base" such as prototype.js would always be included)
* Do lazy fetching of scripts within an ajax-call. This seems to be possible, but very tricky due to the asynchronous
nature of an ajax-request. Needs some more research
## API Documentation
`[api:Requirements]`

View File

@ -0,0 +1,179 @@
# Restful Service
## Introduction
RestfulService enables connecting to remote web services which supports REST interface and consume those web services
(for example Flickr, Youtube, Amazon and etc). RestfulService can parse the XML response (sorry no JSON support)
returned from the web service. Further it supports caching of the response, and you can customize the cache interval.
To gain the functionality you can either create a new RestfulService object or create a class extending the
RestfulService (see `flickrservice` and `youtubeservice` modules).
## Examples
### Creating a new RestfulObject
:::php
//example for using RestfulService to connect and retrive latest twitter status of an user.
$twitter = new RestfulService("http://twitter.com/statuses/user_timeline/user.xml", $cache_expiry );
$params = array('count' => 1);
$twitter->setQueryString($params);
$conn = $twitter->connect();
$msgs = $twitter->getValues($conn, "status");
### Extending to a new class
:::php
//example for extending RestfulService
class FlickrService extends RestfulService {
function __construct($expiry=NULL){
parent::__construct('http://www.flickr.com/services/rest/', $expiry);
$this->checkErrors = true;
}
......
### Multiple requests by using the $subURL argument on connect()
:::php
// Set up REST service
$service = new RestfulService("http://example.harvestapp.com");
$service->basicAuth('username', 'password');
$service->httpHeader('Accept: application/xml');
$service->httpHeader('Content-Type: application/xml');
$peopleXML = $service->connect('/people');
$people = $service->getValues($peopleXML, 'user');
...
$taskXML = $service->connect('/tasks');
$tasks = $service->getValues($taskXML, 'task');
## Features
### Caching
To set the cache interval you can pass it as the 2nd argument to constructor.
:::php
new RestfulService("http://twitter.com/statuses/user_timeline/user.xml", 3600 );
### Getting Values & Attributes
You can traverse throught document tree to get the values or attribute of a particular node.
for example you can traverse
:::xml
<entries>
<entry id='12'>Sally</entry>
<entry id='15'>Ted</entry>
<entry id='30'>Matt</entry>
<entry id='22'>John</entry>
<entries>
to extract the id attributes of the entries use:
:::php
$this->getAttributes($xml, "entries", "entry") //will return all attributes of each entry node
to extract the values (the names) of the entries use:
:::php
$this->getValues($xml, "entries", "entry") //will return all values of each entry node
### Searching for Values & Attributes
If you don't know the exact position of dom tree where the node will appear you can use xpath to search for the
node.Recommended for retrieving values of namespaced nodes.
:::xml
<media:guide>
<media:entry id="2030">video</media:entry>
</media:guide>
to get the value of entry node with the namespace media, use:
:::php
$this->searchValue($response, "//media:guide/media:entry")
## Best Practices
### Handling Errors
If the web service returned an error (for example, API key not available or inadequate parameters) RestfulService could
delgate the error handling to it's descendant class. To handle the errors define a function called errorCatch
:::php
/*
This will raise Youtube API specific error messages (if any).
*/
function errorCatch($response){
$err_msg = $response;
if(strpos($err_msg, '<') === false)
//user_error("YouTube Service Error : $err_msg", E_USER_ERROR);
user_error("YouTube Service Error : $err_msg", E_USER_ERROR);
else
return $response;
}
If you want to bypass error handling on your sub-classes you could define that in the constructor.
:::php
function __construct($expiry=NULL){
parent::__construct('http://www.flickr.com/services/rest/', $expiry);
$this->checkErrors = false; //Set checkErrors to false to bypass error checking
}
## Other Uses
### How to use RestfulService to easily embed an RSS feed
`[api:RestfulService]` can be used to easily embed an RSS feed (since it's also an xml response) from a site
such as del.icio.us
Put something like this code in mysite/code/Page.php inside class Page_Controller
:::php
// Accepts an RSS feed URL and outputs a list of links from it
function RestfulLinks($url){
$delicious = new RestfulService($url);
$conn = $delicious->connect();
$result = $delicious->getValues($conn, "item");
$output = '';
foreach ($result as $key => $value) {
// Fix quote encoding
$description = str_replace('&amp;quot;', '&quot;', $value->description);
$output .= '<li><a href="'.$value->link.'">'.$value->title.'</a><br />'.$description.'</li>';
}
return $output;
}
Put something like this code in mysite/templates/Layout/HomePage.ss:
:::ss
<h3>My Latest Del.icio.us Links</h3>
<ul>
$RestfulLinks(http://del.icio.us/rss/elijahlofgren)
</ul>
## API Documentation
`[api:RestfulService]`

View File

@ -0,0 +1,84 @@
# RSS Feed
## Introduction
Generating RSS/Atom-feeds is just a matter of rendering a `[api:DataObject]` and the Page Comment Interface.
Handled through the `[api:RSSFeed]` class.
RSSFeed doesn't limit you to generating "article-based" feeds, it is just as easy to create a feed of your current
staff-members. The only logical limitation here is that every item in the RSS-feed should be accessible through a URL on
your website, so its advisable to just create feeds from subclasses of `[api:SiteTree]`.
## Usage
### Showing latest Blog posts
* The first part will add an appropriate link tag for autodetecting RSS feeds
* The second part sets up /this-page/rss to return the RSS feed. This one returns the children of the current page.
:::php
function init() {
RSSFeed::linkToFeed($this->Link() . "rss", "RSS feed of this blog");
parent::init();
}
function rss() {
$rss = new RSSFeed($this->Children(), $this->Link(), "My feed", "This is an example feed.", "Title", "Content", "Author");
$rss->outputToBrowser();
}
### Example of showing the 10 most recently updated pages
You can use RSSFeed to easily create a feed showing your latest Page updates. Just change mysite/code/Page.php to
something like this:
:::php
<?php
class Page extends SiteTree {
static $db = array(
);
static $has_one = array(
);
}
class Page_Controller extends ContentController {
function init() {
RSSFeed::linkToFeed($this->Link() . "rss", "10 Most Recently Updated Pages");
parent::init();
}
function rss() {
$rss = new RSSFeed($this->LatestUpdates(), $this->Link(), "10 Most Recently Updated Pages", "Shows a list of the 10 most recently updated pages.", "Title", "Content", "Author");
$rss->outputToBrowser();
}
function LatestUpdates() {
// 10 is the number of pages
return DataObject::get("Page", "", "LastEdited DESC", "", 10);
}
}
?>
## Viewing Comment RSS Feeds
You can view RSS feeds for comments for a certain page or for all comments on your site by visiting
http://www.yoursite.com/PageComment/rss . That produces a RSS Feed of the most recent comments to all of your site. You
can also do http://www.yoursite.com/PageComment/rss?pageid=46 where pageid is the id of the page you want to follow
## External Sources
RSSFeed only creates feeds from your own data. We've included the [SimplePie](http://simplepie.org) RSS-parser for
accessing feeds from external sources.
## Related
* [blog module](http://silverstripe.org/blog-module)
## API Documentation
`[api:RSSFeed]`

View File

@ -0,0 +1,196 @@
# SearchContext
## Introduction
Manages searching of properties on one or more `[api:DataObject]` types, based on a given set of input parameters.
SearchContext is intentionally decoupled from any controller-logic,
it just receives a set of search parameters and an object class it acts on.
The default output of a SearchContext is either a `[api:SQLQuery]` object for further refinement, or a
`[api:DataObject]` instance.
In case you need multiple contexts, consider namespacing your request parameters by using `FieldSet->namespace()` on
the $fields constructor parameter.
SearchContext is mainly used by `[api:ModelAdmin]`, our generic data administration interface. Another
implementation can be found in generic frontend search forms through the [genericviews](http://silverstripe.org/generic-views-module) module.
## Requirements
* *SilverStripe 2.3*
## Usage
Getting results
:::php
singleton('MyDataObject')->getDefaultSearchContext();
### Defining fields on your DataObject
See `[api:DataObject::$searchable_fields]`.
### Customizing fields and filters
In this example we're defining three attributes on our MyDataObject subclasss: `PublicProperty`, `HiddenProperty`
and `MyDate`. The attribute `HiddenProperty` should not be searchable, and `MyDate` should only search for dates
*after* the search entry (with a `GreaterThanFilter`). Similiar to the built-in `DataObject->getDefaultSearchContext()` method, we're building our own `getCustomSearchContext()` variant.
:::php
class MyDataObject extends DataObject {
static $db = array(
'PublicProperty' => 'Text'
'HiddenProperty' => 'Text',
'MyDate' => 'Date'
);
public function getCustomSearchContext() {
$fields = $this->scaffoldSearchFields(array(
'restrictFields' => array('PublicProperty','MyDate')
));
$filters = array(
'PublicProperty' => new PartialMatchFilter('PublicProperty'),
'MyDate' => new GreaterThanFilter('MyDate')
);
return new SearchContext(
$this->class,
$fields,
$filters
);
}
}
### Generating a search form from the context
:::php
class Page_Controller extends ContentController {
public function SearchForm() {
$context = singleton('MyDataObject')->getCustomSearchContext();
$fields = $context->getSearchFields();
$form = new Form($this, "SearchForm",
$fields,
new FieldSet(
new FormAction('doSearch')
)
);
return $form;
}
public function doSearch($data, $form) {
$context = singleton('MyDataObject')->getCustomSearchContext();
$results = $context->getResults($data);
return $this->customise(array(
'Results' => $results
))->renderWith('Page_results');
}
}
### Pagination
For paginating records on multiple pages, you need to get the generated `SQLQuery` before firing off the actual
search. This way we can set the "page limits" on the result through `setPageLimits()`, and only retrieve a fraction of
the whole result set.
:::php
function getResults($searchCriteria = array()) {
$start = ($this->request->getVar('start')) ? (int)$this->request->getVar('start') : 0;
$limit = 10;
$context = singleton('MyDataObject')->getCustomSearchContext();
$query = $context->getQuery($searchCriteria, null, array('start'=>$start,'limit'=>$limit));
$records = $context->getResults($searchCriteria, null, array('start'=>$start,'limit'=>$limit));
if($records) {
$records->setPageLimits($start, $limit, $query->unlimitedRowCount());
}
return $records;
}
notice that if you want to use this getResults function, you need to change the function doSearch for this one:
:::php
public function doSearch($data, $form) {
$context = singleton('MyDataObject')->getCustomSearchContext();
$results = $this->getResults($data);
return $this->customise(array(
'Results' => $results
))->renderWith(array('Catalogo_results', 'Page'));
}
The change is in **$results = $this->getResults($data);**, because you are using a custom getResults function.
Another thing you cant forget is to check the name of the singleton you are using in your project. the example uses
**MyDataObject**, you need to change it for the one you are using
For more information on how to paginate your results within the template, see [Tutorial: Site Search](/tutorials/4-site-search).
### The Pagination Template
to show the results of your custom search you need at least this content in your template, notice that
Results.PaginationSummary(4) defines how many pages the search will show in the search results. something like:
**Next 1 2 *3* 4 5 … 558**
:::ss
<% if Results %>
<ul>
<% control Results %>
<li>$Titulo, $Autor</li>
<% end_control %>
</ul>
<% else %>
<p>Sorry, your search query did not return any results.</p>
<% end_if %>
<% if Results.MoreThanOnePage %>
<div id="PageNumbers">
<p>
<% if Results.NotFirstPage %>
<a class="prev" href="$Results.PrevLink" title="View the previous page">Prev</a>
<% end_if %>
<span>
<% control Results.PaginationSummary(4) %>
<% if CurrentBool %>
$PageNum
<% else %>
<% if Link %>
<a href="$Link" title="View page number $PageNum">$PageNum</a>
<% else %>
&hellip;
<% end_if %>
<% end_if %>
<% end_control %>
</span>
<% if Results.NotLastPage %>
<a class="next" href="$Results.NextLink" title="View the next page">Next</a>
<% end_if %>
</p>
</div>
<% end_if %>
## Available SearchFilters
See SearchFilter API Documentation `[api:SearchFilter]`
## API Documentation
`[api:SearchContext]`
## Related
* `[api:ModelAdmin]`
* `[api:RestfulServer]`
* [Tutorial: Site Search](/tutorials/4-site-search)

View File

@ -0,0 +1,96 @@
# Site Reports
## Introduction
A report is a little bit of functionally in the CMS designed to provide a report of your data or content. You can access
the site reports by clicking "Site Reports" in the left hand side bar and selecting the report you wish to view.
![](_images/sitereport.png)
By default the CMS ships with a couple basic reports -
## Default Reports
* "Empty Pages" which will generate a list of pages without content
* "Pages edited in the last 2 weeks" which will list all the pages edited in the last 2 weeks in order of most recently
edited.
* "To Do" which displays all the ToDo notes you have added to each page and a link to the page. This is in 2.2.2 and
later
* Also the Ecommerce module provides 2 or 3 reports out of box. Such as All Products, Orders...
## Creating Custom Reports
You can create reports for you own data quickly and easily. A general knowledge of Silverstripe's
[Datamodel](/topics/datamodel) would help before you attempt this.
Inside the Mysite/Code folder - your projects code, create a file called CustomSideReport or MyProjectSiteReport and
inside this file we can add our site reports.
CustomSideReport.php
:::php
<?php
class CustomSideReport_NameOfReport extends SideReport {
function title() {
// the name of our report
}
function records() {
// what we want the report to return and what order
}
function fieldsToShow() {
// which fields on that object do we want to show? Title, Author?
}
}
?>
Now this won't do anything! You will just get a blank report that doesn't work! So for this to do something we have to
fill in these 3 methods title() records() and fieldsToShow() till we have something like this. For example if you want
to list every Page on your site!
CustomSideReport.php
:::php
<?php
/**
* This report lists all the pages in the CMS
* of type Page. Sorted by title.
*/
class CustomSideReport_AllPages extends SideReport {
function title() {
// this is the title of the report
return "All Pages";
}
function records() {
// the data the report returns all the dataobjects of type Page and sorted by title. See datamodel for more info
return DataObject::get("Page", "", "Title");
}
function fieldsToShow() {
// fields you want to display. This will display a list of titles which link to the page in the cms. Handy!
return array(
"Title" => array("NestedTitle", array("2")),
);
}
}
?>
Reload the CMS and test it out for your self! You should be able to select the report and view all the pages.
## Notes
* Your CustomSideReport_ReportName must extend SideReport!
* You can have more then 1 report in the 1 file. Actually its recommended!. You should create 1 CustomSideReport.php
file and add class's as you need them inside that for each report.
## TODO
* How to format and make nicer reports.
* More examples.
## API Documentation
`[api:ReportAdmin]`

View File

@ -0,0 +1,71 @@
# SiteConfig
## Introduction
The SiteConfig panel was introduced in 2.4 for providing a generic interface for managing site wide settings or
functionality which is used throughout the site. Out of the box it provides 2 fields 'Site Name' and 'Site Tagline'.
## Accessing SiteConfig Options
You can access SiteConfig options from any SS template by using the function $SiteConfig.FieldName
:::ss
$SiteConfig.Title
$SiteConfig.Tagline
// or
<% control SiteConfig %>
$Title $AnotherField
<% end_control %>
Or if you want to access variables in the PHP you can do
:::php
$config = SiteConfig::current_site_config();
$config->Title
## Extending SiteConfig
To extend the options available in the panel you can define your own fields via an Extension.
Create a mysite/code/CustomSiteConfig.php file.
:::php
<?php
class CustomSiteConfig extends DataObjectDecorator {
function extraStatics() {
return array(
'db' => array(
'FooterContent' => 'HTMLText'
)
);
}
public function updateCMSFields(FieldSet $fields) {
$fields->addFieldToTab("Root.Main", new HTMLEditorField("FooterContent", "Footer Content"));
}
}
Then add a link to your extension in the _config.php file like below.
Object::add_extension('SiteConfig', 'CustomSiteConfig');
This tells SilverStripe to add the CustomSiteConfig extension to the SiteConfig class.
After adding those two pieces of code, rebuild your database by visiting http://yoursite.com/dev/build and then reload
the admin interface. You may need to reload it with a ?flush=1 on the end.
You can define as many extensions for SiteConfig as you need. For example if you are developing a module you can define
your own global settings for the dashboard.
## API Documentation
`[api:SiteConfig]`

View File

@ -0,0 +1,298 @@
# Sitetree
## Introduction
Basic data-object representing all pages within the site tree. The omnipresent *Page* class (located in
*mysite/code/Page.php*) is based on this class.
## Linking
:::php
// wrong
$mylink = $mypage->URLSegment;
// right
$mylink = $mypage->Link(); // alternatively: AbsoluteLink(), RelativeLink()
## Querying
Use *SiteTree::get_by_link()* to correctly retrieve a page by URL, as it taked nested URLs into account (a page URL
might consist of more than one *URLSegment*).
:::php
// wrong
$mypage = DataObject::get_one('SiteTree', '"URLSegment" = \'<mylink>\'');
// right
$mypage = SiteTree::get_by_link('<mylink>');
## Nested/Hierarchical URLs
In a nutshell, the nested URLs feature means that your site URLs now reflect the actual parent/child page structure of
your site. In SilverStripe 2.3 and earlier, all page URLs would be on the top level, regardless of whether they were
nested under other pages or not. In 2.4 however, the URLs now map directly to the chain of parent and child pages. The
below table shows a quick summary of what these changes mean for your site:
![url table](http://silverstripe.org/assets/screenshots/Nested-URLs-Table.png)
This feature is enabled by default in SilverStripe 2.4 or newer. To activate it for older sites, insert the following
code in your *mysite/_config.php*:
:::php
SiteTree::enable_nested_urls();
After activating nested URLs on an existing database, you'll have to run a migration task to rewrite internal URL
references in the *SiteTree.Content* field.
http://<yourdomain.tld>/dev/tasks/MigrateSiteTreeLinkingTask
## Limiting Children/Parent
By default, any page type can be the child of any other page type. However, there are 4 static properties that can be
used to set up restrictions that will preserve the integrity of the page hierarchy.
:::php
class BlogHolder extends Page {
// Blog holders can only contain blog entries
static $allowed_children = array("BlogEntry");
static $default_child = "BlogEntry";
...
class BlogEntry extends Page {
// Blog entries can't contain children
static $allowed_children = "none";
static $default_parent = "blog";
static $can_be_root = false;
...
class Page extends SiteTree {
// Don't let BlogEntry pages be underneath Pages. Only underneath Blog holders.
static $allowed_children = array("*Page,", "BlogHolder");
}
* **allowed_children:** This can be an array of allowed child classes, or the string "none" - indicating that this page
type can't have children. If a classname is prefixed by "*", such as "*Page", then only that class is allowed - no
subclasses. Otherwise, the class and all its subclasses are allowed.
* **default_child:** If a page is allowed more than 1 type of child, you can set a default. This is the value that
will be automatically selected in the page type dropdown when you create a page in the CMS.
* **default_parent:** This should be set to the *URLSegment* of a specific page, not to a class name. If you have
asked to create a page of a particular type that's not allowed underneath the page that you have selected, then the
default_parent page will be selected. For example, if you have a gallery page open in the CMS, and you select add blog
entry, you can set your site up to automatically select the blog page as a parent.
* **can_be_root:** This is a boolean variable. It lets you specify whether the given page type can be in the top
level.
Note that there is no allowed_parents control. To set this, you will need to specify the allowed_children of all other
page types to exclude the page type in question. IMO this is less than ideal; it's possible that in a future release we
will add allowed_parents, but right now we're trying to limit the amount of mucking around with the API we do.
Here is an overview of everything you can add to a class that extends sitetree. NOTE: this example will not work, but
it is a good starting point, for choosing your customisation.
:::php
class Page extends SiteTree {
// tree customisation
static $icon = "";
static $allowed_children = array("SiteTree"); // set to string "none" or array of classname(s)
static $default_child = "Page"; //one classname
static $default_parent = null; // NOTE: has to be a URL segment NOT a class name
static $can_be_root = true; //
static $hide_ancestor = null; //dont show ancestry class
// extensions and functionality
static $versioning = array();
static $default_sort = "Sort";
/static $extensions = array();
public static $breadcrumbs_delimiter = " &raquo; ";
public function canCreate() {
//here is a trick to only allow one (e.g. holder) of a page
return !DataObject::get_one($this->class);
}
public function canDelete() {
return false;
}
function getCMSFields() {
$fields = parent::getCMSFields();
return $fields;
}
## Recipes
### Automatic Child Selection
By default, `[api:SiteTree]` class to build a tree using the ParentID field. However, sometimes, you want to change
this default behaviour.
For example, in our e-commerce module, we use a many-to-many join, Product::Parents, to let you put Products in multiple
groups. Here's how to implement such a change:
* **Set up your new data model:** Create the appropriate many-many join or whatever it is that you're going to use to
store parents.
* **Define stageChildren method:** This method should return the children of the current page, for the current version.
If you use DataObject::get, the `[api:Versioned]` class will rewrite your query to access the live site when
appropriate.
* **Define liveChildren method:** The method should return the children of the current page, for the live site.
Both the CMS and the site's data controls will make use of this, so navigation, breadcrumbs, etc will be updated. If 1
node appears in the tree more than once, it will be represented differently.
**TO DO:** Work out this representation.
### Custom Children Getters
Returning custom children for a specific `SiteTree` subclass can be handy to influence the tree display within the
CMS. An example of custom children might be products which belong to multiple categories. One category would get its
products from a `$many_many` join rather than the default relations.
Children objects are generated from two functions `stageChildren()` and `liveChildren()` and the tree generation in
the CMS is calculated from `numChildren()`. Please keep in mind that the returned children should still be instances
of `SiteTree`.
Example:
:::php
class MyProduct extends Page {
static $belongs_many_many = array(
'MyCategories' => 'MyCategory'
);
}
class MyCategory extends Page {
static $many_many = array(
'MyProducts' => 'MyProduct'
);
function stageChildren($showAll = false) {
// @todo Implement $showAll
return $this->MyProducts();
}
function liveChildren($showAll = false) {
// @todo Implement $showAll
return $this->MyProducts();
}
function numChildren() {
return $this->MyProducts()->Count();
}
} }
}
### Multiple parents in the tree
The `[api:LeftAndMain]` tree supports multiple parents. We overload CMSTreeClasses and make it include "manyparents" in
the class list.
:::php
function CMSTreeClasses($controller) {
return parent::CMSTreeClasses($controller) . ' manyparents';
}
Don't forget to define a new Parent() method that also references your new many-many join (or however it is you've set
up the hierarchy!
:::php
function getParent() {
return $this->Parent();
}
function Parent() {
$parents = $this->Parents();
if($parents) return $parents->First();
}
Sometimes, you don't want to mess with the CMS in this manner. In this case, leave stageChildren() and liveChildren()
as-is, and instead make another method, such as ChildProducts(), to get the data from your many-many join.
### Dynamic Grouping
Something that has been talked about [here](http://www.silverstripe.com/site-builders-forum/flat/15416#post15940) is the
concept of "dynamic grouping". In essence, it means adding navigational tree nodes to the tree that don't correspond to
a database record.
How would we do this? In our example, we're going to update BlogHolder to show BlogEntry children grouped into months.
We will create a class called BlogMonthTreeNode, which will extend ViewableData instead of DataRecord, since it's not
saved into the database. This will represent our dynamic groups.
### LeftAndMain::getSiteTreeFor()
Currently LeftAndMain::getSiteTreeFor() Calls LeftAndMain::getRecord($id) to get a new record. We need to instead
create a new function getTreeRecord($id) which will be able to create BlogMonthTreeNode objects as well as look up
SiteTree records from the database.
The IDs don't **need** be numeric; so we can set the system to allow for 2 $id formats.
* (ID): A regular SiteTree object
* BlogMonthTreeNode-(BlogHolderID)-(Year)-(Month): A BlogMonthTreeNode object
To keep the code generic, we will assume that if the $id isn't numeric, then we should explode('-', $id), and use the
first part as the classname, and all the remaining parts as arguments to the constructor.
Your BlogMonthTreeNode constructor will then need to take $blogHolderID, $year, $month as arguments.
### Divorcing front-end site's Children() and the CMS's AllChildrenIncludingDeleted()
We need a way of cleanly specifying that there are two different child sources - children for the CMS tree, and children
for the front-end site.
* We currently have stageChildren() / liveChildren()
* We should probably add cmsStageChildren() and cmsLiveChildren() into the mix, for SiteTree.
AllChildrenIncludingDeleted() could then call the "cms..." versions of the functions, but if we were to to this, we
should probably rename AllChildrenIncludingDeleted() to CMSTreeChildren() or something like that.
### BlogHolder::cmsStageChildren() & BlogHolder::cmsLiveChildren()
We will need to define these methods, to
* Get the stage/live children of the page, grouped by month
* For each entry returned, generate a new BlogMonthTreeNode object.
* Return that as a dataobjectset.
### BlogMonthTreeNode
* Parameter 'ID': should return 'BlogMonthTreeNode-(BlogHolderID)-(Year)-(Month)'. You can do this by implementing
getID().
* Methods cmsStageChildren() and cmsLiveChildren(): These should return the blog-entries for that month.
After that, there will be some other things to tweak, like the tree icons.
### Where to from here?
This is a lot of work for the specific example of blog-entries grouped by month. Instead of BlogMonthTreeNode, you
could genericise this to a DynamicTreeGroup class, which would let you specify the parent node, the type of grouping,
and the specific group.
## TODO
Clean up this documentation
## API Documentation
`[api:Sitetree]`

View File

@ -0,0 +1,208 @@
# SQL Query
## Introduction
An object representing a SQL query. It is easier to deal with object-wrappers than string-parsing a raw SQL-query. This
object is used by `[api:DataObject]`, though...
A word of caution: Dealing with low-level SQL is not encouraged in the Silverstripe [datamodel](/topics/datamodel) for various
reasons. You'll break the behaviour of:
* Custom getters/setters
* DataObject::onBeforeWrite/onBeforeDelete
* Automatic casting
* Default-setting through object-model
* `[api:DataObject]`
* Database abstraction
We'll explain some ways to use *SELECT* with the full power of SQL, but still maintain a connection to the Silverstripe
[datamodel](/topics/datamodel).
## Usage
### SELECT
:::php
$sqlQuery = new SQLQuery();
$sqlQuery->select = array(
'Firstname AS Name',
'YEAR(Birthday) AS BirthYear'
);
$sqlQuery->from = "
Player
LEFT JOIN Team ON Player.TeamID = Team.ID
";
$sqlQuery->where = "
YEAR(Birthday) = 1982
";
// $sqlQuery->orderby = "";
// $sqlQuery->groupby = "";
// $sqlQuery->having = "";
// $sqlQuery->limit = "";
// $sqlQuery->distinct = true;
// get the raw SQL
$rawSQL = $sqlQuery->sql();
// execute and return a Query-object
$result = $sqlQuery->execute();
### DELETE
:::php
// ...
$sqlQuery->delete = true;
### INSERT/UPDATE
(currently not supported -see below for alternative solutions)
## Working with results
The result is an array lightly wrapped in a database-specific subclass of `[api:Query]`. This class implements the
*Iterator*-interface defined in PHP5, and provides convenience-methods for accessing the data.
### Iterating
:::php
foreach($result as $row) {
echo $row['BirthYear'];
}
### Quick value checking
Raw SQL is handy for performance-optimized calls.
:::php
class Team extends DataObject {
function getPlayerCount() {
$sqlQuery = new SQLQuery(
"COUNT(Player.ID)",
"Team LEFT JOIN Player ON Team.ID = Player.TeamID"
);
return $sqlQuery->execute()->value();
}
Way faster than dealing with `[api:DataObject]`s, but watch out for premature optimisation:
:::php
$players = $myTeam->Players();
echo $players->Count();
### Mapping
Useful for creating dropdowns.
:::php
$sqlQuery = new SQLQuery(
array('YEAR(Birthdate)', 'Birthdate'),
'Player'
);
$map = $sqlQuery->execute()->map();
$field = new DropdownField('Birthdates', 'Birthdates', $map);
### "Raw" SQL with DB::query()
This is not recommended for most cases, but you can also use the Silverstripe database-layer to fire off a raw query:
:::php
DB::query("UPDATE Player SET Status='Active'");
One example for using a raw DB::query is when you are wanting to order twice in the database:
:::php
$records = DB::query('SELECT *, CASE WHEN "ThumbnailID" = 0 THEN 2 ELSE 1 END AS "HasThumbnail" FROM "TempDoc" ORDER BY "HasThumbnail", "Name" ASC');
$items = singleton('TempDoc')->buildDataObjectSet($records);
This CASE SQL creates a second field "HasThumbnail" depending if "ThumbnailID" exists in the database which you can then
order by "HasThumbnail" to make sure the thumbnails are at the top of the list and then order by another field "Name"
separately for both the items that have a thumbnail and then for those that don't have thumbnails.
### "Semi-raw" SQL with buildSQL()
You can gain some ground on the datamodel-side when involving the selected class for querying. You don't necessarily
need to call *buildSQL* from a specific object-instance, a *singleton* will do just fine.
:::php
$sqlQuery = singleton('Player')->buildSQL(
'YEAR(Birthdate) = 1982'
);
This form of building a query has the following advantages:
* Respects DataObject::$default_sort
* Automatically LEFT JOIN on all base-tables (see [database-structure](database-structure))
* Selection of *ID*, *ClassName*, *RecordClassName*, which are necessary to use *buildDataObjectSet* later on
* Filtering records for correct *ClassName*
### Transforming a result to DataObjectSet
This is a commonly used technique inside Silverstripe: Use raw SQL, but transfer the resulting rows back into
DataObjects.
:::php
$sqlQuery = new SQLQuery();
$sqlQuery->select = array(
'Firstname AS Name',
'YEAR(Birthday) AS BirthYear',
// IMPORTANT: Needs to be set after other selects to avoid overlays
'Player.ClassName AS ClassName',
'Player.ClassName AS RecordClassName',
'Player.ID AS ID'
);
$sqlQuery->from = array(
"Player",
"LEFT JOIN Team ON Player.TeamID = Team.ID"
);
$sqlQuery->where = array(
"YEAR(Player.Birthday) = 1982"
);
$result = $sqlQuery->execute();
var_dump($result->first()); // array
// let Silverstripe work the magic
$myDataObjectSet = singleton('Player')->buildDataObjectSet($result);
var_dump($myDataObjectSet->First()); // DataObject
// this is where it gets tricky
$myFirstPlayer = $myDataObjectSet->First();
var_dump($myFirstPlayer->Name); // 'John'
var_dump($myFirstPlayer->Firstname); // undefined, as it was not part of the SELECT-clause;
var_dump($myFirstPlayer->Surname); // undefined, as it was not part of the SELECT-clause
// lets assume that class Player extends BasePlayer,
// and BasePlayer has a database-column "Status"
var_dump($myFirstPlayer->Status); // undefined, as we didn't LEFT JOIN the BasePlayer-table
CAUTION: Depending on the selected columns in your query, you might get into one of the following scenarios:
* Not all object-properties accessible: You need to take care of selecting the right stuff yourself
* Overlayed object-properties: If you *LEFT JOIN* a table which also has a column 'Birthdate' and do a global select on
this table, you might not be able to access original object-properties.
* You can't create DataObjects where no scalar record-data is available, e.g. when using *GROUP BY*
* Naming conflicts with custom getters: A getter like Player->getName() will overlay the column-data selected in the
above example
Be careful when saving back DataObjects created through *buildDataObjectSet*, you might get strange side-effects due to
the issues noted above.
## Using FormFields with custom SQL
Some subclasses of `[api:FormField]` for ways to create sophisticated report-tables based on SQL.
## Related
* [datamodel](/topics/datamodel)
* `[api:DataObject]`
* [database-structure](database-structure)
## API Documentation
`[api:SQLQuery]`

View File

@ -0,0 +1,288 @@
# Static Publisher
## Introduction
Many sites get too much traffic to justify dynamically sending every request. Caching is needed. Static Publishing
will generate static versions of your content (HTML) that can be served without ever hitting PHP or the Database.
See `[api:StaticExporter]` for a less flexible, but easier way of building a local static cache from all of
your pages.
See [Partial-Caching](partial-caching) for a much more flexible way of building in caching without statically delivering
content. Partial Caching is recommended as a basic enhancement to any SilverStripe site however if your site is planning
a vast amount of traffic (eg an article is being dug) then Static Publisher will be appropriate.
## Requirements
*Requires SilverStripe 2.3*
## Usage
SilverStripe doesn't have enough information about your template and data-structures to automatically determine which
URLs need to be cached, and at which time they are considered outdated. By adding a custom method allPagesToCache() to
your Page class, you can determine which URLs need caching, and hook in custom logic. This array of URLs is used by the
publisher to generate folders and HTML-files.
:::php
class Page extends SiteTree {
// ...
/**
* Return a list of all the pages to cache
*/
function allPagesToCache() {
// Get each page type to define its sub-urls
$urls = array();
// memory intensive depending on number of pages
$pages = DataObject::get("SiteTree");
foreach($pages as $page) {
$urls = array_merge($urls, (array)$page->subPagesToCache());
}
// add any custom URLs which are not SiteTree instances
$urls[] = "sitemap.xml";
return $urls;
}
/**
* Get a list of URLs to cache related to this page
*/
function subPagesToCache() {
$urls = array();
// add current page
$urls[] = $this->Link();
// cache the RSS feed if comments are enabled
if ($this->ProvideComments) {
$urls[] = Director::absoluteBaseURL() . "pagecomment/rss/" . $this->ID;
}
return $urls;
}
function pagesAffectedByChanges() {
$urls = $this->subPagesToCache();
if($p = $this->Parent) $urls = array_merge((array)$urls, (array)$p->subPagesToCache());
return $urls;
}
}
## Excluding Pages
The allPagesToCache function returns all the URLs needed to cache. So if you want to exclude specific pages from the
cache then you unset these URLs from the returned array. If you do not want to cache a specific class (eg UserDefinedForms)
you can also add an exclusion
:::php
function allPagesToCache() {
$urls = array();
$pages = DataObject::get("SiteTree");
// ignored page types
$ignored = array('UserDefinedForm');
foreach($pages as $page) {
// check to make sure this page is not in the classname
if(!in_array($page->ClassName, $ignored)) {
$urls = array_merge($urls, (array)$page->subPagesToCache());
}
}
return $urls;
}
You can also pass the filtering to the original DataObject::get("SiteTree");
:::php
function allPagesToCache() {
$urls = array();
$pages = DataObject::get("SiteTree", "ClassName != 'UserDefinedForm'");
...
## Single server Caching
This setup will store the cached content on the same server as the CMS. This is good for a basic performance enhancement.
### Setup
Put this in mysite/_config.php. This will create static content in a "cache/" subdirectory, with an HTML suffix.
:::php
Object::add_extension("SiteTree", "FilesystemPublisher('cache/', 'html')");
* Put this into your .htaccess. It will serve requests from the cache, statically, if the cache file exists. Replace
**sitedir** with the a subdirectory that you would like to serve the site from (for example, in your dev environment).
[View .htaccess
example](http://open.silverstripe.com/browser/modules/cms/trunk/code/staticpublisher/htaccess_example_rsyncsingleserver)
* **New for 2.4:** In 2.4, we use a simple PHP script, static-main.php, to control cache lookup. This make the
.htaccess update simpler.
Just look for this line:
RewriteRule .* sapphire/main.php?url=%1&%{QUERY_STRING} [L]
And change the PHP script from main.php to static-main.php:
RewriteRule .* sapphire/static-main.php?url=%1&%{QUERY_STRING} [L]
## Using Static Publisher With Subsites Module
Append the following code to mysite/config.php
:::php
FilesystemPublisher::$domain_based_caching = true;
Instead of the above code snippet for Page.php, use the following code:
:::php
class Page extends SiteTree {
// ...
function allPagesToCache() {
// Get each page type to define its sub-urls
$urls = array();
// memory intensive depending on number of pages
$pages = Subsite::get_from_all_subsites("SiteTree");
foreach($pages as $page) {
$urls = array_merge($urls, (array)$page->subPagesToCache());
}
return $urls;
}
function subPagesToCache() {
$urls = array();
$urls[] = $this->AbsoluteLink();
return $urls;
}
function pagesAffectedByChanges() {
$urls = $this->subPagesToCache();
if($p = $this->Parent) $urls = array_merge((array)$urls, (array)$p->subPagesToCache());
return $urls;
}
// ... some other code ...
}
And the last thing you need to do is adding your main site's host mapping to subsites/host-map.php. For example, your
main site's host is mysite.com the content of the file would be:
:::php
<?php
$subsiteHostmap = array (
// .. subsite hots mapping ..,
'mysite.com', 'mysite.com'
);
Remember that you need to add main site's host mapping every time a subsite is added or modified because the operation
overwrites your manual modification to the file and subsite module does not add main site's hot mapping automatically at
the moment.
Another note for host-map.php file. This file doesn't not exist until you have created at least one subsite.
## Multiple Server Caching
In this setup, you have one server that is your dynamic CMS server, and one or more separate servers that are
responsible for serving static content. The publication system on the CMS will rsync changes to the static content
servers as needed. No PHP files will be synced to the static content servers unless explicitly requested. All static
assets (images, javascript, etc.) will be rsynced from their original locations. You can then put a load-balancer on the
front of the static content servers.
This approach is very secure, because you can lock the CMS right down (for example, by IP) and hide all the PHP code
away from potential hackers. It is also good for high-traffic situations.
### Setup
Add the RsyncMultiHostPublisher extension to your SiteTree objects in mysite/_config.php. This will create static
content in a "cache/" subdirectory, with an HTML suffix.
:::php
Object::add_extension("SiteTree", "RsyncMultiHostPublisher('cache/', 'html')");
RsyncMultiHostPublisher::set_targets(array(
'<rsyncuser>@<static-server1>:<webroot>',
'<rsyncuser>@<static-server2>:<webroot>',
));
Where `<rsyncuser>` is a unix account with write permissions to `<webroot>` (e.g. `/var/www`), and
`<static-server1>` and `<static-server2>` are the names of your static content servers. The number of servers is
flexible and depends on your infrastructure and scalability needs.
* Ensure that the `rsync` unix tool is installed on the CMS server, and ssh access is enabled on the static content
servers.
* No password can be specified for the SSH connection . The class assumes a key-based authentication without requiring
a password for the username specified in `<rsyncuser>` (see [http://www.csua.berkeley.edu/~ranga/notes/ssh_nopass.html
tutorial](http://www.csua.berkeley.edu/~ranga/notes/ssh_nopass.html tutorial)).
* Put the .htaccess file linked below into the webroot of each static content server (and rename it to `.htaccess`).
It will serve requests from the cache, statically, if the cache file exists. Replace **sitedir** with the a
subdirectory that you would like to serve the site from (for example, in your dev environment).
[View .htaccess
example](http://open.silverstripe.com/browser/modules/cms/trunk/code/staticpublisher/htaccess_example_rsyncmultiservers)
## Cache Control
There is also the option to wrap some PHP logic around the static HTML content served by the content servers, which can
greatly reduce the bandwidth required on your content servers. This code takes care of cache control through HTTP
headers (''Cache-control'', `If-modified-since`), meaning the files will only be delivered if they changed since the
browser client last requested them. The last modification date for each static file is controlled by the publication
script, meaning the cache gets invalidated on each publication.
To enable cache control, specify "php" instead of "html" in the RsyncMultiHostPublisher definition.
:::php
Object::add_extension("SiteTree", "RsyncMultiHostPublisher('cache/', 'php')");
And use this slightly different .htaccess file. Make sure that index.php can be used as a directory index!
[View .htaccess
example](http://open.silverstripe.com/browser/modules/cms/trunk/code/staticpublisher/htaccess_example_rsyncwithphp)
## Deployment
Once you've set up your rewrite rules and defined which pages need caching, you can build the static HTML files. This is
done by the `[api:RebuildStaticCacheTask]`
Execution via URL
http://www.example.com/dev/buildcache?flush=1
Execution on CLI (via [sake](/topics/commandline))
sake dev/buildcache flush=1
Depending on which extension you've set up for your SiteTree (FilesystemPublisher or RsyncMultiHostPublisher), the
method publishPages() either stores the generated HTML-files on the server's filesystem, or deploys them to other
servers via rsync.
It is adviseable to set dev/buildcache up as an automated task (e.g. unix cron) which continually rebuilds and redeploys
the cache.
## Related
* `[api:StaticExporter]`
* [Partial-Caching](partial-caching)
## API Documentation
* `[api:StaticPublisher]`

View File

@ -0,0 +1,82 @@
# TableField
## Introduction
TableField behaves in the same manner as `[api:TableListField]`, however allows the editing of existing and adding of
new rows.
The data is saved back by the surrounding form-saving (mostly EditForm->save).
See `[api:TableListField]` for more documentation on the base-class
## Usage
### Add hidden default data
Please use **TableField->setExtraData()** to specify additional (non-editable) data. You might use the following code
that shows the Player of Team with a particular Team ID and automatically saves new Players into this Team.
In this example, you'll note that we're setting TeamID to $this->ID. This works well if you're including a TableField
as an editable field on a getCMSFields() call.
:::php
$myTableField = new TableField(
'MyTableField', // fieldName
'Player', // sourceType
array(
'FirstName'=>'First Name',
'Surname'=>'Surname'
), // fieldList
array(
'FirstName'=>'TextField',
'Surname'=>'TextField'
), // fieldTypes
null, // filterField (legacy)
"Player.TeamID",
$this->ID
);
// add some HiddenFields thats saved with each new row
$myTableField->setExtraData(array(
'TeamID' => $this->ID ? $this->ID : '$RecordID'
));
The '$RecordID' value is used when building forms that create new records. It will be populated with whatever record id
is created.
### Row Transformation
You can apply a `[api:FormTransformation]` to any given field,
based on a eval()ed php-rule. You can access all columns on the generated DataObjects here.
:::php
$myTF->setTransformationConditions(array(
"PlayerName" => array(
"rule" => '$PlayerStatus == "Retired" || $PlayerStatus == "Injured"',
"transformation" => "performReadonlyTransformation"
)
));
### Required Fields
Due to the nested nature of this fields dataset, you can't set any required columns as usual with the
`[api:RequiredFields]`** on the TableField-instance for this.
Note: You still have to attach some form of `[api:Validator]` to the form to trigger any validation on this field.
### Nested Table Fields
When you have TableField inside a `[api:ComplexTableField]`, the parent ID may not be known in your
getCMSFields() method. In these cases, you can set a value to '$RecordID' in your TableField extra data, and this will
be populated with the newly created record id upon save.
## Known Issues
* A TableField doesn't reload any submitted form-data if the saving is interrupted by a failed validation. After
refreshing the form with the validation-errors, the TableField will be blank again.
* You can't add **visible default data** to columns in a TableField, please use *setExtraData*
## API Documentation
`[api:TableField]`

View File

@ -0,0 +1,288 @@
# TableListField
## Introduction
Form field that embeds a list of `[api:DataObject]`s into a form, such as a member list or a file list.
Provides customizeable columns, record-deletion by ajax, paging, sorting, CSV-export, printing, input by
`[api:DataObject]` or raw SQL.
## Example
Here's an example of a full featured TableListField implementation. It features editing members in the database directly
as a button on each record, as well as filtering, and sorting. It also makes use of the 'export' permission, allowing
export of data as a CSV.
:::php
function getReportField() {
$resultSet = new DataObjectSet();
$filter = `;
$sort = "Member.ID ASC";
$join = `;
$instance = singleton('Member');
$query = $instance->buildSQL($filter, $sort, null, $join);
$query->groupby[] = 'Member.ID';
$report = new TableListField(
'CorporateReport',
'Member',
array(
'ID' => 'ID',
'FirstName' => 'First Name',
'Surname' => 'Surname',
'Email' => 'Email',
'MembershipType' => 'Membership Type',
'MembershipStatus' => 'Membership Status',
'DateJoined' => 'Date Joined',
'PaidUntil' => 'Paid Until',
'Edit' => ''
)
);
$report->setCustomQuery($query);
$report->setFieldFormatting(array(
'Email' => '<a href=\"mailto: $Email\" title=\"Email $FirstName\">$Email</a>',
'Edit' => '<a href=\"admin/security/index/1?executeForm=EditForm&ID=1&ajax=1&action_callfieldmethod&fieldName=Members&ctf[childID]=$ID&ctf[ID]=1&ctf[start]=0&methodName=edit\"><img src=\"cms/images/edit.gif\" alt=\"Edit this member\" /></a>'
));
$report->setFieldCasting(array(
'DateJoined' => 'Date->Nice',
'PaidUntil' => 'Date->Nice'
));
$report->setShowPagination(true);
if(isset($_REQUEST['printable'])) {
$report->setPageSize(false);
} else {
$report->setPageSize(20);
}
$report->setPermissions(array(
'export',
'delete',
'print'
));
return $report;
}
For more information on each of the features used in the example, you can read below.
## Usage
### Source Input
:::php
// default: DataObject selection (e.g. all 'Product's)
$myTableListField = new TableListField(
'MyName',
'Product',
array('Price', 'Code')
);
// custom DataObjectSet
$myProducts = DataObject::get('Product','Code = "MyCode"');
$myTableListField->setCustomSourceItems($myProducts);
// custom SQL
$customCsvQuery = singleton('Product')->buildSQL();
$customCsvQuery->select[] = "CONCAT(col1,col2) AS MyCustomSQLColumn";
$myTableListField->setCustomCsvQuery($customQuery);
TableListField also tries to resolve Component-relations(has_one, has_many) and custom getters automatically:
:::php
$myTableListField = new TableListField(
'MyName',
'Product',
array(
'Buyer.LastName',
'PriceWithShipping'
)
);
// Product.php Example
class Product extends DataObject {
$has_one = array('Buyer'=>'Member');
function getPriceWithShipping() {
return $this->Price + $this->Shipping;
}
}
### Pagination
Paging works by AJAX, but also works without javascript on link-basis.
:::php
$myTableListField->setPageSize(100); // defaults to 20
### Sorting
The easiest method is to add the sorting criteria as a constructor parameter. Sorting should be applied manually, where
appropriate. Only direct columns from the produced SQL-query are supported.
Example (sorting by "FirstName" column):
:::php
$report = new TableListField(
'CorporateReport', // name
'Member', // sourceClass
array(
'ID' => 'ID',
'FirstName' => 'First Name',
'LastName' => 'Last Name',
), // fieldList
null, // sourceFilter
'FirstName' // sourceSort
);
If you want to sort by custom getters in your DataObject, please reformulate them to a custom SQL column. This
restriction is needed to avoid performance-hits by caching and sorting potentially large datasets on PHP-level.
### Casting
Column-values can be casted, based on the casting-types available through DBObject (sapphire/core/model/fieldtypes).
:::php
$myTableListField->setFieldCasting(array(
"MyCustomDate"=>"Date",
"MyShortText"=>"Text->FirstSentence"
));
### Permissions
Permissions vary in different TableListField-implementations, and are evaluated in the template.
By default, all listed permissions are enabled.
:::php
$myTableListField->setPermissions(array(
'delete',
'export',
'print'
));
### Formatting
Specify custom formatting for fields, e.g. to render a link instead of pure text.
Caution: Make sure to escape special php-characters like in a normal php-statement.
:::php
$myTableListField->setFieldFormatting(array(
"myFieldName" => '<a href=\"custom-admin/$ID\">$ID</a>'
));
### Highlighting
"Highlighting" is similiar to "Formatting", but applies to the whole row rather than a column.
Definitions for highlighting table-rows with a specific CSS-class. You can use all column-names
in the result of a query. Use in combination with {@setCustomQuery} to select custom properties and joined objects.
:::php
$myTableListField->setHighlightConditions(array(
array(
"rule" => '$Flag == "red"',
"class" => "red"
),
array(
"rule" => '$Flag == "orange"',
"class" => "orange"
)
));
### Export
Export works only to CSV currently, with following specs:
* Line delimiter: "\n"
* Separator: ";"
* Column-quotes: none
:::php
$myTableListField->setPermissions(array('export'));
$myTableListField->setFieldListCsv(array(
'Price' => 'Price',
'ItemCount' => 'Item Count',
'ModelNumber' => 'Model Number'
));
You can influence the exported values by adjusting the generated SQL.
:::php
$customCsvQuery = singleton('Product')->buildSQL();
$customCsvQuery->select[] = "CONCAT(col1,col2) AS MyCustomSQLColumn";
$myTableListField->setCustomCsvQuery($customQuery);
$myTableListField->setFieldListCsv(array(
'MyCustomSQLColumn'
));
### Row-Summaries
You can summarize specific columns in your result-set. The term "summary" is used in a broad sense, you can also
implement averages etc.
:::php
$myTableListField->addSummary(
'Total Revenue and Sales Count',
array(
"Price" => array("sum","Currency->Nice"),
"ItemCount" => "sum"
)
);
In TableField-implementation, these summaries also react to changes in input-fields by javascript.
Available methods:
* sum
* avg
### Grouping
Used to group by a specific column in the DataObject and create partial summaries.
Please use only together with addSummary().
(Automatically disables sorting).
:::php
$myTableListField->groupByField = 'MyColumnName';
## Best Practices
### Custom Sorting
Please subclass TableListField to implement custom sorting, following the naming-convention
"`colFunction_<yourFunctionName>`".
:::php
class CustomTableListField extends TableListField {
// referenced through "dateAverage"
function colFunction_dateAverage($values) {
// custom date summaries
}
}
### Adding Utility-functions
In case you want to perform utility-functions like "export" or "print" through action-buttons,
make sure to subclass Utility() which collates all possible actions.
### Customizing Look&Feel
You can exchange the used template, e.g. to change applied CSS-classes or the HTML-markup:
:::php
$myTableListField->setTemplate("MyPrettyTableListField");
## API Documentation
[api:TableListField]

View File

@ -0,0 +1,108 @@
# Typography
## Introduction
SilverStripe lets you customise the style of content in the CMS.
## Usage
This is done by setting up a CSS file called
(projectname)/css/typography.css
You also need to create a file called (projectname)/css/editor.css with the following content:
:::css
/**
* This support file is used to style the WYSIWYG editor in the CMS
*/
@import "typography.css";
body.mceContentBody {
min-height: 200px;
font-size: 62.5%;
}
body.mceContentBody a.broken {
background-color: #FF7B71;
border: 1px red solid;
}
In typography.css you can define styles of any of the tags that will get created by the editor:
* P, BLOCKQUOTE
* H1-6
* UL, OL, LI
* TABLE
* STRONG, EM, U
* A
It's important to realise that this CSS file is included directly into the CMS system, and if you aren't careful, you
can alter the styling of other parts of the interface. While this is novel, it can be dangerous and is probably not
what you're after.
The way around this is to limit all your styling selectors to elements inside something with class="typography". The
other half of this is to put class="typography" onto any area in your template where you would like the styling to be
applied.
**WRONG**
:::css
CSS:
h1, h2 {
color: #F77;
}
Template:
<div>
$Content
</div>
**RIGHT**
:::css
CSS:
.typography h1, .typography h2 {
color: #F77;
}
Template:
<div class="typography">
$Content
</div>
If you would to include different styles for different sections of your site, you can use class names the same as the
name of the data fields. This example sets up different paragraph styles for 2 HTML editor fieldsc alled Content and
OtherContent:
:::css
.Content.typography p {
font-size: 12px;
}
.OtherContent.typography p {
font-size: 10px;
}
### Removing the typography class
Sometimes, it's not enough to add a class, you also want to remove the typography class. You can use the
HTMLEditorField method setCSSClass.
This example sets another CSS class typographybis:
:::php
function getCMSFields() {
...
$htmleditor = new HTMLEditorField("ContentBis", "Content Bis");
$htmleditor->setCSSClass('typographybis');
$fields->addFieldToTab("Root.Content.Main", $htmleditor);
...
return $fields;
}
This functionality will be available in the version 2.0.2 of the CMS.

View File

@ -0,0 +1,92 @@
# URL Variable Tools
## Introduction
This page lists a number of "page options" , "rendering tools" or "special URL variables" that you can use to debug your
sapphire applications. These are consumed in PHP using the $_REQUEST or $_GET superglobals throughout the Sapphire
core.
**General Usage**
Append the option and corresponding value to your URL in your browser's address bar. You may find the [Firefox UrlParams extension](https://addons.mozilla.org/en-US/firefox/addon/1290) useful in order to debug a POST requests (Like Forms).
http://yoursite.com/page?option_name=value
http://yoursite.com/page?option_1=value&option_2=value
## Templates
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| flush | | 1,all | | This will clear out all cached information about the page. This is used frequently during development - for example, when adding new PHP or SS files. See below for value descriptions. |
| showtemplate | | 1 | | Show the compiled version of all the templates used, including line numbers. Good when you have a syntax error in a template. Cannot be used on a Live site without **isDev** **flush** can be used with the following values: |
| ?flush=1 | | | | | Flushes the current page and included templates |
| ?flush=all | | | | Flushes the entire template cache |
## General Testing
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| isDev | | 1 | | Put the site into [development mode](/topics/debugging), enabling debugging messages to the browser on a live server. For security, you'll be asked to log in with an administrator log-in |
| isTest | | 1 | | Put the site into [test mode](/topics/debugging), enabling debugging messages to the admin email and generic errors to the browser on a live server |
| debug | | 1 | | Show a collection of debugging information about the director / controller operation |
| debug_request | | 1 | | Show all steps of the request from initial HTTPRequest to Controller to Template Rendering |
## Classes and Objects
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| debugmanifest | | 1 | | Show the entire Sapphire manifest as currently built (Use /dev/build to rebuild) |
| usetestmanifest | | 1 | | Force use of the default test manifest |
| debugmethods | | 1 | | Shows all methods available when an object is constructed (useful when extending classes or using object decorators) |
| debugfailover | | 1 | | Shows failover methods from classes extended |
## Database
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| showqueries | | 1 | | List all SQL queries executed |
| previewwrite | | 1 | | List all insert / update SQL queries, and **don't** execute them. Useful for previewing writes to the database. |
## Profiling
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| debug_memory | | 1 | | Output the number of bytes of memory used for this request |
| debug_profile | | 1 | | Enable the [profiler](/topics/debugging) for the duration of the request |
| profile_trace | | 1 | | Includes full stack traces, must be used with **debug_profile** |
| debug_behaviour | | 1 | | Get profiling of [Behaviour.js](http://bennolan.com/behaviour) performance (Firebug recommended) |
| debug_javascript | | 1 | | Force debug-output on live-sites |
## Misc
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| forceFormat | | xhtml,html | | Force the content negotiator to deliver HTML or XHTML is allowed |
| showspam | | 1 | | Show comments marked as spam when viewing Comments on a Page (Saving spam to the database must be enabled) |
| ajax | | 1 | | Force request to process as AJAX request, useful for debugging from a browser |
| force_ajax | | 1 | | Similar to **ajax** |
## Security Redirects
You can set an URL to redirect back to after a [Security](/topics/security) action. See the section on [URL
Redirections](security#redirect_back_to_another_page_after_login) for more information and examples.
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| BackURL | | URL | | Set to a relative URL string to use once Security Action is complete |
## Building and Publishing URLS
| Site URL | | Action |
| -------- | | ------ |
| %%http://yoursite.com%%**/dev/build** | | Rebuild the entire database and manifest, see below for additional URL Variables |
| %%http://yoursite.com%%**/admin/publishall/** | | Publish all pages on the site |
| %%http://yoursite.com%%**/anypage/images/flush** | | Creates new images for the page by deleting the resized ones and going back to the original to create new resized one |
### /dev/build
| URL Variable | | Values | | Description |
| ------------ | | ------ | | ----------- |
| quiet | | 1 | | Don't show messages during build |
| dont_populate | | 1 | | Don't run **requireDefaultRecords()** on the models when building. This will build the table but not insert any records |

View File

@ -0,0 +1,33 @@
# Versioned
The Versioned class is a `[api:DataObject]` that adds versioning and staging capabilities to the objects.
## Trapping the publication event
Sometimes, you'll want to do something whenever a particular kind of page is published. This example sends an email
whenever a blog entry has been published.
*SilverStripe 2.3*
:::php
class Page extends SiteTree {
// ...
function publish($fromStage, $toStage, $createNewVersion = false) {
mail("sam@silverstripe.com", "Blog published", "The blog has been published");
return $this->extension_instances['Versioned']->publish($fromStage, $toStage, $createNewVersion);
}
}
*SilverStripe 2.4*
:::php
class Page extends SiteTree {
// ...
function onAfterPublish() {
mail("sam@silverstripe.com", "Blog published", "The blog has been published");
parent::onAfterPublish();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,57 @@
# Access Control and Page Security
There is a fairly comprehensive security mechanism in place for SilverStripe. If you want to add premium content to your
site you have to figure this stuff out, and it's not entirely obvious.
## Ways to restrict access
There are a number of ways to restrict access in SilverStripe. In the security tab in the CMS you can create groups
that have access to certain parts. The options can be found on the [permissions](/reference/permission) documentation.
Once you have groups, you can set access for each page for a particular groups. This can be:
- anyone
- any person who is logged in
- a specific group
It is unclear how this works for data-objects that are not pages.
## The Security Groups in SilverStripe
In the security tab you can make groups for security. The way this was intended was as follows (this may be a counter
intuitive):
- employees
1. marketing
- marketing executive
Thus, the further up the hierarchy you go the MORE privileges you can get. Similarly, you could have:
- members
1. coordinators
- admins
Where members have some privileges, coordinators slightly more and administrators the most; having each group inheriting
privileges from its parent group.
## Permission checking is at class level
SilverStripe provides a security mechanism via the *Permission::check* method (see *LeftAndMain.php* for examples on how
the admin screens work)
(next step -- go from *Permission::checkMember*...
### Nuts and bolts -- figuring it out
Here are my notes trying to figure this stuff out. Not really useful unless you're VERY interested in how exactly SS
works.
### Loading the admin page: looking at security
If you go to [your site]/admin -- how does that work?
*Director.php* maps the 'admin' URL request through a *Director* rule to the CMSMain controller (see `[api:CMSMain]`, with no arguments.
*CMSMain.init()* calls its parent which, of all things is called *LeftAndMain*. It's in *LeftAndMain* that the
important security checks are made by calling *Permission::check*.
`[api:Security::permissionFailure]` is the next utility function you can use to redirect to the login form.
### Customizing Access Checks in CMS Classes
see `[api:LeftAndMain]`

View File

@ -0,0 +1,125 @@
# Commandline Usage via "sake"
## Introduction
SilverStripe can call controllers through commandline `php` just as easily as through a web browser.
This can be handy to automate tasks with cron jobs, run unit tests and maintenance tasks,
and a whole bunch of other scripted goodness.
The main entry point for any commandline execution is `cli-script.php`. For example, to run a database rebuild
from the commandline, use this command:
cd your-webroot/
php sapphire/cli-script.php dev/build
Make sure that your commandline php version uses the same configuration as your webserver (run `php -i` to find out more).
## GET parameters as arguments
You can add parameters to the command by using normal form encoding.
All parameters will be available in `$_GET` within SilverStripe.
cd your-webroot/
php sapphire/cli-script.php myurl myparam=1 myotherparam=2
## SAKE: Sapphire make
Sake is a simple wrapper around `cli-script.php`. It also tries to detect which `php` executable to use
if more than one are available.
**If you are using a debian server:** Check you have the php-cli package installed for sake to work.
If you get an error when running the command php -v, then you may not have php-cli installed so sake won't work.
### Installation
You can copy the `sake` file into `/usr/bin/sake` for easier access (this is optional):
cd your-webroot/
sudo ./sapphire/sake installsake
Note: This currently only works on unix-like systems, not on Windows.
## Configuration
Sometimes SilverStripe needs to know the URL of your site, for example, when sending an email. When you're visiting
your site in a web browser this is easy to work out, but if you're executing scripts on the command-line, it has no way
of knowing.
To work this out, you should add lines of this form to your [_ss_environment.php](/topics/environment-management) file.
:::php
global $_FILE_TO_URL_MAPPING;
$_FILE_TO_URL_MAPPING['/Users/sminnee/Sites'] = 'http://localhost';
What the line says is that any Folder under /Users/sminnee/Sites/ can be accessed in a web browser from
http://localhost. For example, /Users/sminnee/Sites/mysite will be available at http://localhost/mysite.
You can add multiple file to url mapping definitions. The most specific mapping will be used. For example:
:::php
global $_FILE_TO_URL_MAPPING;
$_FILE_TO_URL_MAPPING['/Users/sminnee/Sites'] = 'http://localhost';
$_FILE_TO_URL_MAPPING['/Users/sminnee/Sites/mysite'] = 'http://mysite.localhost';
Using this example, /Users/sminnee/Sites/mysite/ would be accessed at http://mysite.localhost/, and
/Users/sminnee/Sites/othersite/ would be accessed at http://localhost/othersite/
## Usage
Sake will either run `./sapphire/cli-script.php` or `./cli-script.php`, depending on what's available.
It's particularly useful for running build tasks...
cd /your/site/folder
sake db/build
sake dev/tests/all
It can also be handy if you have a long running script.
cd /your/site/folder
sake MyReallyLongTask
### Running processes
You can use sake to make daemon processes for your application.
Step 1: Make a task or controller class that runs a loop. Because Sapphire has memory leaks, you should make the PHP
process exit when it hits some reasonable memory limit. Sake will automatically restart your process whenever it exits.
The other thing you should do is include some appropriate sleep()s so that your process doesn't hog the system. The
best thing to do is to have a short sleep when the process is in the middle of doing things, and a long sleep when
doesn't have anything to do.
This code provides a good template:
:::php
class MyProcess extends Controller {
function index() {
set_time_limit(0);
while(memory_get_usage() < 32*1024*1024) {
if($this->somethingToDo()) {
$this->doSomething();
sleep(1)
} else {
sleep(300);
}
}
}
}
Step 2: Install the "daemon" command-line tool on your server.
Step 3: Use sake to start and stop your process
sake -start MyProcess
sake -stop MyProcess
Note that sake processes are currently a little brittle, in that the pid and log files are placed in the site root
directory, rather than somewhere sensible like /var/log or /var/run.

View File

@ -0,0 +1,77 @@
# Common Configuration through _config.php
## Introduction
Silverstripe doesn't have a global configuration-array or an interface with all available configuration-options. As all
Silverstripe logic is contained in classes, the appropriate place to configure their behaviour is directly in the class
itself.
This lack of a configuration-GUI is on purpose, as we'd like to keep developer-level options where they belong (into
code), without cluttering up the interface. See this core forum discussion ["The role of the
CMS"](http://www.silverstripe.com/core-team-discussion/flat/2723) for further reasoning.
In addition to these principle, some settings are
* Author-level configuration like interface language or date/time formats can be performed in the CMS "My Profile" section (`admin/myprofile`).
* Group-related configuration like [api:HTMLEditorField] settings can be found in the "Security" section (`admin/security`).
* Site-wide settings like page titles can be set (and extended) on the root tree element in the CMS "Content" section (through the [siteconfig](/reference/siteconfig) API).
## _ss_environment.php
See [environment-management](/topics/environment-management).
## mysite/_config.php
This file is detected in each folder by `[api:ManifestBuilder]`. This way, every toplevel-folder (=module)
can have independent configuration-rules.
//Please note that this is the only place where you can put in procedural code - all other functionality is wrapped in
classes (see [common-problems](/installation/common-problems)).//
You can call most static methods from _config.php - classes will be loaded as required. Here's a list - **this is
incomplete - please add to it** *Try to keep it in alphabetical order too! :)*
| Call | | Description |
| ---- | | ----------- |
| Authenticator::register_authenticator($authenticator);| | Enable an authentication method (for more details see [security](/topics/security)). |
| Authenticator::set_default_authenticator($authenticator); | | Modify tab-order on login-form.|
| BasicAuth::disable() | | Disable basic authentication checking for dev sites (useful when testing credit card transaction post-backs etc) |
| BBCodeParser::disable_autolink_urls(); | | Disables plain hyperlinks from being turned into links when bbcode is parsed. |
| BlogEntry::allow_wysiwyg_editing(); | | Enable rich text editing for blog posts. |
| ContentNegotiator::set_encoding(string $encoding) | | The encoding charset to use - UTF-8 by default |
| ContentNegotiator::disable() | | Disables the negotiation of content type -usually used to stop it from rewriting the DOCTYPE of the document
| Debug::send_errors_to(string $email) | | Send live errors on your site to this address (site has to be in 'live' mode using Director::set_environment_type(live) for this to occur |
| Director::set_environment_type(string dev,test,live) | | Sets the environment type (e.g. dev site will show errors, live site hides them and displays a 500 error instead) |
| Director::set_dev_servers(array('localhost', 'dev.mysite.com)) | | Set servers that should be run in dev mode (see [debugging](debugging)) |
| Director::addRules(int priority, array rules) | | Create a number of URL rules to be checked against when SilverStripe tries to figure out how to display a page. See cms/_config.php for some examples. Note: Using ->something/ as the value for one of these will redirect the user to the something/ page. |
| Email::setAdminEmail(string $adminemail) | | Sets the admin email for the site, used if there is no From address specified, or when you call Email::getAdminEmail() |
| Email::send_all_emails_to(string $email) | | Sends all emails to this address. Useful for debugging your email sending functions |
| Email::cc_all_emails_to(string $email) | | Useful for CC'ing all emails to someone checking correspondence |
| Email::bcc_all_emails_to(string $email) | | BCC all emails to this address, similar to CC'ing emails (above) |
| MathSpamProtection::setEnabled() | | Adds a math spam question to all page comment forms |
| PageComment::enableModeration(); | | Enables comment moderation |
| Security::encrypt_passwords($encrypt_passwords); | | Specify if you want store your passwords in clear text or encrypted (for more details see [security](/topics/security)) |
| Security::set_password_encryption_algorithm($algorithm, $use_salt);| | If you choose to encrypt your passwords, you can choose which algorithm is used to and if a salt should be used to increase the security level even more (for more details see [security](/topics/security)). |
| Security::setDefaultAdmin('admin','password'); | | Set default admin email and password, helpful for recovering your password |
| SSAkismet::setAPIKey(string $key) | | Enables use of the Akismet spam filter. The key must be a valid WordPress API key. |
| SSViewer::set_theme(string $themename) | | Choose the default theme for your site |
## Constants
Some constants are user-defineable within *_ss_environment.php*.
| Name | | Description |
| ---- | | ----------- |
| *TEMP_FOLDER* | | Absolute file path to store temporary files such as cached templates or the class manifest. Needs to be writeable by the webserver user. Defaults to *sys_get_temp_dir()*, and falls back to *silverstripe-cache* in the webroot. See *getTempFolder()* in *sapphire/core/Core.php* |
## User-level: Member-object
All user-related preferences are stored as a property of the `[api:Member]`-class (and as a database-column in the
*Member*-table). You can "mix in" your custom preferences by using `[api:DataObject]` for details.
## Permissions
See [security](/topics/security) and [permission](/reference/permission)
## See Also
[Config Cheat sheet](http://www.ssbits.com/a-config-php-cheatsheet/)

View File

@ -0,0 +1,99 @@
# Controller
Base controller class. You will extend this to take granular control over the actions and url handling of aspects of
your SilverStripe site.
## Example
mysite/code/Controllers/FastFood.php
:::php
<?php
class FastFood_Controller extends Controller {
function order($arguments) {
print_r($arguments);
}
}
?>
mysite/_config.php
:::php
Director::addRules(50, array('fastfood/$Action/$ID/$Name' => 'FastFood_Controller'));
Request for '/fastfood/order/24/cheesefries' would result in the following to the $arguments above. If needed, use
"?flush=1" on the end of request after making any code changes to your controller.
:::ss
Array
(
[Action] => order
[ID] => 24
[Name] => cheesefries
)
## URL Handling
In the above example the URLs were configured using the `[api:Director]` rules in the **_config.php** file.
Alternatively you can specify these in your Controller class via the **$url_handlers** static array (which gets
processed by the RequestHandler).
This is useful when you want to subvert the fixed action mapping of 'fastfood/order/*' to the function **order**. In
the case below we also want any orders coming through '/fastfood/drivethrough/' to use the same order function.
mysite/code/Controllers/FastFood.php
:::php
class FastFood_Controller extends Controller {
public static $url_handlers = array(
'drivethrough/$Action/$ID/$Name' => 'order'
);
## URL Patterns
The RequestHandler class will parse all rules you specify against the following patterns.
**A rule must always start with alphabetical ([A-Za-z]) characters or a $Variable declaration**
| Pattern | | Description |
| ----------- | | --------------- |
| `$` | | **Param Variable** - Starts the name of a paramater variable, it is optional to match this unless ! is used |
| `!` | | **Require Variable** - Placing this after a parameter variable requires data to be present for the rule to match |
| `//` | | **Shift Point** - Declares that only variables denoted with a $ are parsed into the $params AFTER this point in the regex |
## Examples
See maetl's article in the Links below of a detailed explanation.
`$Action/$ID/$OtherID` - Standard URL handler for a Controller. Take whatever `URLSegment` it is set to, find
the Action to match a function in the controller, and parse two optional `$param` variables that will be named `ID` and
`OtherID`.
`admin/help//$Action/$ID` - Match an url starting with `/admin/help/`, but don't include `/help/` as part of the
action (the shift point is set to start parsing variables and the appropriate controller action AFTER the `//`)
`tag/$Tag!` - Match an URL starting with `/tag/` after the controller's `URLSegment` and require it to have something
after it. If the URLSegment is **order** then `/order/tag/34` and `/order/tag/asdf` match but `/order/tag/` will not
You can use the `debug_request=1` switch from the [urlvariabletools](/reference/urlvariabletools) to see these in action.
## API Documentation
`[api:Controller]`
## Links
* `[api:Director]` class
* [execution-pipeline](/reference/execution-pipeline)
* [URL Handling in Controllers](http://maetl.net/silverstripe-url-handling) by maetl

93
docs/en/topics/css.md Normal file
View File

@ -0,0 +1,93 @@
# CSS #
## Introduction ##
SilverStripe strives to keep out of a template designer's way as much as possible -
this also extends to how you want to write your CSS.
## Adding CSS to your template ##
You are free to add `<style>` and `<link>` tags to your template (typically `themes/yourtheme/templates/Page.ss`).
SilverStripe provides a management layer for javascript and CSS files on top of that with the [Requirements](/reference/requirements) class,
by adding some simple PHP calls to your controller or template. Some files are automatically included,
depending on what functionality you are using (e.g. SilverStripe forms automatically include `sapphire/css/Form.css`).
In your controller (e.g. `mysite/code/Page.php`):
:::php
class Page_Controller {
function init() {
// either specify the css file manually
Requirements::css("mymodule/css/my.css", "screen,projection");
// or mention the css filename and SilverStripe will get the file from the current theme and add it to the template
Requirements::themedCSS('print', 'print');
}
}
Or in your template (e.g. `themes/yourtheme/templates/Page.ss`):
:::ss
<% require css(mymodule/css/my.css) %>
Management through the `Requirements` class has the advantage that modules can include their own CSS files without modifying your template.
On the other hand, you as a template developer can "block" or change certain CSS files that are included from thirdparty code.
## WYSIWYG editor: typography.css and editor.css
This stylesheet is used to "namespace" rules which just apply in a rendered site and the WYSIWYG-editor of the CMS. This
is needed to get custom styles in the editor without affecting the remaining CMS-styles.
An example of a good location to use `class="typography"` is the container element to your WYSIWYG-editor field. The
`$Content` WYSIWYG editor field already comes with SilverStripe out-of-the-box:
:::html
<!--
This is a good way, you're only applying class="typography"
to where the WYSIWYG editor is, and not the entire layout.
-->
`<div id="Main">`
`<div id="LeftContent">`
`<p>`We have a lot of content to go here.`</p>`
`</div>`
`<div id="Content" class="typography">`
$Content
`</div>`
`</div>`
The `typography.css` file should contain only styling for these elements (related to the WYSIWYG editor):
* **Headers (h1 - h6)**
* **Text (p, blockquote, pre)**
* **Lists (ul, li)**
* **CSS alignment (img.left, .left, .right etc)**
* **Tables**
* **Miscellaneous (hr etc)**
The advantages are that it's fully styled, as a default starting point which you can easily tweak. It also doesn't
affect the CMS styling at all (except for the WYSIWYG), which is what we want.
It's also separated from the rest of the layout. If you wanted to change typography only, for where you usually edit the
content you don't need to go wading through other CSS files related to the actual layout.
To get these styles working in the CMS. Eg you use a font you want in the CMS area you need to create an editor.css
file. Then with this file you can define styles for the CMS or just import the styles from typography. Unlike
`typography.css`, `editor.css` is NOT included in the front end site. So this is `themes/your_theme/css/editor.css`
:::css
/* Import the common styles from typography like link colors. */
@import 'typography.css';
/* We want the backend editor to have a bigger font as well though */
.typography * { font-size: 200% }
See [typography](/reference/typography) for more information.
## Best Practices ##
## Related ##
* [javascript](javascript)
* ["Compass" module](http://silverstripe.org/compass-module/): Allows writing CSS in SASS/LESS syntax, with better code management through mixins, includes and variables

View File

@ -0,0 +1,34 @@
# Data Types
These are the data-types that you can use when defining your data objects. They are all subclasses of `[api:DBField]`
for introducing their usage.
## Types
* `[api:Varchar]`: A variable-length string of up to 255 characters, designed to store raw text
* `[api:Text]`: A variable-length string of up to 2 megabytes, designed to store raw text
* `[api:HTMLVarchar]`: A variable-length string of up to 255 characters, designed to store HTML
* `[api:HTMLText]`: A variable-length string of up to 2 megabytes, designed to store HTML
* `[api:Enum]`: An enumeration of a set of strings
* `[api:Boolean]`: A boolean field.
* `[api:Int]`: An integer field.
* `[api:Decimal]`: A decimal number.
* `[api:Currency]`: A number with 2 decimal points of precision, designed to store currency values.
* `[api:Percentage]`: A decimal number between 0 and 1 that represents a percentage.
* `[api:Date]`: A date field
* `[api:SS_Datetime]`: A date / time field
* `[api:Time]`: A time field
## HTMLText vs. Text, and HTMLVarchar vs. Varchar
The database field types HTMLVarchar and Varchar are exactly the same in the database. However, the templating engine
knows to escape the Varchar field and not the HTMLVarchar field. So, it's important you use the right field if you
don't want to be putting $FieldType.XML everywhere.
If you're going to put HTML content into the field, please use the field type with the HTML prefix. Otherwise, you're
going to risk double-escaping your data, forgetting to escape your data, and generally creating a confusing situation.
## Usage
* See [datamodel](/topics/datamodel) for information about **database schemas** implementing these types

479
docs/en/topics/datamodel.md Normal file
View File

@ -0,0 +1,479 @@
# Datamodel
SilverStripe uses an [object-relational model](http://en.wikipedia.org/wiki/Object-relational_model) that assumes the
following connections:
* Each database-table maps to a php-class
* Each database-row maps to a php-object
* Each database-column maps to a property on a php-object
All data tables in SilverStripe are defined as subclasses of `[api:DataObject]`. Inheritance is supported in the data
model: seperate tables will be linked together, the data spread across these tables. The mapping and saving/loading
logic is handled by sapphire, you don't need to worry about writing SQL most of the time.
The advanced object-relational layer in SilverStripe is one of the main reasons for requiring PHP5. Most of its
customizations are possible through [PHP5 Object
Overloading](http://www.onlamp.com/pub/a/php/2005/06/16/overloading.html) handled in the `[api:Object]`-class.
See [database-structure](/reference/database-structure) for in-depth information on the database-schema.
## Generating the database-schema
The SilverStripe database-schema is generated automatically by visiting the URL.
`http://`<mysite>`/dev/build`
> Note: You need to be logged in as an administrator to perform this command.
## Querying Data
There are static methods available for querying data. They automatically compile the necessary SQL to query the database
so they are very helpful. In case you need to fall back to plain-jane SQL, have a look at `[api:SQLQuery]`.
:::php
$records = DataObject::get($obj, $filter, $sort, $join, $limit);
:::php
$record = DataObject::get_one($obj, $filter);
:::php
$record = DataObject::get_by_id($obj, $id);
**CAUTION: Please make sure to properly escape your SQL-snippets (see [security](/topics/security).**
## Joining
Passing a *$join* statement to DataObject::get will filter results further by the JOINs performed against the foreign
table. **It will NOT return the additionally joined data.** The returned *$records* will always be a
`[api:DataObject]`.
When using *$join* statements be sure the string is in the proper format for the respective database engine. In MySQL
the use of backticks may be necessary when referring Table Names and potentially Columns. (see [MySQL
Identifiers](http://dev.mysql.com/doc/refman/5.0/en/identifiers.html)):
:::php
// Example from the forums: http://www.silverstripe.org/archive/show/79865#post79865
// Note the use of backticks on table names
$links = DataObject::get("SiteTree",
"ShowInMenus = 1 AND ParentID = 23",
"",
"LEFT JOIN `ConsultationPaperHolder` ON `ConsultationPaperHolder`.ID = `SiteTree`.ID",
"0, 10");
## Properties
### Definition
Data is defined in the static variable $db on each class, in the format:
`<property-name>` => "data-type"
:::php
class Player extends DataObject {
static $db = array(
"FirstName" => "Varchar",
"Surname" => "Varchar",
"Description" => "Text",
"Status" => "Enum('Active, Injured, Retired')",
"Birthday" => "Date"
);
}
See [data-types](data-types) for all available types.
### Overloading
"Getters" and "Setters" are functions that help us save fields to our data objects. By default, the methods getField()
and setField() are used to set data object fields. They save to the protected array, $obj->record. We can overload the
default behaviour by making a function called "get`<fieldname>`" or "set`<fieldname>`".
:::php
class Player extends DataObject {
static $db = array(
"Status" => "Enum('Active, Injured, Retired')"
);
// access through $myPlayer->Status
function getStatus() {
// check if the Player is actually... born already!
return (!$this->obj("Birthday")->InPast()) ? "Unborn" : $this->Status;
}
### Customizing
We can create new "virtual properties" which are not actually listed in *static $db* or stored in the database-row.
Here we combined a Player's first name and surname, accessible through $myPlayer->Title.
:::php
class Player extends DataObject {
function getTitle() {
return "{$this->FirstName} {$this->Surname}";
}
// access through $myPlayer->Title = "John Doe";
// just saves data on the object, please use $myPlayer->write() to save the database-row
function setTitle($title) {
list($firstName, $surName) = explode(' ', $title);
$this->FirstName = $firstName;
$this->Surname = $surName;
}
}
**CAUTION: It is common practice to make sure that pairs of custom getters/setter deal with the same data, in a consistent
format.**
**CAUTION: Custom setters can be hard to debug: Please double check if you could transform your data in more
straight-forward logic embedded to your custom controller or form-saving.**
### Default Values
Define the default values for all the $db fields. This example sets the "Status"-column on Player to "Active" whenever a
new object is created.
:::php
class Player extends DataObject {
static $defaults = array(
"Status" => 'Active',
);
}
> Note: Alternatively you can set defaults directly in the database-schema (rather than the object-model). See
[data-types](data-types) for details.
### Casting
Properties defined in *static $db* are automatically casted to their [data-types](data-types) when used in templates.
You can also cast the return-values of your custom functions (e.g. your "virtual properties").
Calling those functions directly will still return whatever type your php-code generates,
but using the *obj()*-method or accessing through a template will cast the value accordig to the $casting-definition.
:::php
class Player extends DataObject {
static $casting = array(
"MembershipFee" => 'Currency',
);
// $myPlayer->MembershipFee() returns a float (e.g. 123.45)
// $myPlayer->obj('MembershipFee') returns a object of type Currency
// In a template: <% control MyPlayer %>MembershipFee.Nice<% end_control %> returns a casted string (e.g. "$123.45")
function getMembershipFee() {
return $this->Team()->BaseFee * $this->MembershipYears;
}
}
## Relations
Relations are built through static array definitions on a class, in the format:\\
`<relationship-name>` => `<classname>`{php}
### has_one
A 1-to-1 relation creates a database-column called "`<relationship-name>`ID", in the example below this would be "TeamID"
on the "Player"-table.
:::php
// access with $myPlayer->Team()
class Player extends DataObject {
static $has_one = array(
"Team" => "Team",
);
}
SilverStripe's `[api:SiteTree]` base-class for content-pages uses a 1-to-1 relationship to link to its
parent element in the tree:
:::php
// access with $mySiteTree->Parent()
class SiteTree extends DataObject {
static $has_one = array(
"Parent" => "SiteTree",
);
}
### has_many
Defines 1-to-many joins. A database-column named ""`<relationship-name>`ID"" will to be created in the child-class.
**CAUTION: Please specify a $has_one-relationship on the related child-class as well, in order to have the necessary
accessors available on both ends.**
:::php
// access with $myTeam->Players() or $player->Team()
class Team extends DataObject {
static $has_many = array(
"Players" => "Player",
);
}
class Player extends DataObject {
static $has_one = array(
"Team" => "Team",
);
}
To specify multiple has_manys to the same object you can use dot notation to distinguish them like below
:::php
class Person {
static $has_many = array(
"Managing" => "Company.Manager",
"Cleaning" => "Company.Cleaner",
);
}
class Company {
static $has_one = array(
"Manager" => "Person",
"Cleaner" => "Person"
);
}
Multiple $has_one relationships are okay if they aren't linking to the same object type.
:::php
/**
* THIS IS BAD
*/
class Team extends DataObject {
static $has_many = array(
"Players" => "Player",
);
}
class Player extends DataObject {
static $has_one = array(
"Team" => "Team",
"AnotherTeam" => "Team",
);
}
### many_many
Defines many-to-many joins. A new table, (this-class)_(relationship-name), will be created with a pair of ID fields.
**CAUTION: Please specify a $belongs_many_many-relationship on the related class as well, in order to have the necessary
accessors available on both ends.**
:::php
// access with $myTeam->Categories() or $myCategory->Teams()
class Team extends DataObject {
static $many_many = array(
"Categories" => "Category",
);
}
class Category extends DataObject {
static $belongs_many_many = array(
"Teams" => "Team",
);
}
### Adding relations
Inside sapphire it doesn't matter if you're editing a *has_many*- or a *many_many*-relationship. You need to get a
`[api:ComponentSet]`.
:::php
class Team extends DataObject {
// see "many_many"-description for a sample definition of class "Category"
static $many_many = array(
"Categories" => "Category",
);
/**
* @param DataObjectSet
*/
function addCategories($additionalCategories) {
$existingCategories = $this->Categories();
// method 1: Add many by iteration
foreach($additionalCategories as $category) {
$existingCategories->add($category);
}
// method 2: Add many by ID-List
$existingCategories->addMany(array(1,2,45,745));
}
}
### Custom Relation Getters
You can use the flexible datamodel to get a filtered result-list without writing any SQL. For example, this snippet gets
you the "Players"-relation on a team, but only containing active players. (See `[api:DataObject::$has_many]` for more info on
the described relations).
:::php
class Team extends DataObject {
static $has_many = array(
"Players" => "Player"
);
// can be accessed by $myTeam->ActivePlayers
function getActivePlayers() {
return $this->Players("Status='Active'");
}
}
## Data Handling
When saving data through the object model, you don't have to manually escape strings to create SQL-safe commands.
You have to make sure though that certain properties are not overwritten, e.g. *ID* or *ClassName*.
### Creation
:::php
$myPlayer = new Player();
$myPlayer->Firstname = "John"; // sets property on object
$myPlayer->write(); // writes row to database
### Update
:::php
$myPlayer = DataObject::get_by_id('Player',99);
if($myPlayer) {
$myPlayer->Firstname = "John"; // sets property on object
$myPlayer->write(); // writes row to database
}
### Batch Update
:::php
$myPlayer->update(
ArrayLib::filter_keys(
$_REQUEST,
array('Birthday', 'Firstname')
)
);
Alternatively you can use *castedUpdate()* to respect the [data-types](/topics/data-types). This is preferred to manually
casting data before saving.
:::php
$myPlayer->castedUpdate(
ArrayLib::filter_keys(
$_REQUEST,
array('Birthday', 'Firstname')
)
);
### onBeforeWrite
You can customize saving-behaviour for each DataObject, e.g. for adding security. These functions are private, obviously
it wouldn't make sense to call them externally on the object. They are triggered when calling *write()*.
Example: Disallow creation of new players if the currently logged-in player is not a team-manager.
:::php
class Player extends DataObject {
static $has_many = array(
"Teams"=>"Team"
);
function onBeforeWrite() {
// check on first write action, aka "database row creation" (ID-property is not set)
if(!$this->ID) {
$currentPlayer = Member::currentUser();
if(!$currentPlayer->IsTeamManager()) {
user_error('Player-creation not allowed', E_USER_ERROR);
exit();
}
}
// check on every write action
if(!$this->record['TeamID']) {
user_error('Cannot save player without a valid team-connection', E_USER_ERROR);
exit();
}
// CAUTION: You are required to call the parent-function, otherwise sapphire will not execute the request.
parent::onBeforeWrite();
}
}
> Note: There are no separate methods for *onBeforeCreate* and *onBeforeUpdate*. Please check for the existence of
$this->ID to toggle these two modes, as shown in the example above.
### onBeforeDelete
Triggered before executing *delete()* on an existing object.
Example: Checking for a specific [permission](/reference/permission) to delete this type of object.
It checks if a member is logged in who belongs to a group containing the permission "PLAYER_DELETE".
:::php
class Player extends DataObject {
static $has_many = array(
"Teams"=>"Team"
);
function onBeforeDelete() {
if(!Permission::check('PLAYER_DELETE')) {
Security::permissionFailure($this);
exit();
}
parent::onBeforeDelete();
}
}
### Saving data with forms
See [forms](/topics/forms).
### Saving data with custom SQL
See `[api:SQLQuery]` for custom *INSERT*, *UPDATE*, *DELETE* queries.
## Decorating DataObjects
You can add properties and methods to existing DataObjects like `[api:Member]` (a core class) without hacking core
code or subclassing.
Please see `[api:DataObjectDecorator]` for a general description, and `[api:Hierarchy]` for our most
popular examples.
## FAQ
### Whats the difference between DataObject::get() and a relation-getter?
You can work with both in pretty much the same way, but relationship-getters return a special type of collection:
A `[api:ComponentSet]` with relation-specific functionality.
:::php
$myTeam = DataObject::get_by_id('Team',$myPlayer->TeamID); // returns DataObjectSet
$myTeam->add(new Player()); // fails
$myTeam = $myPlayer->Team(); // returns Componentset
$myTeam->add(new Player()); // works

145
docs/en/topics/debugging.md Normal file
View File

@ -0,0 +1,145 @@
# Debugging
## Environment Types
Silverstripe knows three different environment-types (or "debug-levels"). Each of the levels gives you different tools
and functionality. "dev", "test" and "live". You can either configure the environment of the site in the
mysite/_config.php file or in your [environment configuration file](/topics/environment-management).
The definition of setting an environment in your mysite/_config.php looks like
:::php
Director::set_environment_type("dev");
### Dev Mode
When developing your websites, adding page types or installing modules you should run your site in devmode. In this mode
you will be able to view full error backtraces and view the development tools without logging in as admin.
To set your site to dev mode set this in your mysite/_config.php file
:::php
Director::set_environment_type("dev");
Please note **devmode should not be enabled long term on live sites for security reasons**. In devmode by outputting
backtraces of function calls a hacker can gain information about your environment (including passwords) so you should
use devmode on a public server very very carefully
### Test Mode
Test mode is designed for staging environments or other private collaboration sites before deploying a site live. You do
not need to use test mode if you do not have a staging environment or a place for testing which is on a public server)
In this mode error messages are hidden from the user and it includes BasicAuth integration if you want to password
protect the site.
To set your site to test mode set this in your mysite/_config.php file
:::php
Director::set_environment_type("test");
A common situation is to enable password protected site viewing on your test site only. You can enable that but adding
this to your mysite/_config file
:::php
if(Director::isTest()) BasicAuth::protect_entire_site();
### Live Mode
Live sites should always run in live mode. Error messages are suppressed from the user but can be optionally configured
to email the developers. This enables near real time reporting of any fatal errors or warnings on the site and can help
find any bugs users run into.
To set your site to live mode set this in your mysite/_config.php file
:::php
Director::set_environment_type("live");
### Checking Environment Types
Use the following methods:
:::php
Director::isDev();
Director::isTest();
Director::isLive();
This is useful when you have various API keys on your site and separate ones for dev / live or for configuring
environment settings based on type
:::php
if(Director::isDev()) {
// this is for dev only
}
else {
// this is for the live site
}
## Email Errors
:::php
if(Director::isLive()) Debug::send_errors_to("your@email.com");
## Customizing Error-Output
You can customize "friendly error messages" in test/live-mode by creating *assets/error-500.html*.
## URL Variable Tools
You can get lots of information on the current rendering context without writing any code or launching a debugger: Just
attach some [Debug Parameters](/reference/urlvariabletools) to your current URL to see the compiled template, or all performed
SQL-queries.
## Debugging methods
The Debug class contains a number of static methods
* *Debug::show($myVariable)*: performs a kind of *print_r($myVariable)*, but shows it in a more useful format.
* *Debug::message("Wow, that's great")*: prints a short debugging message.
* *SS_Backtrace::backtrace()* (2.3: *Debug::backtrace()*): prints a calls-stack
* *Debug::sendLiveErrorsTo("sam@silverstripe.com")*: On the live site, all errors will get sent to this address.
### Error handling
On development sites, we deal harshly with any warnings or errors: a full call-stack is shown and execution stops. This
is basically so that we deal with them promptly, since most warnings are indication that **something** is broken.
On live sites, all errors are emailed to the address specified in Debug::sendLiveErrorsTo($email)
### Debugging techniques
Since we don't have a decent interactive debugger going, we use the following debugging techniques:
* Putting *Debug::show()* and *Debug::message()* at key places in the code can help you know what's going on.
Sometimes, it helps to put this debugging information into the core modules, although, if possible, try and get what you
need by using [url querystring variables](/reference/urlvariabletools).
* Calling *user_error("breakpoint", E_USER_ERROR)* will kill execution at that point and give you a call stack to see
where you came from. Alternatively, *SS_Backtrace::backtrace()* gives you similar information without killing
execution.
* There are some special [url querystring variables](/reference/urlvariabletools) that can be helpful in seeing what's going on
with core modules, such as the templates.
* You can also use *$Debug* with *ViewableData* in templates.
#### Unit Testing
A good way to avoid writing the same test stubs and var_dump() commands over and over again is to codify them as [unit
tests](testing-guide). This way you integrate the debugging process right into your quality control, and eventually in
the development effort itself as "test-driven development".
#### Profiling
Silverstripe includes a profiling suite called [Profiler](http://www.adepteo.net/profiler/manual.html) from Carl Taylor
at Adepteo. You can use this withing your installation during development to find bottlenecks and more. You can enable
the profiler by adding `?debug_profile=1` to your URL.

View File

@ -0,0 +1,65 @@
# Directory Structure
## Introduction
The directory-structure in Silverstripe it built on "convention over configuration", so the placement of some files and
directories is meaningful to its logic.
## Core Structure
Directory | Description
--------- | -----------
`assets/` | Contains images and other files uploaded via the SilverStripe CMS. You can also place your own content inside it, and link to it from within the content area of the CMS.
`cms/` | Contains all the files that form the CMS area of your site. Its structure is similiar to the mysite/ directory, so if you find something interesting, it should be easy enough to look inside and see how it was built.
`sapphire/` | The framework that builds both your own site and as the CMS that powers it. Youll be utilizing files in this directory often, both directly and indirectly.
## Custom Code Structure
We're using `<mysite>` as an example - arbitrary directory-names are allowed, as long as they don't collide with
existing modules or the directories listes in "Core Structure".
| Directory | Description |
| --------- | ----------- |
| `<mysite>/` | This directory contains all of your code that defines your website. |
| `<mysite>/code` | PHP code for model and controller (subdirectories are optional) |
| `<mysite>/templates` | HTML [templates](templates) with *.ss-extension |
| `<mysite>/css ` | CSS files |
| `<mysite>/images ` | Images used in the HTML templates |
| `<mysite>/javascript` | Javascript and other script files
## Themes Structure
| `themes/blackcandy/` | Standard "blackcandy" theme |
| ------------------ | --------------------------- |
| `themes/blackcandy_blog/` | Theme additions for the blog module |
| `themes/yourtheme/` | The themes folder can contain more than one theme - here's your own |
See [themes](/topics/themes)
## Module Structure {#module_structure}
Modules are currently top-level folders that need to have a *_config.php*-file present.
They should follow the same conventions as posed in "Custom Site Structure"
Example Forum:
| Directory | Description |
| --------- | ----------- |
| `forum/` | This directory contains all of your code that defines your website. |
| `forum/code` | PHP code for model and controller (subdirectories are optional) |
| ... | ... |
![](_images/modules_folder.jpg)
## PHP Include Paths
Due to the way `[api:ManifestBuilder]` recursively detects php-files and includes them through PHP5's
*__autoload()*-feature, you don't need to worry about include paths. Feel free to structure your php-code into
subdirectories inside the *code*-directory.
## Best Practices
### Making /assets readonly
See [secure-development#filesystem](/topics/security#filesystem)

123
docs/en/topics/email.md Normal file
View File

@ -0,0 +1,123 @@
# Email
SilverStripe has emailing functionality using the built-in mail() function in PHP.
Features include sending plaintext- and HTML emails, sending bulk emails, subscription, handling bounced back emails.
## Configuration
Your PHP configuration needs to include the SMTP module for sending emails.
If you are not running an SMTP server together with your webserver, you might need to setup PHP with the credentials for
an external SMTP server (see [PHP documentation for mail()](http://php.net/mail)).
## Usage
### Sending combined HTML and Plaintext
By default, emails are sent in both HTML and Plaintext format.
A plaintext representation is automatically generated from the system
by stripping HTML markup, or transformining it where possible
(e.g. `<strong>text</strong>` is converted to `*text*`).
:::php
$email = new Email($from, $to, $subject, $body);
$email->send();
The default HTML template is located in `sapphire/templates/email/GenericEmail.ss`.
### Sending Plaintext only
:::php
$email = new Email($from, $to, $subject, $body);
$email->sendPlain();
### Templates
**Requirements: SilverStripe 2.3+**
* Create a SS-template file called, in this example we will use 'MyEmail.ss' inside mysite/templates/email.
* Fill this out with the body text for your email. You can use any [SS-template syntax](/topics/templates) (e.g. `<% control %>`,
`<% if %>`, $FirstName etc)
* Choose your template with **setTemplate()**
* Populate any custom data into the template before sending with **populateTemplate()**
:::php
$email = new Email($from, $to, $subject, $body);
$email->setTemplate('MyEmail');
// You can call this multiple times or bundle everything into an array, including DataSetObjects
$email->populateTemplate(Member::currentUser());
$welcomeMsg = 'Thank you for joining on '.date('Y-m-d'.'!';
$email->populateTemplate(
array(
'WelcomeMessage' => $welcomeMsg, // Accessible in template via $WelcomeMessage
)
);
$email->send();
### Subclassing
Class definition:
:::php
<?php
class MyEmail extends Email{
protected
$to = '$Email', // Be sure to encase this in single-quotes, as it is evaluated later by the template parser
$from = 'email@email.com',
$ss_template = 'MyEmail';
}
?>
Usage:
:::php
<?php
$email = new MyEmail();
$email->populateTemplate(Member::currentUser()); // This will populate the template, $to, $from etc variables if they exist
$email->send(); // Will immediately send an HTML email with appropriate plain-text content
?>
### Administrator Emails
The static function `Email::setAdminEmail()` can be called from a _config.php file to set the address that these
emails should originate from. This address is used if the `from` field is empty.
### Redirecting Emails
* Email::send_all_emails_to($address) will redirect all emails sent to the given address. Handy for testing!
* Email::cc_all_emails_to() and Email::bcc_all_emails_to() will keep the email going to its original recipients, but
add an additional receipient in the BCC/CC header. Good for monitoring system-generated correspondence on the live
systems.
:::php
if(Director::isLive()) Email::bcc_all_emails_to("client@example.com");
else Email::send_all_emails_to("developer@example.com");
### Setting Custom Headers
For email headers which do not have getters or setters (like setTo(), setFrom()) you can use **addCustomHeader($header,
$value)**
:::php
$email = new Email(...);
$email->addCustomHeader('HeaderName', 'HeaderValue');
..
See http://en.wikipedia.org/wiki/E-mail#Message_header for a list of header names.
### Newsletters
The [newsletter module](http://silverstripe.org/newsletter-module) provides a UI and logic to send batch emails.
## API Documentation
`[api:Email]`

View File

@ -0,0 +1,104 @@
# Environment management
As website developers, we noticed that we had a few problems. You may have the same problems:
* On our development laptops, we have a number of sites, but the database connection details are the same for each of
them. Why should we have to go through the installation process and re-enter them each time?
* Each of those sites needed to be in development mode when we were editing them on our laptops, but in production mode
when we deploy them to our servers. Additionally, our production host's database connection details will likely be
different than our local server.
SilverStripe comes with a solution to this: the "_ss_environment.php" file. You can put a single _ss_environment.php
file in your "projects" folder on your development box, and it will be used by each of your development sites.
## Setting up your development machine with _ss_environment.php
In this example, we assume that you are managing multiple projects as subfolders of "~/Sites/", and that you can visit
these at "http://localhost/". For example, you might have a project at "~/Sites/myproject/", and visit it at
"http://localhost/myproject/".
Create a new file, ~/Sites/_ss_environment.php. Put the following content in it, editing the values of the
"SS_DATABASE_..."" and "SS_DEFAULT_ADMIN_..." defines as appropriate.
:::php
<?php
/* What kind of environment is this: development, test, or live (ie, production)? */
define('SS_ENVIRONMENT_TYPE', 'dev/test/live');
/* Database connection */
define('SS_DATABASE_SERVER', 'localhost');
define('SS_DATABASE_USERNAME', 'root');
define('SS_DATABASE_PASSWORD', '');
/* Configure a default username and password to access the CMS on all sites in this environment. */
define('SS_DEFAULT_ADMIN_USERNAME', 'username');
define('SS_DEFAULT_ADMIN_PASSWORD', 'password');
Now, edit each of your site's configuration file, `~/Sites/(projectname)/mysite/_config.php`. Delete all mention
of `$databaseConfig` and `Director::set_dev_servers`, and instead make sure that you file starts like this.
:::php
<?php
global $project;
$project = 'mysite';
global $database;
$database = '(databasename)';
// Use _ss_environment.php file for configuration
require_once("conf/ConfigureFromEnv.php");
## How it works
The mechanism by which the "_ss_environment.php" files work is quite simple. Here's how it works:
* At the beginning of SilverStripe's execution, the _ss_environment.php file is searched for, and if it is found, it's
included. SilverStripe looks in 3 places for the file:
* The site's base folder (ie, a sibling of sapphire, jsparty, and cms)
* The parent of the base folder
* The grandparent of the base folder
* The "_ss_environment.php" file sets a number of "define()".
* "conf/ConfigureFromEnv.php" is included from within your "mysite/_config.php". This file has a number of regular
configuration commands that use those defines as their arguments. If you are curious, open up
"sapphire/conf/ConfigureFromEnv.php" and see for yourself!
### An Example
This is my '_ss_environment.php' file. I have it placed in '/var', as each of the sites are in a subfolder of '/var'.
:::php
<?php
// These three defines set the database connection details.
define('SS_DATABASE_SERVER', 'localhost');
define('SS_DATABASE_USERNAME', 'root');
define('SS_DATABASE_PASSWORD', '<password>');
// This sets a prefix, which is prepended to the $database variable. This is
// helpful mainly on shared hosts, when every database has a prefix.
define('SS_DATABASE_PREFIX', 'simon_');
// These two lines are a bit complicated. If I'm connecting to the server from
// 127.0.0.1 or MyIP and I'm using a browser with a + in the UserAgent, the site
// is put in dev mode, otherwise it is put in live mode. Most sites would only
// need to put the site in either dev or live mode, thus wont need the IP checks
if(isset($_SERVER['REMOTE_ADDR']) && ($_SERVER['REMOTE_ADDR'] == '127.0.0.1' || ($_SERVER['REMOTE_ADDR'] == '<MyIP>'
&& strpos($_SERVER['HTTP_USER_AGENT'], '+') !== false)))
define('SS_ENVIRONMENT_TYPE', 'dev');
else
define('SS_ENVIRONMENT_TYPE', 'live');
// These two defines sets a default login which, when used, will always log
// you in as an admin, even creating one if none exist.
define('SS_DEFAULT_ADMIN_USERNAME', '<email>');
define('SS_DEFAULT_ADMIN_PASSWORD', '<password>');
// This causes errors to be written to the silverstripe.log file in the same directory as this file, so /var.
// Before PHP 5.3.0, you'll need to use dirname(__FILE__) instead of __DIR__
define('SS_ERROR_LOG', __DIR__ . '/silverstripe.log');
// This is used by sake to know which directory points to which URL
global $_FILE_TO_URL_MAPPING;
$_FILE_TO_URL_MAPPING['/var/www'] = 'http://simon.geek.nz';

View File

@ -0,0 +1,105 @@
# Error Handling
SilverStripe has its own error trapping and handling support.
## Error Levels
SilverStripe recognises two basic levels of error:
* **WARNING:** Something strange has happened; the system has attempted to continue as best it can, but the developers
need to look at this. This category also include areas where a newer version of SilverStripe requires changes to the
site's customised code.
* **FATAL ERROR:** There is no way that the system can attempt to continue with the particular operation; it would be
dangerous to report success to the user.
You should use [user_error](http://www.php.net/user_error) to throw errors where appropriate. The more information we
have about what's not right in the system, the better we can make the application.
* **E_USER_WARNING:** Err on the side of over-reporting warnings. The more warnings we have, the less chance there is
of a developer leaving a bug. Throwing warnings provides a means of ensuring that developers know whow
* Deprecated functions / usage patterns
* Strange data formats
* Things that will prevent an internal function from continuing. Throw a warning and return null.
* **E_USER_ERROR:** Throwing one of these errors is going to take down the production site. So you should only throw
E_USER_ERROR if it's going to be **dangerous** or **impossible** to continue with the request.
Note that currently, the SilverStripe core doesn't follow these standards perfectly.
* Right now, **every** failed SQL statement throws a fatal error. Many 'select' queries could probably be reduced to
warnings.
* A lot of assertion checking in the system that throws errors when it should throw warnings.
## Friendly Website Errors
An HTTP 500 error will be sent when there has been a fatal error on either a test or production site. You can make this
friendlier - much like the 404 page, the error content can be edited within the CMS.
* Create a page of type `[api:ErrorPage]`
* Set the error code to 500
* Publish the page.
**HOW IT WORKS: **The publication script for ErrorPage will write the full HTML content, including the template styling,
to assets/error-500.html. The fatal error handler looks for the presence of this file, and if it exists, dumps the
content. This means that database access isn't required to provide a 500 error page.
## Filesystem Logs
### From SilverStripe
*Requires SilverStripe 2.3*
You can indicate a log file relative to the site root. The named file will have a terse log sent to it, and the full log
(an encoded file containing backtraces and things) will go to a file of a similar name, but with the suffix ".full"
added.
<mysite>/_config.php:
:::php
// log errors and warnings
SS_Log::add_writer(new SS_LogFileWriter('/my/logfile/path'), SS_Log::WARN, '<=');
// or just errors
SS_Log::add_writer(new SS_LogFileWriter('/my/logfile/path'), SS_Log::ERR);
#### Deprecated method (SS 2.3 ?)
<mysite>/_config.php:
:::php
Debug::log_errors_to("/my/logfile/path");
### From PHP
In addition to SilverStripe-integrated logging, it is adviseable to fall back to PHPs native logging functionality. A
script might terminate before it reaches the SilverStripe errorhandling, for example in the case of a fatal error.
<mysite>/_config.php:
:::php
ini_set("log_errors", "On");
ini_set("error_log", "/my/logfile/path");
## Email Logs
You can send both fatal errors and warnings in your code to a specified email-address.
<mysite>/_config.php:
:::php
// log errors and warnings
SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::WARN, '<=');
// or just errors
SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::ERR);
### Deprecated method (SS 2.3 ?)
:::php
Debug::send_errors_to("developer@example.org");
Debug::send_warnings_to("developer@example.org"); // Optional, implied by send_errors_to()

View File

@ -0,0 +1,67 @@
# Extending the CMS
CMSMain is part of the CMS. It is the controller for the content editor.
## Creating another hierarchical editor by subclassing CMSMain
Sometimes you'll want to provide an administration interface that is pretty much exactly what CMSMain provides, but it's
not appropriate to include your data in with the site content. For example, Hayden developed a hierarchical category
administrator on the Guano application.
Here's how you can do this:
## Using classes other than SiteTree in the site tree
It is possible to use to different classes in two separate site trees. In Guano for example, there is the usual site
content tree and a category tree. To change that find:
:::php
static $tree_class = 'SiteTree';
And change the string to the name of the class that will be the base class for classes visible in the site tree.
## Overloading page urls
If using a url other than admin/ for your section then you will need to change the SiteTreeHandlers to use the correct
controller.
Create the init method:
:::php
function init() {
parent::init();
Requirements::javascript('project-name/javascript/Classname_left.js');
}
Where project-name and Classname are changed as appropriate.
Create the javascript file and add the handlers:
:::php
if(typeof SiteTreeHandlers == 'undefined') SiteTreeHandlers = {};
SiteTreeHandlers.parentChanged_url = 'url/ajaxupdateparent';
SiteTreeHandlers.orderChanged_url = 'url/ajaxupdatesort';
SiteTreeHandlers.showRecord_url = 'url/show/';
SiteTreeHandlers.loadPage_url = 'url/show/';
SiteTreeHandlers.loadTree_url = 'url/getsubtree';
where url is the relative link to the page (eg 'admin/categories'). You can change the handler functions as necessary.
## Overloading EditForm
You may need to overload EditForm if your class does not use the Versioned extension.
## Overloading SiteTreeAsUL
The tree hints can sometimes cause problems when reorganising the tree, and the CMSMain::SiteTreeAsUL function uses
SiteTree explicitly. Use:
:::php
public function SiteTreeAsUL() {
// $this->generateDataTreeHints();
$this->generateTreeStylingJS();
return $this->getSiteTreeFor( $this->stat('tree_class') );
}

19
docs/en/topics/files.md Normal file
View File

@ -0,0 +1,19 @@
# Files and Images
## Files as database records
TODO Explain relationship of files to database
## Management through "Files & Images"
TODO Screenshot of admin interface
## Upload
TODO Link to Upload and FileIframeField classes
## Image Resizing
If you've changed the resize functions of your image uploaders you can run this again - and all the images will be
resampled to the new arguments for the GD functions. This also, in some cases, repairs broken image links that can
happen from time to time.

View File

@ -0,0 +1,77 @@
# Form Validation
Form validation is a combination of PHP and JavaScript
## PHP
### Introduction
Validators are implemented as an argument to the [api:Form] constructor. You create a required fields validator like
so. In this case, we're creating a [api:RequiredFields] validator - the [api:Validator] class itself is an abstract
class.
:::php
function Form() {
$form = new Form($this, 'Form',
new FieldSet(
new TextField('MyRequiredField'),
new TextField('MyOptionalField')
),
new FieldSet(
new FormAction('submit', 'Submit')
),
new RequiredFields(array('MyRequiredField'))
);
// Optional: Add a CSS class for custom styling
$form->dataFieldByName('MyRequiredField)->addExtraClass('required');
return $form;
}
### Subclassing Validator
To create your own validator, you need to subclass validator and define two methods:
* **javascript()** Should output a snippet of JavaScript that will get called to perform javascript validation.
* **php($data)** Should return true if the given data is valid, and call $this->validationError() if there were any
errors.
## JavaScript
### Default validator.js implementation
TODO Describe behaviour.js solution easily, how to disable it
Setting fieldEl.requiredErrorMsg or formEl.requiredErrorMsg will override the default error message. Both can include
the string '$FieldLabel', which will be replaced with the field's label. Otherwise, the message is "Please fill out
"$FieldLabel", it is required".
You can use Behaviour to load in the appropriate value:
:::js
Behaviour.register({
'#Form_Form' : {
requiredErrorMsg: "Please complete this question before moving on.",
}
});
### Other validation libraries
By default, SilverStripe forms with an attached Validator instance use the custom Validator.js clientside logic. It is
quite hard to customize, and might not be appropriate for all use-cases. You can disable integrated clientside
validation, and use your own (e.g. [jquery.validate](http://docs.jquery.com/Plugins/Validation)).
Disable for all forms (in `mysite/_config.php`):
:::php
Validator::set_javascript_validation_handler('none');
Disable for a specific form:
:::php
$myForm->getValidator()->setJavascriptValidationHandler('none');
## Related
* Model Validation with [api:DataObject->validate()]

279
docs/en/topics/forms.md Normal file
View File

@ -0,0 +1,279 @@
# Forms
## Introduction
Form is the base class of all forms in a sapphire application. Forms in your application can be created either by
instantiating the Form class itself, or by subclassing it.
## Instantiating a form
Creating a form is a matter of defining a method to represent that form. This method should return a form object. The
constructor takes the following arguments:
* `$controller`: This must be the controller that contains the form.
* `$name`: This must be the name of the method on that controller that is called to return the form. The first two
fields allow the form object to be re-created after submission. **It's vital that they are properly set - if you ever
have problems with form action handler not working, check that these values are correct.**
* `$fields`: A `[api:FieldSet]`s that make up the editable portion of the form.
* `$actions`: A `[api:FieldSet]`s that make up the control portion of the form - the buttons at the bottom.
* `$validator`: An optional `[api:Validator]` for more information.
Example:
:::php
function MyCustomForm() {
$fields = new FieldSet(
new EmailField("Email"),
new EncryptField("Password")
);
$actions = new FieldSet(new FormAction("login", "Log in"));
return new Form($this, "MyCustomForm", $fields, $actions);
}
## Subclassing a form
It's the reponsibility of your subclass' constructor to call
:::php
parent::__construct()
with the right parameters. You may choose to take $fields and $actions as arguments if you wish, but $controller and
$name must be passed - their values depend on where the form is instantiated.
:::php
class MyForm extends Form {
function __construct($controller, $name) {
$fields = new FieldSet(
new EmailField("Email"),
new EncryptedField("Password")
);
$actions = new FieldSet(new FormAction("login", "Log in"));
parent::__construct($controller, $name, $fields, $actions);
}
}
The real difference, however, is that you can then define your controller methods within the form class itself.
## Form Field Types
There are many classes extending `[api:FormField]`. Some examples:
* `[api:TextField]`
* `[api:EmailField]`
* `[api:NumericField]`
* `[api:DateField]`
* `[api:CheckboxField]`
* `[api:DropdownField]`
* `[api:OptionsetField]`
* `[api:CheckboxSetField]`
Full overview at [form-field-types](/reference/form-field-types)
### Using Form Fields
To get these fields automatically rendered into a form element, all you need to do is create a new instance of the
class, and add it to the fieldset of the form.
:::php
$form = new Form(
$controller = $this,
$name = "SignupForm",
$fields = new FieldSet(
new TextField(
$name = "FirstName",
$title = "First name"
),
new TextField("Surname"),
new EmailField("Email", "Email address"),
),
$actions = new FieldSet(
// List the action buttons here
new FormAction("signup", "Sign up")
),
$requiredFields = new RequiredFields(
// List the required fields here: "Email", "FirstName"
)
);
You'll note some of the fields are optional.
Implementing the more complex fields requires extra arguments.
:::php
$form = new Form(
$controller = $this,
$name = "SignupForm",
$fields = new FieldSet(
// List the your fields here
new TextField(
$name = "FirstName",
$title = "First name"
),
new TextField("Surname"),
new EmailField("Email", "Email address")
new DropdownField(
$name = "Country",
$title = "Country (if outside nz)",
$source = Geoip::getCountryDropDown(),
$value = Geoip::visitor_country()
)
), new FieldSet(
// List the action buttons here
new FormAction("signup", "Sign up")
), new RequiredFields(
// List the required fields here: "Email", "FirstName"
)
);
## Readonly
Readonly on a Form
:::php
$myForm->makeReadonly();
Readonly on a FieldSet
:::php
$myFieldSet->makeReadonly();
Readonly on a FormField
:::php
$myReadonlyField = $myField->transform(new ReadonlyTransformation());
// shortcut
$myReadonlyField = $myField->performReadonlyTransformation();
## Using a custom template
*Required Silverstripe 2.3 for some displayed functionality*
You can use a custom form template to render with, instead of *Form.ss*
It's recommended you only do this if you've got a lot of presentation text, graphics that surround the form fields. This
is better than defining those as *LiteralField* objects, as it doesn't clutter the data layer with presentation junk.
First of all, you need to create your form on it's own class, that way you can define a custom template using a `forTemplate()` method on your Form class.
:::php
class MyForm extends Form {
function __construct($controller, $name) {
$fields = new FieldSet(
new TextField('FirstName', 'First name'),
new EmailField('Email', 'Email address')
);
$actions = new FieldSet(
new FormAction('submit', 'Submit')
);
parent::__construct($controller, $name, $fields, $actions);
}
function forTemplate() {
return $this->renderWith(array(
$this->class,
'Form'
));
}
function submit($data, $form) {
// do stuff here
}
}
`forTemplate()` tells the Form class to render with a template of return value of `$this->class`, which in this case
is *MyForm*, the name of the class. If the template doesn't exist, then it falls back to using Form.ss
*MyForm.ss* should then be placed into your *templates/Includes* directory for your project. Here is an example of
basic customisation:
:::ss
<form $FormAttributes>
<% if Message %>
<p id="{$FormName}_error" class="message $MessageType">$Message</p>
<% else %>
<p id="{$FormName}_error" class="message $MessageType" style="display: none"></p>
<% end_if %>
<fieldset>
<div id="FirstName" class="field text">
<label class="left" for="$FormName_FirstName">First name</label>
$dataFieldByName(FirstName)
</div>
<div id="Email" class="field email">
<label class="left" for="$FormName_Email">Email</label>
$dataFieldByName(Email)
</div>
$dataFieldByName(SecurityID)
</fieldset>
<% if Actions %>
<div class="Actions">
<% control Actions %>$Field<% end_control %>
</div>
<% end_if %>
</form>
`$dataFieldByName(FirstName)` will return the form control contents of `Field()` for the particular field object, in
this case `TextField->Field()` or `EmailField->Field()` which returns an `<input>` element with specific markup
for the type of field. Pass in the name of the field as the first parameter, as done above, to render it into the
template.
To find more methods, have a look at the Form class, as there is a lot of different methods of customising the form
templates, for example, you could use `<% control Fields %>` instead of specifying each field manually, as we've done
above.
### Securing forms against Cross-Site Request Forgery (CSRF)
SilverStripe tries to protect users against *Cross-Site Request Forgery (CSRF)* by adding a hidden *SecurityID*
parameter to each form. See [secure-development](/topics/security) for details.
### Remove existing fields
If you want to remove certain fields from your subclass:
:::php
class MyCustomForm extends MyForm {
function __construct($controller, $name) {
parent::__construct($controller, $name);
// remove a normal field
$this->fields->removeByName('MyFieldName');
// remove a field from a tab
$this->fields->removeFieldFromTab('TabName', 'MyFieldName');
}
}
### Working with tabs
Adds a new text field called FavouriteColour next to the Content field in the CMS
:::php
$fields->addFieldToTab('Root.Content.Main', new TextField('FavouriteColour'), 'Content');
## Related
* [form-field-types](/reference/form-field-types)
* `[api:FormField]` class
* [multiform module](http://silverstripe.org/multi-form-module)
## API Documentation
`[api:Form]`

324
docs/en/topics/i18n.md Normal file
View File

@ -0,0 +1,324 @@
# i18n
## Introduction
The i18n class (short for "internationalization") in Silverstripe enables you to display templates and PHP code in
different languages based on your global settings and the preferences of your website users. This process is also known
as l10n (short for "localization").
For translating any content managed through the CMS or stored in the database, please refer to the
[translation](/topics/translation) documentation (which explains the `[api:Translatable]` extension).
This page aims to describe the low-level functionality of the i18n-API. It targets developers who:
* are involved in creating templates in different languages
* want to build their own modules with i18n capabilities
* want to make their PHP-code (e.g. form labels) i18n-ready
Please note that this project scope currently **doesn't include full support for format conversion in dates or
currencies**. Check our [roadmap](http://open.silverstripe.com/roadmap).
## Usage
### Enabling i18n
The i18n class is enabled by default.
### Setting the locale
To set the locale you just need to call `[api:i18n::set_locale()]` passing, as a parameter, the name of the locale that you want to
set.
:::php
//Example 1: setting the locale
i18n::set_locale('de_DE'); //Setting the locale to German (Germany)
i18n::set_locale('ca_AD'); //Setting to Catalan (Andorra)
Once we set a locale, all the calls to the translator function will return strings according to the set locale value, if
these translations are available. See
[unicode.org](http://unicode.org/cldr/data/diff/supplemental/languages_and_territories.html) for a complete listing of
available locales.
### Getting the locale
As you set the locale you can also get the current value, just by calling `[api:i18n::get_locale()]`.
### Declaring the content language in HTML {#declaring_the_content_language_in_html}
To let browsers know which language they're displaying a document in, you can declare a language in your template.
:::html
//'Page.ss' (HTML)
<html lang="$ContentLocale">
//'Page.ss' (XHTML)
<html lang="$ContentLocale" xml:lang="$ContentLocale" xmlns="http://www.w3.org/1999/xhtml">
Setting the '<html>' attribute is the most commonly used technique. There are other ways to specify content languages
(meta tags, HTTP headers), explained in this [w3.org article](http://www.w3.org/International/tutorials/language-decl/).
### Date and time formats
Formats can be set globally in the i18n class. These settings are currently only picked up by the CMS, you'll need
to write your own logic for any frontend output.
:::php
i18n::set_date_format('dd.MM.YYYY');
i18n::set_time_format('HH:mm');
Most localization routines in SilverStripe use the [http://framework.zend.com/manual/en/zend.date.html](Zend_Date API).
This means all formats are defined in
[http://framework.zend.com/manual/en/zend.date.constants.html#zend.date.constants.selfdefinedformats](ISO date format),
not PHP's built-in [date()](http://nz.php.net/manual/en/function.date.php).
### i18n in Form Fields
Date- and time related form fields support i18n ([api:DateField], [api:TimeField], [api:DatetimeField]).
:::php
i18n::set_locale('ca_AD');
$field = new DateField(); // will automatically set date format defaults for 'ca_AD'
$field->setLocale('de_DE'); // will not update the date formats
$field->setConfig('dateformat', 'dd.MM.YYYY'); // sets typical 'de_DE' date format
Form fields in the CMS are automatically set according to the profile settings for the logged-in user (`Member->DateFormat` and `Member->TimeFormat`).
## Adapting modules for i18n
Adapting a module to make it localizable is easy with SilverStripe. You just need to avoid hardcoding strings that are
language-dependent and use a translator function call instead.
:::php
// without i18n
echo "This is a string";
// with i18n
echo _t("Namespace.Entity","This is a string");
All strings passed through the _t() function will be collected in a separate language table (see "Collecting entities"
below), which is the starting point for translations.
### The _t() function
Here is the function prototype of this translator function
:::php
function _t(string $entity [, string $string [, int $priority [, string $context]]]) {
**$entity:** The first parameter is the identifier, and is composed by a namespace and an entity name, with a dot separating them.
The main class name (i.e. the same one that the php name file) should usually be used as the namespace. This means that
if we are coding in the file LeftAndMain.php, the namespace should be 'LeftAndMain', and therefore the complete first
parameter would be 'LeftAndMain.ENTITY'. There is an exception to this rule. If you are using the same exactly string in two different files, for example in
A.php and B.php, and the string in B.php will always be the same string that in A.php, then you can 'declare' this
string in A.php with `_t('A.ENTITY','String that is used in A and B');`{php} and then in B.php simply write:
`_t('A.ENTITY');`{php} In this way if somewhere in the future you need to modify this string, you just need to edit it
in one file (A.php). Translators will also have to translate this string just once. Entity names are by convention written in uppercase. They have to be unique within their namespace, and its purpose is
to serve as an identificator to this string, together with the namespace. Having an unique identificator for each string
allows some features like change tracking. Therefore, a meaningful name is always welcomed, although not required. And
also, that's why you shouldn't change an existing entity name in the code, unless you have a good reason to do it.
**$string:** The second parameter is the string itself. It's not mandatory if you have set this same string in another place before
(using the same class and entity). So you could write `_t('ClassName.HELLO',"Hello")` and later `_t('ClassName.HELLO')`.
In fact, if you write the string in this second case, a warning will be issued when text-collecting to alert that you
are redeclaring an entity.
**$priority:** Priority parameter is an optional parameter and it can be used to set a translation priority. If a string is widely
used, it should have a high priority (PR_HIGH), in this way translators will be able to prioritise the translation of
this strings. If a string is extremely rarely shown, use PR_LOW. You can use PR_MEDIUM as well. Leaving this field blank
will be interpretated as a "normal" priority (some less than PR_MEDIUM). Using priorities allows translators to benefit from the 80/20 rule when translating, since typically there is a reduced
set of strings that are widely displayed, and a lot of more specific strings. Therefore, in a module with a considerable
amount of strings, where partial translations can be expected, priorities will help to have translated the most
displayed strings. If a string is in a class is inheritable, it's not recommended to establish a priority (we don't know about child
behavior a priori).
### Context
Last parameter is context, it's also optional. Sometimes short phrases or words can have several translations depending
upon where they are used, and Context serves as a way to tell translators more information about the string in these
cases where translating can be difficult, due to lack of context or ambiguity.
This context param can also be used with other situations where translation may need to know more than the original
string, for example with sprintf '%' params inside the string, since you can tell translators about the meaning of this
parameters.
:::php
//Example 4: Using context to hint information about a parameter
sprintf(
_t('CMSMain.RESTORED',
"Restored '%s' successfully",
PR_MEDIUM,
'Param %s is a title'
),
$title
)
### Usage
There're two types of files in a module where you can use this _t() function: code files (under code folder) and
template files (under templates)
* In code files, in order to ask for a translated string, we have to write a normal php call to this function.
Example:
:::php
_t('LeftAndMain.HELLO','Site content',PR_HIGH,'Menu title');
_t('LeftAndMain.FILESIMAGES','Files & Images',PR_HIGH);
_t('LeftAndMain.NEWSLETTERS','Newsletters');
* In template files these calls are written slightly different to ease readibility, diminish overhead and allow a
cleaner template file. Calls can be placed anywhere, but they are preceded and followed by `<% and %>` as usual in the
SilverStripe templating language, and the first parameter is omitted (namespace in template files is always the file
itself).
Therefore, the following would be a valid use in templates:
:::ss
<a href="http://www.silverstripe.com" title="<% _t('VISIT','Visit www.silverstripe.com') %>">
Using SS templating variables in the translatable string (e.g. $Author, $Date..) is not currently supported.
### sprintf()-support
Sprintf enables us to dynamically replace parts of a translated string, e.g. by a username or a page-title.
:::php
// in PHP-file
sprintf(
_t('CMSMain.RESTORED',"Restored '%s' successfully"),
$title
)
**Caution**: In templates (*.ss)-files you can only use ONE argument for your sprintf-support, and can't use spaces
between parameters.
:::php
// in SS-template ($title must be available in the current template-scope)
<% sprintf(_t('CMSMain.RESTORED',"Restored '%s' successfully"),$title) %>
## Collecting text
To collect all the text in code and template files we have just to visit:
`http://<mysite>/dev/tasks/i18nTextCollectorTask`
Text collector will then read the files, build the master string table for each module where it finds calls to the
underscore function, and tell you about the created files and any possible entity redeclaration.
If you want to run the text collector for just one module you can use the 'module' parameter:
`http://<mysite>/dev/tasks/i18nTextCollectorTask/?module=cms`
**Note**: You'll need to install PHPUnit to run the text collector (see [testing-guide](/topics/testing)).
## Language tables in PHP
Each module can have one language table per locale. These tables are just PHP files with array notations. By convention,
the files are stored in the /lang subfolder, and are named after their locale value, e.g. "en_US.php".
Example: sapphire/lang/en_US.php (extract)
:::php
// ...
$lang['en_US']['ImageUploader']['ATTACH'] = array(
'Attach %s',
PR_MEDIUM,
'Attach image/file'
);
$lang['en_US']['FileIFrameField']['NOTEADDFILES'] = 'You can add files once you have saved for the first time.';
// ...
Translation table: sapphire/lang/de_DE.php (extract)
:::php
$lang['de_DE']['ImageUploader']['ATTACH'] = '%s anhängen';
$lang['de_DE']['FileIframeField']['NOTEADDFILES'] = 'Sie können Dateien hinzufügen sobald Sie das erste mal gespeichert haben';
## Javascript Usage
*Requires SilverStripe 2.3*
i18n in javascript works with mostly the same assumption as its PHP-equivalent.
### Requirements
Add the i18n library requirement to your code.
:::php
Requirements::javascript(SAPPHIRE_DIR . "/javascript/i18n.js");
Each language has its own language table in a separate file. To save bandwidth, only two tables are actually loaded by
the browser: The current locale, and the default locale as a fallback. The Requirements class has a special method to
determine these includes: Just point it to a directory instead of a file, and the class will figure out the includes.
:::php
Requirements::add_i18n_javascript('<my-module-dir>/javascript/lang');
### Translation Tables in JavaScript
Translation tables are automatically included as required, depending on the configured locale in *i18n::get_locale()*.
As a fallback for partially translated tables we always include the master table (en_US.js) as well.
Master Table (mymodule/javascript/lang/en_US.js)
:::js
if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
console.error('Class ss.i18n not defined');
} else {
ss.i18n.addDictionary('en_US', {
'MYMODULE.MYENTITY' : "Really delete these articles?"
});
}
Example Translation Table (mymodule/javascript/lang/de_DE.js)
:::js
ss.i18n.addDictionary('de_DE', {
'MYMODULE.MYENTITY' : "Artikel wirklich löschen?"
});
### Basic Usage
:::js
alert(ss.i18n._t('MYMODULE.MYENTITY'));
### Advanced Usage with sprintf()
:::js
// MYMODULE.MYENTITY contains "Really delete %s articles by %s authors?"
alert(ss.i18n.sprintf(
ss.i18n._t('MYMODULE.MYENTITY'),
42,
'Douglas Adams'
));
// Displays: "Really delete 42 articles by Douglas Adams?"
## Limitations
* No detecting/conversion of character encodings (we rely fully on UTF-8)
* Translation of graphics/assets
* Usage of gettext (too clumsy, too many requirements)
* Displaying multipe languages/encodings on the same page
## Links
* [http://www.i18nguy.com/](http://www.i18nguy.com/)

36
docs/en/topics/index.md Normal file
View File

@ -0,0 +1,36 @@
# Topics
This section provides an overview on how things fit together, the "conceptual glue" between APIs and features.
It is where most documentation should live, and is the natural "second step" after finishing the tutorials.
* [Access Control and Page Security](access-control): Restricting access and setting up permissions on your website
* [Command line Usage](commandline): Calling controllers via the command line interface using `sake`
* [Configuring your website](configuration): How to configure the `_config.php` file
* [Controller](controller): The intermediate layer between your templates and the data model
* [Data Types](data-types): Types that properties on `DataObject` can have (e.g. `Text` or `Date`)
* [Datamodel](datamodel): How we use an "Object-relational model" to expose database information in a useful way
* [Debugging](debugging): Tracking down errors via logs, URL parameters and profiling
* [Directory Structure](directory-structure): Whats core files, where do modules and my own project files go?
* [Emails](email): Configuring and sending emails
* [Environment management](environment-management): Sharing configuration details (e.g. database login, passwords) with multiple websites via a `_ss_environment.php` file
* [Error Handling](error-handling): Error messages and filesystem logs
* [Extending the CMS](extending-the-cms): Introduction to changing the default CMS editor
* [Files and Images](files): File and Image management in the database and how to manipulate images
* [Form Validation](form-validation): Built-in validation on form fields, and how to extend it
* [Forms](forms): Create your own form, add fields and create your own form template using the existing `Form` class
* [Internationalization (i18n)](i18n): Displaying templates and PHP code in different languages using i18n
* [Javascript](javascript): Best practices for developing with JavaScript in SilverStripe
* [Module Development](module-development): Creating a module (also known as "extension" or "plugin") to contain reuseable functionality
* [Modules](modules): Introduction, how to download and install a module (e.g. with blog or forum functionality)
* [Page Types](page-types): What is a "page type" and how do you create one?
* [Search](search): Searching for properties in the database as well as other documents
* [Security](security): How to develop secure SilverStripe applications with good code examples
* [Templates](templates): SilverStripe template syntax: Variables, loops, includes and much more
* [Testing](testing): Functional and Unit Testing with PHPUnit and SilverStripe's testing framework
* [Developing Themes](theme-development): Package templates, images and CSS to a reusable theme
* [Translation](translation): Creating content in multiple languages
* [Widgets](widgets): Small feature blocks which can be placed on a page by the CMS editor
## Feedback
If you have a topic you would like covered in these section please ask for it on our [Bug Tracker](http://open.silverstripe.org)

View File

@ -0,0 +1,647 @@
# JavaScript
**Important: Parts of this guide apply to the SilverStripe 2.4 release, particularly around the jQuery.entwine
library.**
This page describes best practices for developing with JavaScript in SilverStripe. This includes work in the CMS
interface, form widgets and custom project code. It is geared towards our "library of choice", jQuery, but most
practices can be applied to other libraries as well.
## File Inclusion
SilverStripe-driven code should use the `Requirements` class to manage clientside dependencies like CSS and JavaScript
files, rather than including `<script>` and `<link>` tags in your templates. This has the advantage that a registry
of requirements can be built up from different places outside of the main controller, for example included `FormField`
instances.
See [requirements](/reference/requirements) documentation.
## jQuery, jQuery UI and jQuery.entwine: Our libraries of choice
We predominantly use [jQuery](http://jquery.com) as our abstraction library for DOM related programming, within the
SilverStripe CMS and certain framework aspects.
For richer interactions such as drag'n'drop, and more complicated interface elements like tabs or accordions,
SilverStripe CMS uses [jQuery UI](http://ui.jquery.com) on top of jQuery.
For any custom code developed with jQuery, you have four choices to structure it: Custom jQuery Code, a jQuery Plugin, a
jQuery UI Widget, or a `jQuery.entwine` behaviour. We'll detail below where each solution is appropriate.
**Important**: Historically we have been using [PrototypeJS](http://prototypejs.com), which is now discouraged. SilverStripe as a framework doesn't impose a choice of library. It
tries to generate meaningful markup which you can alter with other JavaScript libraries as well. Only the CMS itself and
certain form widgets require jQuery to function correctly. You can also use jQuery in parallel with other libraries, see
[here](http://docs.jquery.com/Using_jQuery_with_Other_Libraries).
### Custom jQuery Code
jQuery allows you to write complex behaviour in a couple of lines of JavaScript. Smaller features which aren't likely to
be reused can be custom code without further encapsulation. For example, a button rollover effect doesn't require a full
plugin. See "[How jQuery Works](http://docs.jquery.com/How_jQuery_Works)" for a good introduction.
You should write all your custom jQuery code in a closure. This will prevent jQuery from conflicting from any prototype
code or any other framework code.
:::javascript
(function($) {
$(document).ready(function(){
// your code here.
})
})(jQuery);
### jQuery Plugins
A jQuery Plugin is essentially a method call which can act on a collection of DOM elements. It is contained within the `jQuery.fn` namespace, and attaches itself automatically to all jQuery collections. The basics for are outlined in the
official [jQuery Plugin Authoring](http://docs.jquery.com/Plugins/Authoring) documentation.
There a certain [documented patterns](http://www.learningjquery.com/2007/10/a-plugin-development-pattern) for plugin
development, most importantly:
* Claim only a single name in the jQuery namespace
* Accept an options argument to control plugin behavior
* Provide public access to default plugin settings
* Provide public access to secondary functions (as applicable)
* Keep private functions private
* Support the [Metadata Plugin](http://docs.jquery.com/Plugins/Metadata/metadata)
Example: A plugin to highlight a collection of elements with a configurable foreground and background colour
(abbreviated example from [learningjquery.com](http://www.learningjquery.com/2007/10/a-plugin-development-pattern)).
:::js
// create closure
(function($) {
// plugin definition
$.fn.hilight = function(options) {
// build main options before element iteration
var opts = $.extend({}, $.fn.hilight.defaults, options);
// iterate and reformat each matched element
return this.each(function() {
$this = $(this);
// build element specific options
var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
// update element styles
$this.css({
backgroundColor: o.background,
color: o.foreground
});
});
};
// plugin defaults
$.fn.hilight.defaults = {
foreground: "red",
background: "yellow"
};
// end of closure
})(jQuery);
Usage:
:::js
(function($) {
// Highlight all buttons with default colours
jQuery(':button').highlight();
// Highlight all buttons with green background
jQuery(':button').highlight({background: "green"});
// Set all further highlight() calls to have a green background
$.fn.hilight.defaults.background = "green";
})(jQuery);
### jQuery UI Widgets
UI Widgets are jQuery Plugins with a bit more structure, targeted towards interactive elements. They require jQuery and
the core libraries in jQuery UI, so are generally more heavyweight if jQuery UI isn't already used elsewhere.
Main advantages over simpler jQuery plugins are:
* Exposing public methods on DOM elements (incl. pseudo-private methods)
* Exposing configuration and getters/setters on DOM elements
* Constructor/Destructor hooks
* Focus management and mouse interaction
See the [official developer guide](http://jqueryui.com/docs/Developer_Guide) and other
[tutorials](http://bililite.com/blog/understanding-jquery-ui-widgets-a-tutorial/) to get started.
Example: Highlighter
:::js
(function($) {
$.widget("ui.myHighlight", {
getBlink: function () {
return this._getData('blink');
},
setBlink: function (blink) {
this._setData('blink', blink);
if(blink) this.element.wrapInner('<blink></blink>');
else this.element.html(this.element.children().html());
},
_init: function() {
// grab the default value and use it
this.element.css('background',this.options.background);
this.element.css('color',this.options.foreground);
this.setBlink(this.options.blink);
}
});
// For demonstration purposes, this is also possible with jQuery.css()
$.ui.myHighlight.getter = "getBlink";
$.ui.myHighlight.defaults = {
foreground: "red",
background: "yellow",
blink: false
};
})(jQuery);
Usage:
:::js
(function($) {
// call with default options
$(':button').myHighlight();
// call with custom options
$(':button').myHighlight({background: "green"});
// set defaults for all future instances
$.ui.myHighlight.defaults.background = "green";
// Adjust property after initialization
$(':button').myHighlight('setBlink', true);
// Get property
$(':button').myHighlight('getBlink');
})(jQuery);
### entwine: Defining Behaviour and Public APIs
jQuery.entwine is a third-party plugin, from its documentation:
"A basic desire for jQuery programming is some sort of OO or other organisational method for code. For your
consideration, we provide a library for entwineUI style programming. In entwineUI you attach behavioral code to DOM
objects. entwine extends this concept beyond what is provided by other libraries to provide a very easy to use system
with class like, ploymorphic, namespaced properties."
Use jQuery.entwine when your code is likely to be customized by others, for example for most work in the CMS interface.
It is also suited for more complex applications beyond a single-purpose plugin.
Example: Highlighter
:::js
(function($) {
$(':button').entwine({
Foreground: 'red',
Background: 'yellow',
highlight: function() {
this.css('background', this.getBackground());
this.css('color', this.getForeground());
}
});
})(jQuery);
Usage:
:::js
(function($) {
// call with default options
$(':button').entwine().highlight();
// set options for existing and new instances
$(':button').entwine().setBackground('green');
// get property
$(':button').entwine().getBackground();
})(jQuery);
This is a deliberately simple example, the strength of jQuery.entwine over simple jQuery plugins lies in its public
properties, namespacing, as well as its inheritance based on CSS selectors. Please see the [project
documentation](http://github.com/hafriedlander/jquery.entwine/tree/master) for more complete examples.
## Architecture and Best Practices
### Keep things simple
Resist the temptation to build "cathedrals" of complex interrelated components. In general, you can get a lot done in
jQuery with a few lines of code. Your jQuery code will normally end up as a series of event handlers applied with `jQuery.live()` or jQuery.entwine, rather than a complex object graph.
### Don't claim global properties
Global properties are evil. They are accesible by other scripts, might be overwritten or mis-used. A popular case is the `$` shortcut in different libraries: in PrototypeJS it stands for `document.getElementByID()`, in jQuery for `jQuery()`.
:::js
// you can't rely on '$' being defined outside of the closure
(function($) {
var myPrivateVar; // only available inside the closure
// inside here you can use the 'jQuery' object as '$'
})(jQuery);
You can run `[jQuery.noConflict()](http://docs.jquery.com/Core/jQuery.noConflict)` to avoid namespace clashes.
NoConflict mode is enabled by default in the SilverStripe CMS javascript.
### Initialize at document.ready
You have to ensure that DOM elements you want to act on are loaded before using them. jQuery provides a wrapper around
the `window.onload` and `document.ready` events.
:::js
// DOM elements might not be available here
$(document).ready(function() {
// The DOM is fully loaded here
});
See [jQuery FAQ: Launching Code on Document
Ready](http://docs.jquery.com/How_jQuery_Works#Launching_Code_on_Document_Ready).
### Bind events "live"
jQuery supports automatically reapplying event handlers when new DOM elements get inserted, mostly through Ajax calls.
This "live binding" saves you from reapplying this step manually.
Caution: Only applies to certain events, see the [jQuery.live() documentation](http://docs.jquery.com/Events/live).
Example: Add a 'loading' classname to all pressed buttons
:::js
// manual binding, only applies to existing elements
$('input[[type=submit]]').bind('click', function() {
$(this).addClass('loading');
});
// live binding, applies to any inserted elements as well
$('input[[type=submit]]').live(function() {
$(this).addClass('loading');
});
See [jQuery FAQ: Why do my events stop working after an AJAX
request](http://docs.jquery.com/Frequently_Asked_Questions#Why_do_my_events_stop_working_after_an_AJAX_request.3F).
### Assume Element Collections
jQuery is based around collections of DOM elements, the library functions typically handle multiple elements (where it
makes sense). Encapsulate your code by nesting your jQuery commands inside a `jQuery().each()` call.
Example: ComplexTableField implements a paginated table with a pop-up for displaying
:::js
$('div.ComplexTableField').each(function() {
// This is the over code for the tr elements inside a ComplexTableField.
$(this).find('tr').hover(
// ...
);
});
### Use plain HTML and jQuery.data() to store data
The DOM can make javascript configuration and state-keeping a lot easier, without having to resort to javascript
properties and complex object graphs.
Example: Simple form change tracking to prevent submission of unchanged data
Through CSS properties
:::js
$('form :input').bind('change', function(e) {
$(this.form).addClass('isChanged');
});
$('form').bind('submit', function(e) {
if($(this).hasClass('isChanged')) return false;
});
Through jQuery.data()
:::js
$('form :input').bind('change', function(e) {
$(this.form).data('isChanged', true);
});
$('form').bind('submit', function(e) {
alert($(this).data('isChanged'));
if($(this).data('isChanged')) return false;
});
See [interactive example on jsbin.com](http://jsbin.com/opuva)
You can also use the [jQuery.metadata Plugin](http://docs.jquery.com/Plugins/Metadata/metadata) to serialize data into
properties of DOM elements. This is useful if you want to encode element-specific data in markup, for example when
rendering a form element through the SilverStripe templating engine.
Example: Restricted numeric value field
:::ss
<input type="text" class="restricted-text {min:4,max:10}" />
:::js
$('.restricted-text').bind('change', function(e) {
if(
e.target.value < $(this).metadata().min
|| e.target.value > $(this).metadata().max
) {
alert('Invalid value');
return false;
}
});
See [interactive example on jsbin.com](http://jsbin.com/axafa)
### Return HTML/JSON and HTTPResponse class for AJAX responses
Ajax responses will sometimes need to update existing DOM elements, for example refresh a set of search results.
Returning plain HTML is generally a good default behaviour, as it allows you to keep template rendering in one place (in
SilverStripe PHP code), and is easy to deal with in JavaScript.
If you need to process or inspect returned data, consider extracting it from the loaded HTML instead (through id/class
attributes, or the jQuery.metadata plugin). For returning status messages, please use the HTTP status-codes.
Only return evaluated JavaScript snippets if unavoidable. Most of the time you can just pass data around, and let the
clientside react to changes appropriately without telling it directly through JavaScript in AJAX responses. Don't use
the `[api:Form]` SilverStripe class, which is built solely around
this inflexible concept.
Example: Autocomplete input field loading page matches through AJAX
Template:
:::ss
<ul>
<% control Results %>
<li id="Result-$ID">$Title</li>
<% end_control %>
</ul>
PHP:
:::php
class MyController {
function autocomplete($request) {
$SQL_title = Convert::raw2sql($request->getVar('title'));
$results = DataObject::get("Page", "Title = '$SQL_title'");
if(!$results) return new HTTPResponse("Not found", 404);
// Use HTTPResponse to pass custom status messages
$this->response->setStatusCode(200, "Found " . $results->Count() . " elements");
// render all results with a custom template
$vd = new ViewableData();
return $vd->customise(array(
"Results" => $results
))->renderWith('AutoComplete');
}
}
HTML
:::ss
<form action"#">
<div class="autocomplete {url:'MyController/autocomplete'}">
<input type="text" name="title" />
<div class="results" style="display: none;">
</div>
<input type="submit" value="action_autocomplete" />
</form>
JavaScript:
:::js
$('.autocomplete input').live('change', function() {
var resultsEl = $(this).siblings('.results');
resultsEl.load(
// get form action, using the jQuery.metadata plugin
$(this).parent().metadata().url,
// submit all form values
$(this.form).serialize(),
// callback after data is loaded
function(data, status) {
resultsEl.show();
// get all record IDs from the new HTML
var ids = jQuery('.results').find('li').map(function() {
return $(this).attr('id').replace(/Record\-/,'');
});
}
);
});
Although they are the minority of cases, there are times when a simple HTML fragment isn't enough. For example, if you
have server side code that needs to trigger the update of a couple of elements in the CMS left-hand tree, it would be
inefficient to send back the HTML of entire tree. SilverStripe can serialize to and from JSON (see the `[api:Convert]` class), and jQuery deals very well with it through
[jQuery.getJSON()](http://docs.jquery.com/Ajax/jQuery.getJSON#urldatacallback), as long as the HTTP content-type is
properly set.
### Use events and observation to link components together
The philosophy behind this javascript guide is **component driven development**: your javascript should be structured as
a set of components that communicate. Event handlers are a great way of getting components to community, as long as
two-way communication isn't required. Set up a number of custom event names that your component will trigger. List
them in the component documentation comment.
jQuery can bind to DOM events and trigger them through custom code. It can also
[trigger custom events](http://docs.jquery.com/Events/trigger), and supports [namespaced
events](http://docs.jquery.com/Namespaced_Events).
Example: Trigger custom 'validationfailed' event on form submission for each empty element
:::js
$('form').bind('submit', function(e) {
// $(this) refers to form
$(this).find(':input').each(function() {
// $(this) in here refers to input field
if(!$(this).val()) $(this).trigger('validationfailed');
});
return false;
});
// listen to custom event on each <input> field
$('form :input').bind('validationfailed',function(e) {
// $(this) refers to input field
alert($(this).attr('name'));
});
See [interactive example on jsbin.com](http://jsbin.com/ipeca).
Don't use event handlers in the following situations:
* If two-way communication is required, for example, calling an method in another component, which returns data that
you then use. Event handlers can't have return values.
* If specific execution order is required. Event handlers are executed in parallel, which makes it difficult to know
the exact order in which code in different threads will execute. If the execution order is likely to cause problems, it
is better to use a code structure that is executed sequentially. An example might be two events modifying the same piece
of the DOM.
### Use callbacks to allow customizations
Callbacks are similar to events in that other components can ask your component to execute a piece of code. The
advantage is that they lack the two problems listed in bullets just above. The disadvantage of callbacks is that you
need to define an custom API for configuring the callbacks; whereas, event observation is a jQuery provided API that
leaves components very loosely coupled.
### Use jQuery.entwine to define APIs as necessary
By default, most of your JavaScript methods will be hidden in closures like a jQuery plugin, and are not accessible from
the outside. As a best practice, each jQuery plugin should only expose one method to initialize and configure it. If you
need more public methods, consider using either a jQuery UI Widget, or define your behaviour as jQuery.entwine rules
(see above).
### Write Documentation
Documentation in JavaScript usually resembles the JavaDoc standard, although there is no agreed standard. Due to the
flexibility of the language it can be hard to generate automated documentation, particularly with the predominant usage
of closure constructs in jQuery and jQuery.entwine.
To generate documentation for SilverStripe code, use [JSDoc toolkit](http://code.google.com/p/jsdoc-toolkit/) (see
[reference of supported tags](http://code.google.com/p/jsdoc-toolkit/wiki/TagReference)). For more class-oriented
JavaScript, take a look at the [jsdoc cookbook](http://code.google.com/p/jsdoc-toolkit/wiki/CookBook). The `@lends`
and `@borrows` properties are particularly useful for documenting jQuery-style code.
JSDoc-toolkit is a commandline utility, see [usage](http://code.google.com/p/jsdoc-toolkit/wiki/CommandlineOptions).
Example: jQuery.entwine
:::js
/**
* Available Custom Events:
* <ul>
* <li>ajaxsubmit</li>
* <li>validate</li>
* <li>loadnewpage</li>
* </ul>
*
* @class Main LeftAndMain interface with some control panel and an edit form.
* @name ss.LeftAndMain
*/
$('.LeftAndMain').entwine('ss', function($){
return/** @lends ss.LeftAndMain */ {
/**
* Reference to some property
* @type Number
*/
MyProperty: 123,
/**
* Renders the provided data into an unordered list.
*
* @param {Object} data
* @param {String} status
* @return {String} HTML unordered list
*/
publicMethod: function(data, status) {
return '<ul>'
+ /...
+ '</ul>';
},
/**
* Won't show in documentation, but still worth documenting.
*
* @return {String} Something else.
*/
_privateMethod: function() {
// ...
}
};
]]);
### Unit Testing
It is important to verify that your code actually does what it says, and the best way to ensure this are **automated
tests**. For jQuery, we use two different tools with different uses: **unit testing** with
[QUnit](http://docs.jquery.com/QUnit) (also used by the jQuery team for the core libraries), and **behaviour driven
testing** with [JSpec](http://visionmedia.github.com/jspec/). There are overlaps between the two solutions, if in doubt
start with JSpec, as it provides a much more powerful testing framework.
Example: QUnit test (from [jquery.com](http://docs.jquery.com/QUnit#Using_QUnit)):
:::js
test("a basic test example", function() {
ok( true, "this test is fine" );
var value = "hello";
equals( "hello", value, "We expect value to be hello" );
});
Example: JSpec Shopping cart test (from [visionmedia.github.com](http://visionmedia.github.com/jspec/))
describe 'ShoppingCart'
before_each
cart = new ShoppingCart
end
describe 'addProduct'
it 'should add a product'
cart.addProduct('cookie')
cart.addProduct('icecream')
cart.should.have 2, 'products'
end
end
end
### Javascript in the CMS {#javascript-cms}
The CMS has a number of Observer-pattern hooks you can access: (The elements which are notified are listed in brackets.)
* Close -- when 'folder' in SiteTree is closed. (form?)
* BeforeSave -- after user clicks 'Save', before AJAX save-request (#Form_EditForm)
* PageLoaded -- after new SiteTree page is loaded. (#Form_EditForm)
* PageSaved -- after AJAX save-request is successful (#Form_EditForm)
* SelectionChanged -- when new item is chosen from SiteTree (#sitetree)
Here's an example of hooking the 'PageLoaded' and 'BeforeSave' methods:
:::javascript
/*
* Observe the SiteTree 'PageLoaded' event, called whenever a SiteTree page is
* opened or reloaded in the CMS.
*
* Also observe 'BeforeSave' which is called when the Save button is pressed,
* before the AJAX call to save the page is sent.
*/
Behaviour.register({
'#Form_EditForm' : {
initialize : function() {
this.observeMethod('PageLoaded', this.pageLoaded);
this.observeMethod('BeforeSave', this.beforeSave);
this.pageLoaded(); // call pageload initially too.
},
pageLoaded : function() {
alert("You loaded a page");
},
beforeSave: function() {
alert("You clicked save");
}
} // #Form_EditForm
});
See ['onload' javascript in the CMS](/reference/leftandmain#onload-javascript)
### Break the rules!
The guidelines are not intended to be hard and fast rules; they cover the most common cases but not everything. Don't be
afraid to experiment with using other approaches.
## Related
* [css](css)
* [Unobtrusive Javascript](http://www.onlinetools.org/articles/unobtrusivejavascript/chapter1.html)
* [Quirksmode: In-depth Javascript Resources](http://www.quirksmode.org/resources.html)
* [behaviour.js documentation](http://open.silverstripe.org/browser/modules/sapphire/branches/2.4/thirdparty/behaviour/README.md)

View File

@ -0,0 +1,55 @@
# Module Development
## Introduction
Creating a module is a good way to re-use abstract code and templates across multiple projects. SilverStripe already has
certain modules included, for example "sapphire" and "cms". These three modules are the core functionality and
templating for any initial installation. If you're wanting to add generic functionality that isn't specific to your
project, like a forum, an ecommerce package or a blog you can do it like this;
1. Create another directory at the root level (same level as "sapphire" and "cms")
2. You must create an _config.php inside your module directory, else SilverStripe will not include it
3. Inside your module directory, follow our [directory structure guidelines](/topics/directory-structure#module_structure)
## Tips
Try and keep your module as generic as possible - for example if you're making a forum module, your members section
shouldn't contain fields like 'Games You Play' or 'Your LiveJournal Name' - if people want to add these fields they can
sub-class your class, or decorate the fields on to it.
If you're using Requirements to include generic support files for your project like CSS or Javascript, and want to
override these files to be more specific in your project, the following code is an example of how to do so using the
init() function on your module controller classes:
:::php
class Forum_Controller extends Page_Controller {
function init() {
if(Director::fileExists(project() . "/css/forum.css")) {
Requirements::css(project() . "/css/forum.css");
}else{
Requirements::css("forum/css/forum.css");
}
parent::init();
}
}
This will use your_project/css/forum.css if it exists, otherwise it falls back to using forum/css/forum.css.
## Publication
If you wish to submit your module to our public directory, you take responsibility for a certain level of code quality,
adherence to conventions, writing documentation, and releasing updates. See [contributing](/misc/contributing).
## Reference
**How To:**
* [Add a link to your module in the main SilverStripe Admin Menu](/reference/leftandmain)
**
Useful Links:**
* [Debugging methods](/topics/debugging)
* [URL Variable Tools](/reference/urlvariabletools) - Lists a number of “page options” , “rendering tools” or “special
URL variables” that you can use to debug your sapphire applications

88
docs/en/topics/modules.md Normal file
View File

@ -0,0 +1,88 @@
# Modules
Sapphire is designed to be a modular application system - even the CMS is simply a module that plugs into it.
A module is, quite simply, a collection of classes, templates, and other resources that is loaded into a top-level
directory. In a default SilverStripe download, even resources in 'sapphire' and 'mysite' are treated in exactly the
same as every other module.
Sapphire's `[api:ManifestBuilder]` will find any class, css or template files anywhere under the site's main
directory. The _config.php file in the module directory can be used to define director rules, calls to
Object::useCustomClass(), and the like. So, by unpacking a module into site's main directory and viewing the site with
?flush=1 on the end of the URL, all the module's new behaviour will be incorporated to your site:
* You can create subclasses of base classes such as SiteTree to extend behaviour.
* You can use Object::useCustomClass() to replace a built in class with a class of your own.
* You can use [a decorator](api:DataObjectDecorator) to extend or alter the behaviour of a built-in class without replacing
it.
* You can provide additional director rules to define your own controller for particular URLs.
For more information on creating modules, see [module-development](/topics/module-development).
## Types of Modules
Because of the broad definition of modules, they can be created for a number of purposes:
* **Applications:** A module can define a standalone application that may work out of the box, or may get customisation
from your mysite folder. "cms" is an example of this.
* **CMS Add-ons:** A module can define an extension to the CMS, usually by defining special page types with their own
templates and behaviour. "blog", "ecommerce", "forum", and "gallery" are examples of this.
* **Blog Widgets:** A module can provide 1 or more blog-widget classes. See [widgets](/topics/widgets) for more information.
* **Developer Tools:** A module can provide a number of classes or resource files that do nothing by themselves, but
instead make it easier for developers to build other applications.
## Finding Modules
* [Official module list on silverstripe.org](http://silverstripe.org/modules)
* [Subversion repository on open.silverstripe.org](http://open.silverstripe.org/browser/modules)
## Installation
Modules should exist in the root folder of your SilverStripe. The root folder being the one that contains the
*sapphire*, *cms* and other folders.
The following article explains the generic installation of a module. Individual modules have their own requirements such
as creating folders or configuring API keys. For information about installing or configuring a specific module see the
modules *INSTALL* (or *README*) file. Modules should adhere to the [directory-structure](/topics/directory-structure)
guidelines.
### Download
To install a module you need to download the tar.gz file from the [modules page](http://www.silverstripe.org/modules) and extract this tar.gz to the root folder mentioned
above.
Note some times the folders extracted from the tar.gz contain the version number or some other folders. You need to make
sure the folder name is the correct name of the module.
### Subversion
#### Option 1: Checkout
cd ~/Sites/yourSilverStripeProject/
svn co http://svn.silverstripe.com/open/modules/modulename/trunk modulename/
Note: Some modules are stored in subfolders. If you want to use a module that is in a subfolder, such as widgets, put
an _ between the subfolder name and the module name, like this:
cd /your/website/root
svn co http://svn.silverstripe.com/open/modules/widgets/twitter/trunk widgets_twitter
#### Option 2: Add to svn:externals
cd ~/Sites/yourSilverStripeProject/
svn propedit svn:externals .
In the editor add the following line (lines if you want multiple)
modulename/ http://svn.silverstripe.com/open/modules/modulename/trunk
Exit the editor and then run
svn up

View File

@ -0,0 +1,160 @@
# Page Types
## Introduction
Page Types are the basic building blocks of any SilverStripe website. A page type can define:
* The template or templates that are used to display content
* What fields are available to edit in the CMS
* Behaviour specific to a page type for example a contact form on the Contact Us page that sends an email
when the form is submitted
All the pages on the base installation are of the page type "Page". See
[tutorial:2-extending-a-basic-site](/tutorials/2-extending-a-basic-site) for a good introduction to page-types.
Each page type on your website is a sub-class of the SiteTree class. Usually, youll define a class called Page
and use this template to lay out the basic design elements that dont change. Take a look at mysite/templates/Page.ss.
It contains standard HTML markup, with some differences. Well go over these later, but for now, you can see that this
file only generates some of the content it sets up the `<html>` tags, deals with the `<head>` section, creates the
first-level navigation, and then closes it all off again. See $Layout? Thats what is doing most of the work when you
visit a page. Now take a look at mysite/templates/Layout/Page.ss. This as you can see has a lot more markup in it
its what is included into $Layout when the Page page type is rendered. Similarly,
mysite/templates/Layout/HomePage.ss would be rendered into $Layout when the HomePage page type is selected for the
current page youre viewing.
Why do we sub-class Page for everything? The easiest way to explain this is to use the example of a search form. If we
create a search form on the Page class, then any other sub-class can also use it in their templates. This saves us
re-defining commonly used forms or controls in every class we use.
![](_images/pagetype-inheritance.png)
Each page type is represented by two classes: a data object and a controller. In the diagrams above and below, the data
objects are black and the controllers are blue. The page controllers are only used when the page type is actually
visited on the website. In our example above, the search form would become a method on the Page_Controller class.
Any methods put on the data object will be available wherever we use this page. For example, we put any customizations
we want to do to the CMS for this page type in here.
![](_images/controllers-and-dataobjects.png)
Page types are created using PHP classes. If youre not sure about how these work, [click here for a gentler
introduction to PHP classes](http://www-128.ibm.com/developerworks/opensource/library/os-phpobj/).
We put the Page class into a file called Page.php inside mysite/code. We also put Page_Controller in here. Any other
classes that are based on Page for example, the class Page_AnythingElse will also go into Page.php. Likewise, the
StaffPage_Image class will go into StaffPage.php.
## Adding database-fields
Adding database fields is a simple process. You define them in an array of the static variable `$db`, this array is
added on the object class. For example, Page or StaffPage. Every time you run db/build to recompile the manifest, it
checks if any new entries are added to the `$db` array and adds any fields to the database that are missing.
For example, you may want an additional field on a StaffPage class which extends Page, called Author. Author is a
standard text field, and can be [casted](/topics/datamodel) as a variable character object in php (VARCHAR in SQL). In the
following example, our Author field is casted as a variable character object with maximum characters of 50. This is
especially useful if you know how long your source data needs to be.
:::php
class StaffPage extends Page {
static $db = array(
'Author' => 'Varchar(50)'
);
}
class StaffPage_Controller extends Page_Controller {
}
See [datamodel](/topics/datamodel) for a more detailed explanation on adding database fields, and how the SilverStripe data
model works.
## Adding formfields and tabs
See [form](/topics/forms) and [tutorial:2-extending-a-basic-site](/tutorials/2-extending-a-basic-site)
## Removing inherited form fields and tabs
### removeFieldFromTab()
Overloading `getCMSFields()` you can call `removeFieldFromTab()` on a `FieldSet` object. For example, if you don't
want the MenuTitle field to show on your page, which is inherited from SiteTree.
:::php
class StaffPage extends Page {
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->removeFieldFromTab('Root.Content.Main', 'MenuTitle');
return $fields;
}
}
class StaffPage_Controller extends Page_Controller {
}
### removeByName()
`removeByName()` for normal form fields is useful for breaking inheritance where you know a field in your form isn't
required on a certain page-type.
:::php
class MyForm extends Form {
function __construct($controller, $name) {
// add a default FieldSet of form fields
$member = singleton('Member');
$fields = $member->formFields();
// We don't want the Country field from our default set of fields, so we remove it.
$fields->removeByName('Country');
$actions = new FieldSet(
new FormAction('submit', 'Submit')
);
parent::__construct($controller, $name, $fields, $actions);
}
}
This will also work if you want to remove a whole tab e.g. $fields->removeByName('Metadata'); will remove the whole
Metadata tab.
For more information on forms, see [form](/topics/forms), [tutorial:2-extending-a-basic-site](/tutorials/2-extending-a-basic-site)
and [tutorial:3-forms](/tutorials/3-forms).
## Creating a new page:
:::php
$page = new Page();
$page->ParentID = 18; //if you want it to be a child of a certain other page...
$page->Title = "Crazy page";
$page->MetaTitle = "madness";
$page->PageTitle = "Funny";
$page->writeToStage('Stage');
$page->publish('Stage', 'Live');
## Updating a page:
:::php
$page = DataObject::get_one("Page", "ParentID = 18");
$page->Title = "More Serious";
$page->writeToStage('Stage');
$page->Publish('Stage', 'Live');
$page->Status = "Published";
## Deleting pages:
:::php
$pageID = $page->ID;
$stageRecord = Versioned::get_one_by_stage('SiteTree', 'Stage', "SiteTree.ID = $pageID");
if ($stageRecord) $stageRecord->delete();
$liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', "SiteTree_Live.ID = $pageID");
if ($liveRecord) $liveRecord->delete();

26
docs/en/topics/search.md Normal file
View File

@ -0,0 +1,26 @@
# Search
## Searching for Pages (and Files)
Fulltext search for page content (and other attributes like "Title" or "MetaTags") can be easily added to SilverStripe.
See [Tutorial: Site Search](/tutorials/4-site-search) for details.
## Searching for DataObjects
The [api:SearchContext] class provides a good base implementation that you can hook into your own controllers.
A working implementation of searchable DataObjects can be seen in the [api:ModelAdmin] class.
## Searching for Documents
SilverStripe does not have a built-in method to search through file content (e.g. in PDF or DOC format).
You can either extract any textual file content into the `[File](api:File)->Content` property, or use a
dedicated search service like the [sphinx module](http://silverstripe.org/sphinx-module).
## Related
* `[api:ModelAdmin]`
* `[api:RestfulServer]`
* [Tutorial: Site Search](/tutorials/4-site-search)
* [genericviews module](http://silverstripe.org/generic-views-module)
* [sphinx module](http://silverstripe.org/sphinx-module)
* [lucene module](http://silverstripe.org/lucene-module)

360
docs/en/topics/security.md Normal file
View File

@ -0,0 +1,360 @@
# Security
## Introduction
This page details notes on how to ensure that we develop secure SilverStripe applications. See [security](/topics/security) for
the Silverstripe-class as a starting-point for most security-related functionality.
See our [contributing guidelines](/misc/contributing#reporting-security-issues) on how
to report security issues.
## SQL Injection
The [coding-conventions](/misc/coding-conventions) help guard against SQL injection attacks but still require developer
dilligence: ensure that any variable you insert into a filter / sort / join clause has been escaped.
See [http://shiflett.org/articles/sql-injection](http://shiflett.org/articles/sql-injection).
### Automatic escaping
Silverstripe automatically runs [addslashes()](http://php.net/addslashes) in DataObject::write() wherever possible. Data
is escaped when saving back to the database, not when writing to object-properties.
* DataObject::get_by_id()
* DataObject::update()
* DataObject::castedUpdate()
* DataObject->Property = 'val', DataObject->setField('Property','val')
* DataObject::write()
* Form->saveInto()
* FormField->saveInto()
* DBField->saveInto()
Note: It is NOT good practice to "be sure" and convert the data passed to the functions below manually. This might
result in *double escaping* and alters the actually saved data (e.g. by adding slashes to your content).
### Manual escaping
As a rule of thumb, whenever you're creating raw queries (or just chunks of SQL), you need to take care of escaping
yourself. See [coding-conventions](/misc/coding-conventions) and [datamodel](/topics/datamodel) for ways to cast and convert
your data.
* SQLQuery
* DataObject::buildSQL()
* DB::query()
* Director::urlParams()
* Controller->requestParams, Controller->urlParams
* GET/POST data passed to a Form-method
Example:
:::php
class MyForm extends Form {
function save($RAW_data, $form) {
$SQL_data = Convert::raw2sql($RAW_data); // works recursively on an array
$objs = DataObject::get('Player', "Name = '{$SQL_data[name]}'");
// ...
}
}
* FormField->Value()
* URLParams passed to a Controller-method
Example:
:::php
class MyController extends Controller {
function myurlaction($RAW_urlParams) {
$SQL_urlParams = Convert::raw2sql($RAW_urlParams); // works recursively on an array
$objs = DataObject::get('Player', "Name = '{$SQL_data[OtherID]}'");
// ...
}
}
As a rule of thumb, you should escape your data **as close to querying as possible**.
This means if you've got a chain of functions passing data through, escaping should happen at the end of the chain.
:::php
class MyController extends Controller {
/**
* @param array $RAW_data All names in an indexed array (not SQL-safe)
*/
function saveAllNames($RAW_data) {
// $SQL_data = Convert::raw2sql($RAW_data); // premature escaping
foreach($RAW_data as $item) $this->saveName($item);
}
function saveName($RAW_name) {
$SQL_name = Convert::raw2sql($RAW_name);
DB::query("UPDATE Player SET Name = '{$SQL_name}'");
}
}
This might not be applicable in all cases - especially if you are building an API thats likely to be customized. If
you're passing unescaped data, make sure to be explicit about it by writing *phpdoc*-documentation and *prefixing* your
variables ($RAW_data instead of $data).
## XSS (Cross-Site-Scripting)
SilverStripe helps you guard any output against clientside attacks initiated by malicious user input, commonly known as
XSS (Cross-Site-Scripting). With some basic guidelines, you can ensure your output is safe for a specific use case (e.g.
displaying a blog post in HTML from a trusted author, or escaping a search parameter from an untrusted visitor before
redisplaying it).
Note: SilverStripe templates do not remove tags, please use [strip_tags()](http://php.net/strip_tags) for this purpose
or [sanitize](http://htmlpurifier.org/) it correctly.
See [http://shiflett.org/articles/foiling-cross-site-attacks](http://shiflett.org/articles/foiling-cross-site-attacks)
for in-depth information about "Cross-Site-Scripting".
### Escaping model properties
`[api:SSViewer]` (the SilverStripe template engine) automatically takes care of escaping HTML tags from specific
object-properties by [casting](/topics/datamodel#casting) its string value into a `[api:DBField]` object.
PHP:
:::php
class MyObject extends DataObject {
public static $db = array(
'MyEscapedValue' => 'Text', // Example value: <b>not bold</b>
'MyUnescapedValue' => 'HTMLText' // Example value: <b>bold</b>
);
}
Template:
:::php
<ul>
<li>$MyEscapedValue</li> // output: &lt;b&gt;not bold&lt;b&gt;
<li>$MyUnescapedValue</li> // output: <b>bold</b>
</ul>
The example below assumes that data wasn't properly filtered when saving to the database, but are escaped before
outputting through SSViewer.
### Overriding default escaping in templates
You can force escaping on a casted value/object by using an [escape type](/topics/datamodel) method in your template, e.g.
"XML" or "ATT".
Template (see above):
:::php
<ul>
// output: <a href="#" title="foo &amp; &#quot;bar&quot;">foo &amp; "bar"</a>
<li><a href="#" title="$Title.ATT">$Title</a></li>
<li>$MyEscapedValue</li> // output: &lt;b&gt;not bold&lt;b&gt;
<li>$MyUnescapedValue</li> // output: <b>bold</b>
<li>$MyUnescapedValue.XML</li> // output: &lt;b&gt;bold&lt;b&gt;
</ul>
### Escaping custom attributes and getters
Every object attribute or getter method used for template purposes should have its escape type defined through the
static *$casting* array. Caution: Casting only applies when using values in a template, not in PHP.
PHP:
:::php
class MyObject extends DataObject {
public $Title = '<b>not bold</b>'; // will be escaped due to Text casting
$casting = array(
"Title" => "Text", // forcing a casting
'TitleWithHTMLSuffix' => 'HTMLText' // optional, as HTMLText is the default casting
);
function TitleWithHTMLSuffix($suffix) {
// $this->Title is not casted in PHP
return $this->Title . '<small>(' . $suffix. ')</small>';
}
}
Template:
:::php
<ul>
<li>$Title</li> // output: &lt;b&gt;not bold&lt;b&gt;
<li>$Title.RAW</li> // output: <b>not bold</b>
<li>$TitleWithHTMLSuffix</li> // output: <b>not bold</b>: <small>(...)</small>
</ul>
Note: Avoid generating HTML by string concatenation in PHP wherever possible to minimize risk and separate your
presentation from business logic.
### Manual escaping in PHP
When using *customise()* or *renderWith()* calls in your controller, or otherwise forcing a custom context for your
template, you'll need to take care of casting and escaping yourself in PHP.
The `[api:Convert]` class has utilities for this, mainly *Convert::raw2xml()* and *Convert::raw2att()* (which is
also used by *XML* and *ATT* in template code).
PHP:
:::php
class MyController extends Controller {
function search($request) {
$htmlTitle = '<p>Your results for:' . Convert::raw2xml($request->getVar('Query')) . '</p>';
return $this->customise(array(
'Query' => DBField::create('Text', $request->getVar('Query')),
'HTMLTitle' => DBField::create('HTMLText', $htmlTitle)
));
}
}
Template:
:::php
<h2 title="Searching for $Query.ATT">$HTMLTitle</h2>
Whenever you insert a variable into an HTML attribute within a template, use $VarName.ATT, no not $VarName.
You can also use the built-in casting in PHP by using the *obj()* wrapper, see [datamodel](/topics/datamodel) .
### Escaping URLs
Whenever you are generating a URL that contains querystring components based on user data, use urlencode() to escape the
user data, not *Convert::raw2att()*. Use raw ampersands in your URL, and cast the URL as a "Text" DBField:
PHP:
:::php
class MyController extends Controller {
function search($request) {
$rssRelativeLink = "/rss?Query=" . urlencode($_REQUEST['query']) . "&sortOrder=asc";
$rssLink = Controller::join_links($this->Link(), $rssRelativeLink);
return $this->customise(array(
"RSSLink" => DBField::create("Text", $rssLink),
));
}
}
Template:
:::php
<a href="$RSSLink.ATT">RSS feed</a>
Some rules of thumb:
* Don't concatenate URLs in a template. It only works in extremely simple cases that usually contain bugs.
* Use *Controller::join_links()* to concatenate URLs. It deals with querystrings and other such edge cases.
## Cross-Site Request Forgery (CSRF)
SilverStripe has built-in countermeasures against this type of identity theft for all form submissions. A form object
will automatically contain a *SecurityID* parameter which is generated as a secure hash on the server, connected to the
currently active session of the user. If this form is submitted without this parameter, or if the parameter doesn't
match the hash stored in the users session, the request is discarded.
If you know what you're doing, you can disable this behaviour:
:::php
$myForm->disableSecurityToken();
See
[http://shiflett.org/articles/cross-site-request-forgeries](http://shiflett.org/articles/cross-site-request-forgeries)
## Casting user input
When working with `$_GET`, `$_POST` or `Director::urlParams` variables, and you know your variable has to be of a
certain type, like an integer, then it's essential to cast it as one. *Why?* To be sure that any processing of your
given variable is done safely, with the assumption that it's an integer.
To cast the variable as an integer, place `(int)` or `(integer)` before the variable.
For example: a page with the URL paramaters *mysite.com/home/add/1* requires that ''Director::urlParams['ID']'' be an
integer. We cast it by adding `(int)` - ''(int)Director::urlParams['ID']''. If a value other than an integer is
passed, such as *mysite.com/home/add/dfsdfdsfd*, then it returns 0.
Below is an example with different ways you would use this casting technique:
:::php
function CaseStudies() {
// cast an ID from URL parameters e.g. (mysite.com/home/action/ID)
$anotherID = (int)Director::urlParams['ID'];
// perform a calculation, the prerequisite being $anotherID must be an integer
$calc = $anotherID + (5 - 2) / 2;
// cast the 'category' GET variable as an integer
$categoryID = (int)$_GET['category'];
// perform a get_by_id, ensure the ID is an integer before querying
return DataObject::get_by_id('CaseStudy', $categoryID);
}
The same technique can be employed anywhere in your PHP code you know something must be of a certain type. A list of PHP
cast types can be found here:
* `(int)`, `(integer)` - cast to integer
* `(bool)`, `(boolean)` - cast to boolean
* `(float)`, `(double)`, `(real)` - cast to float
* `(string)` - cast to string
* `(array)` - cast to array
* `(object)` - cast to object
Note that there is also a 'SilverStripe' way of casting fields on a class, this is a different type of casting to the
standard PHP way. See [casting](/topics/datamodel#casting).
## Filesystem
### Don't allow script-execution in /assets
As all uploaded files are stored by default on the /assets-directory, you should disallow script-execution for this
folder. This is just an additional security-measure to making sure you avoid directory-traversal, check for filesize and
disallow certain filetypes.
Example configuration for Apache2:
<VirtualHost *:80>
...
<LocationMatch assets/>
php_flag engine off
Options -ExecCGI -Includes -Indexes
</LocationMatch>
</VirtualHost>
If you are using shared hosting or in a situation where you cannot alter your Vhost definitions, you can use a .htaccess
file in the assets directory. This requires PHP to be loaded as an Apache module (not CGI or FastCGI).
**/assets/.htaccess**
php_flag engine off
Options -ExecCGI -Includes -Indexes
## Related
* [http://silverstripe.org/security-releases/](http://silverstripe.org/security-releases/)
## Links
* [Best-practices for securing MySQL (securityfocus.com)](http://www.securityfocus.com/infocus/1726)

124
docs/en/topics/templates.md Normal file
View File

@ -0,0 +1,124 @@
# Templates
## Introduction
SilverStripe templates consist of HTML code augmented with special control codes, described below. Because of this, you
can have as much control of your site's HTML code as you like.
Because the SilverStripe templating language is a string processing language it can therefore be used to make other
text-based data formats, such as XML or RTF.
Here is a very simple template:
:::ss
<html>
<head>
<% base_tag %>
<title>$Title</title>
$MetaTags
</head>
<body>
<div id="Container">
<div id="Header">
<h1>Bob's Chicken Shack</h1>
</div>
<div id="Navigation">
<% if Menu(1) %>
<ul>
<% control Menu(1) %>
<li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
</div>
<div class="typography">
$Layout
</div>
<div id="Footer">
<p>Copyright $Now.Year</p>
</div>
</div>
</body>
</html>
<%-- comment --%>
## Default Template Syntax
These tags appear on the default template and should be included in every theme:
### Base Tag
The `<% base_tag %>` placeholder is replaced with the HTML base element. Relative links within a document (such as `<img
src="someimage.jpg" />`) will become relative to the URI specified in the base tag. This ensures the browser knows where
to locate your sites images and css files. So it is a must for templates!
It renders in the template as `<base href="http://www.mydomain.com" />`
### Meta Tags
The `$MetaTags` placeholder in a template returns a segment of HTML appropriate for putting into the `<head>` tag. It
will set up title, keywords and description meta-tags, based on the CMS content and is editable in the 'Meta-data' tab
on a per-page basis. If you dont want to include the title-tag `<title>` (for custom templating), use
`$MetaTags(false)`.
By default `$MetaTags` renders:
:::ss
<title>Title of the Page</title>
<meta name="generator" http-equiv="generator" content="SilverStripe 2.0" >
<meta http-equiv="Content-type" content="text/html; charset=utf-8" >
TODO Explain SiteTree properties and SiteTree->MetaTags() overloading
### Including CSS and JavaScript files
See [CSS](/topics/css) and [Javascript](/topics/javascript) topics for individual including of files and
[requirements](reference/requirements) for good examples of including both Javascript and CSS files.
### Layout Tag
In every SilverStripe theme there is a default `Page.ss` file in the `/templates` folder. `$Layout` appears in this file
and is a core variable which includes a Layout template inside the `/templates/Layout` folder once the page is rendered.
By default the `/templates/Layout/Page.ss` file is included in the html template.
### .typography style
By default, SilverStripe includes the `theme/css/typography.css` file into the Content area. So you should always include the
typography style around the main body of the site so both styles appear in the CMS and on the template. Where the main body of
the site is can vary, but usually it is included in the /Layout files. These files are included into the main Page.ss template
by using the `$Layout` variable so it makes sense to add the .typography style around $Layout.
:::ss
<div class="typography">
$Layout
</div>
## Designing reuseable templates
Although SilverStripe is ultimately flexible in how you create your templates, there's a couple of best practices. These
will help you to design templates for modules, and make it easier for other site developers to integrate them into their
own base templates.
* Most of your templates should be Layout templates
* Build your templates as a [Theme](/topics/themes) so you can easily re-use and exchange them
* Your layout template should include a standard markup structure (`<div id="Layout">`$Layout`</div>`)
* Layout templates only include content that could be completely replaced by another module (e.g. a forum thread). It
might be infeasible to do this 100%, but remember that every piece of navigation that needs to appear inside `$Layout`
will mean that you have to customise templates when integrating the module.
* Any CSS applied to layout templates should be flexible width. This means the surrounding root template can set its
width independently.
* Don't include any navigation elements in your Layout templates, they should be contained in the root template.
* Break down your templates into groups of includes. Site integrators would then have the power to override individual
includes, rather than entire templates.
For more information about templates go to the [Advanced Templates](/reference/advanced-templates) page.
## Related
* [Advanced Templates](/reference/advanced-templates)
* [Typography](/reference/typography)
* [themes](/topics/themes)
* [widgets](/topics/widgets)
* [images](/reference/image)
* [Tutorial 1: Building a basic site](/tutorials/1-building-a-basic-site)
* [Tutorial 2: Extending a basic site](/tutorials/2-extending-a-basic-site)

View File

@ -0,0 +1,67 @@
# Writing functional tests
Functional tests test your controllers. The core of these are the same as unit tests:
* Create a subclass of SapphireTest in the mysite/tests or (module)/tests folder.
* Define static $fixture_file to point to a database YAML file.
* Create methods that start with "test" to create your tests.
* Assertions are used to work out if a test passed or failed.
The code of the tests is a little different. Instead of examining the behaviour of objects, we example the results of
URLs. Here is an example from the subsites module:
:::php
class SubsiteAdminTest extends SapphireTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
/**
* Return a session that has a user logged in as an administrator
*/
function adminLoggedInSession() {
return new Session(array(
'loggedInAs' => $this->idFromFixture('Member', 'admin')
));
}
/**
* Test generation of the view
*/
function testBasicView() {
// Open the admin area logged in as admin
$response1 = Director::test('admin/subsites/', null, $this->adminLoggedInSession());
// Confirm that this URL gets you the entire page, with the edit form loaded
$response2 = Director::test('admin/subsites/show/1', null, $this->adminLoggedInSession());
$this->assertTrue(strpos($response2->getBody(), 'id="Root_Configuration"') !== false);
$this->assertTrue(strpos($response2->getBody(), '<head') !== false);
// Confirm that this URL gets you just the form content, with the edit form loaded
$response3 = Director::test('admin/subsites/show/1', array('ajax' => 1), $this->adminLoggedInSession());
$this->assertTrue(strpos($response3->getBody(), 'id="Root_Configuration"') !== false);
$this->assertTrue(strpos($response3->getBody(), '<form') === false);
$this->assertTrue(strpos($response3->getBody(), '<head') === false);
}
We are using a new static method here: **Director::test($url, $postVars, $sessionObj)**
Director::test() lets us execute a URL and see what happens. It bypasses HTTP, instead relying on the cleanly
encapsulated execution model of Controller.
It takes 3 arguments:
* $url: The URL to execute
* $postVars: Post variables to pass to the URL
* $sessionObj: A Session object representing the current session.
And it returns an HTTPResponse object, which will give you the response headers (including redirection), status code,
and body.
We can use string processing on the body of the response to then see if it fits with our expectations.
If you're testing for natural language responses like error messages, make sure to use [i18n](/topics/i18n) translations through
the *_t()* method to avoid tests failing when i18n is enabled.

View File

@ -0,0 +1,151 @@
# How To Create a Sapphire Test
A unit test class will test the behaviour of one of your DataObjects. This simple fragment of SiteTreeTest provides us
the basics of creating unit tests.
:::php
<?php
/**
* Tests for SiteTree
*/
class SiteTreeTest extends SapphireTest {
/**
* Define the fixture file to use for this test class
*/
static $fixture_file = 'sapphire/tests/SiteTreeTest.yml';
/**
* Test generation of the URLSegment values.
* - Turns things into lowercase-hyphen-format
* - Generates from Title by default, unless URLSegment is explicitly set
* - Resolves duplicates by appending a number
*/
function testURLGeneration() {
$expectedURLs = array(
'home' => 'home',
'staff' => 'my-staff',
'about' => 'about-us',
'staffduplicate' => 'my-staff-2',
'product1' => '1-1-test-product',
'product2' => 'another-product',
'product3' => 'another-product-2',
'product4' => 'another-product-3',
);
foreach($expectedURLs as $fixture => $urlSegment) {
$obj = $this->objFromFixture('Page', $fixture);
$this->assertEquals($urlSegment, $obj->URLSegment);
}
}
}
There are a number of points to note in this code fragment:
* Your test is a **subclass of SapphireTest**. Both unit tests and functional tests are a subclass of SapphireTest.
* **static $fixture_file** is defined. The testing framework will automatically set up a new database for **each** of
your tests. The initial database content will be sourced from the YML file that you list in $fixture_file. You must
define this value. Note also that, for the time being, you can only point to one YML file for each test class.
* Each **method that starts with the word "test"** will be executed by the TestRunner. Define as many as you like; the
database will be rebuilt for each of these.
* **$this->objFromFixture($className, $identifier)** can be used to select one of the objects named in your fixture
file. To identify to the object, we provide a class name and an identifier. The identifier is specified in the YML
file but not saved in the database anywhere. objFromFixture() looks the DataObject up in memory rather than using the
database. This means that you can use it to test the functions responsible for looking up content in the database.
* **$this->assertEquals()** is one of the many assert... functions that PHPUnit provides us. See below for more
information.
## Assertion commands
**$this->assertEquals()** is an example of an assertion function. These functions form the basis of our tests - a test
fails if and only if one or more of the assertions fail.
There are many assertions available:
* See [the PHPUnit manual chapter 22](http://www.phpunit.de/manual/current/en/api.html#api.assert)
for a listing of all PHPUnit's built-in assertions.
* **$this->assertEmailSent($to, $from, $subject, $content)**: When an email is "sent" during a test run, it's not
actually sent. Instead, it is logged in an internal register. You can use assertEmailSent() to verify that an email
was sent. Each of the arguments can be a string, for an exact match, or, a preg_match() compatible regular expression,
if it starts with "/".
## The Database YAML file
The main feature of SapphireTest over the raw PHPUnit classes is that SapphireTest will prepare a temporary database for
you. The content of that database is provided in a special YAML file. YAML is a simple markup languages that uses tabs
and colons instead of the more verbose XML tags, and because of this much better for developers creating files by hand.
We will begin with a sample file and talk our way through it.
Page:
home:
Title: Home
about:
Title: About Us
staff:
Title: Staff
URLSegment: my-staff
Parent: =>Page.about
staffduplicate:
Title: Staff
URLSegment: my-staff
Parent: =>Page.about
products:
Title: Products
product1:
Title: 1.1 Test Product
product2:
Title: Another Product
product3:
Title: Another Product
product4:
Title: Another Product
contact:
Title: Contact Us
ErrorPage:
404:
Title: Page not Found
ErrorCode: 404
The contents of the YAML file are broken into three levels.
* **Top level: class names** - Page and ErrorPage. This is the name of the dataobject class that should be created.
The fact that ErrorPage is actually a subclass is irrelevant to the system populating the database. It just
instantiates the object you specify.
* **Second level: identifiers** - home, about, staff, staffduplicate, etc. These are the identifiers that you pass as
the second argument of SapphireTest::objFromFixture(). Each identifier you specify delimits a new database record.
This means that every record needs to have an identifier, whether you use it or not.
* **Third level: fields** - each field for the record is listed as a 3rd level entry. In most cases, the field's raw
content is provided. However, if you want to define a relationship, you can do so using "=>".
There are a couple of lines like this:
Parent: =>Page.about
This will tell the system to set the ParentID database field to the ID of the Page object with the identifier "about".
This can be used on any has-one or many-many relationship. Note that we use the name of the relationship (Parent), and
not the name of the database field (ParentID)
On many-many relationships, you should specify a comma separated list of values.
MyRelation: =>Class.inst1,=>Class.inst2,=>Class.inst3
An crucial thing to note is that **the YAML file specifies DataObjects, not database records**. The database is
populated by instantiating DataObject objects, setting the fields listed, and calling write(). This means that any
onBeforeWrite() or default value logic will be executed as part of the test. This forms the basis of our
testURLGeneration() test above.
For example, the URLSegment value of Page.staffduplicate is the same as the URLSegment value of Page.staff. When the
fixture is set up, the URLSegment value of Page.staffduplicate will actually be my-staff-2.
Finally, be aware that requireDefaultRecords() is **not** called by the database populator - so you will need to specify
standard pages such as 404 and home in your YAML file.

View File

@ -0,0 +1,64 @@
# Email Sending
SilverStripe's test system has built-in support for testing emails sent using the Email class.
## How it works
For this to work, you need to send emails using the `Email` class, which is generally the way that we recommend you
send emails in your SilverStripe application. Here is a simple example of how you might do this:
:::php
$e = new Email();
$e->To = "someone@example.com";
$e->Subject = "Hi there";
$e->Body = "I just really wanted to email you and say hi.";
$e->send();
Normally, the send() method would send an email using PHP's mail() function. However, if you are running a `SapphireTest` test, then it holds off actually sending the email, and instead lets you assert that an email was sent
using this method.
:::php
$this->assertEmailSent("someone@example.com", null, "/th.*e$/");
The arguments are `$to`, `$from`, `$subject`, `$body`, and can be take one of the following three forms:
* A string: match exactly that string
* `null`/''false'': match anything
* A PERL regular expression (starting with '/'): match that regular expression
## How to use it
Given all of that, there is not a lot that you have to do in order to test emailing functionality in your application.
* Write your SilverStripe application, using the Email class to send emails.
* Write tests that trigger the email sending functionality.
* Include appropriate `$this->assertEmailSent()` calls in those tests.
That's it!
## What isn't tested
It's important to realise that this email testing doesn't actually test everything that there is to do with email. The
focus of this email testing system is testing that your application is triggering emails correctly. It doesn't test
your email infrastructure outside of the webserver. For example:
* It won't test that email is correctly configured on your webserver
* It won't test whether your emails are going to be lost in someone's spam filter
* It won't test bounce-handling or any other auxiliary services of email
## How it's built
For those of you who want to dig a little deeper, here's a quick run-through of how the system has been built. As well
as explaining how we built the email test, this is a good design pattern for making other "tricky external systems"
testable:
1. The `Email::send()` method makes uses of a static object, `Email::$mailer`, to do the dirty work of calling
mail(). The default mailer is an object of type `Mailer`, which performs a normal send.
2. `Email::set_mailer()` can be called to load in a new mailer object.
3. `SapphireTest::setUp()` method calls `Email::set_mailer(new TestMailer())` to replace the default mailer with a `TestMailer` object. This replacement mailer doesn't actually do anything when it is asked to send an email; it just
records the details of the email in an internal field that can be searched with `TestMailer::findEmails()`.
4. `SapphireTest::assertEmailSent()` calls `TestMailer::findEmails()` to see if a mail-send was requested by the
application.

View File

@ -0,0 +1,153 @@
# Unit and Integration Testing
The Sapphire core contains various features designed to simplify the process of creating and managing automated tests.
* [Create a unit test](create-sapphire-test): Writing tests to check core data objects
* [Creating a functional test](create-functional-test): An overview of functional tests and how to write a functional test
* [Email Sending](email-sending): An overview of the built-in email testing code
* [Troubleshooting](testing-guide-troubleshooting): Frequently asked questions list for testing issues
* [Why Unit Test?](why-test): Why should you test and how to start testing
## Introduction
If you are familiar with PHP coding but new to unit testing, you should read the [Introduction](/topics/testing) and
check out Mark's presentation [Getting to Grips with SilverStripe Testing](http://www.slideshare.net/maetl/getting-to-grips-with-silverstripe-testing).
You should also read over [the PHPUnit manual](http://www.phpunit.de/manual/current/en/). It provides a lot of
fundamental concepts that we build on in this documentation.
If you're more familiar with unit testing, but want a refresher of some of the concepts and terminology, you can browse
the [Testing Glossary](#glossary).
To get started now, follow the installation instructions below, and check
[Troubleshooting](/topics/testing/testing-guide-troubleshooting) in case you run into any problems.
## Installation
The framework has a required dependency on [PHPUnit](http://www.phpunit.de/) and an optional dependency on
[SimpleTest](http://simpletest.org/), the two premiere PHP testing frameworks.
To run Sapphire tests, you'll need to be able to access PHPUnit on your include path. First, you'll need to make sure
that you have the PEAR command line client installed. To test this out, type `pear help` at your prompt. You should
see a bunch of generic PEAR info. If it's not installed, you'll need to set it up first (see: [Getting Started with
PEAR](http://www.sitepoint.com/article/getting-started-with-pear/)) or else manually install PHPUnit (see: [Installation
instructions](http://www.phpunit.de/pocket_guide/3.3/en/installation.html)).
The PHPUnit installation via PEAR is very straightforward.
You might have to perform the following commands as root or super user (sudo).
<del>We need a specific version of PHPUnit (3.3.x), as 3.4 or higher breaks our test runner (see [#4573](http://open.silverstripe.com/ticket/4573))</del>
At your prompt, type the following commands:
pear channel-discover pear.phpunit.de
pear channel-discover pear.symfony-project.com
pear install phpunit/PHPUnit
## Running Tests
### Via Web Browser
Go to the main test URL which will give you options for running various available test suites or individual tests on
their own:
http://localhost/dev/tests
### Via Command Line
`cd` to the root level of your project and run [sake](/topics/commandline) (Sapphire Make) to execute the tests:
/path/to/project$ sake dev/tests/all
### Partial Test Runs
Run specific tests:
dev/tests/MyTest,MyOtherTest
Run all tests in a module folder, e.g. "sapphire"
dev/tests/module/<modulename>
Skip certain tests
dev/tests/all SkipTests=MySkippedTest
## Writing Tests
Tests are written by creating subclasses of `[api:SapphireTest]`. You should put tests for your site in the
`mysite/tests` directory. If you are writing tests for a module, put them in the `(modulename)/tests` directory.
Generally speaking, there should be one test class for each application class. The name of the test class should be the
application class, with "Test" as a suffix. For instance, we have all the tests for `SiteTree` in
`sapphire/tests/SiteTreeTest.php`
You will generally write two different kinds of test classes.
* **Unit Test:** Test the behaviour of one of your DataObjects.
* **Functional Test:** Test the behaviour of one of your controllers.
Some people may note that we have used the same naming convention as Ruby on Rails.
## How To
Tutorials and recipes for creating tests using the Sapphire framework:
* **[Create a Sapphire Test](/topics/testing/create-sapphire-test)**
* **Load Test Fixtures**
* **[Create a Functional Test](/topics/testing/create-functional-test)**
* **[Test Outgoing Email Sending](/topics/testing/email-sending)**
## Glossary {#glossary}
**Assertion:** A predicate statement that must be true when a test runs.
**Test Case:** The atomic class type in most unit test frameworks. New unit tests are created by inheriting from the
base test case.
**Test Suite:** Also known as a 'test group', a composite of test cases, used to collect individual unit tests into
packages, allowing all tests to be run at once.
**Fixture:** Usually refers to the runtime context of a unit test - the environment and data prerequisites that must be
in place in order to run the test and expect a particular outcome. Most unit test frameworks provide methods that can be
used to create fixtures for the duration of a test - `setUp` - and clean them up after the test is done - `tearDown'.
**Refactoring:** A behavior preserving transformation of code. If you change the code, while keeping the actual
functionality the same, it is refactoring. If you change the behavior or add new functionality it's not.
**Smell:** A code smell is a symptom of a problem. Usually refers to code that is structured in a way that will lead to
problems with maintenance or understanding.
**Spike:** A limited and throwaway sketch of code or experiment to get a feel for how long it will take to implement a
certain feature, or a possible direction for how that feature might work.
**Test Double:** Also known as a 'Substitute'. A general term for a dummy object that replaces a real object with the
same interface. Substituting objects is useful when a real object is difficult or impossible to incorporate into a unit
test.
**Fake Object**: A substitute object that simply replaces a real object with the same interface, and returns a
pre-determined (usually fixed) value from each method.
**Mock Object:** A substitute object that mimicks the same behavior as a real object (some people think of mocks as
"crash test dummy" objects). Mocks differ from other kinds of substitute objects in that they must understand the
context of each call to them, setting expectations of which, and what order, methods will be invoked and what parameters
will be passed.
**Test-Driven Development (TDD):** A style of programming where tests for a new feature are constructed before any code
is written. Code to implement the feature is then written with the aim of making the tests pass. Testing is used to
understand the problem space and discover suitable APIs for performing specific actions.
**Behavior Driven Development (BDD):** An extension of the test-driven programming style, where tests are used primarily
for describing the specification of how code should perform. In practice, there's little or no technical difference - it
all comes down to language. In BDD, the usual terminology is changed to reflect this change of focus, so *Specification*
is used in place of *Test Case*, and *should* is used in place of *expect* and *assert*.
## Feedback
If you have a topic you would like covered in these section please ask for it on our [Bug Tracker](http://open.silverstripe.org)

View File

@ -0,0 +1,8 @@
# Troubleshooting
Part of the [SilverStripe Testing Guide](testing-guide).
## I can't run my new test class
If you've just added a test class, but you can't see it via the web interface, chances are, you haven't flushed your
manifest cache - append `?flush=1` to the end of your URL querystring.

View File

@ -0,0 +1,93 @@
# Why Unit Test?
*Note: This is part of the [SilverStripe Testing Guide](/topics/testing/).*
So at this point, you might be thinking, *"that's way too complicated, I don't have time to write unit tests on top of
all the things I'm already doing"*. Fair enough. But, maybe you're already doing things that are close to unit testing
without realizing it. Everyone tests all the time, in various ways. Even if you're just refreshing a URL in a browser to
review the context of your changes, you're testing!
First, ask yourself how much time you're already spending debugging your code. Are you inserting `echo`, `print_r`,
and `die` statements into different parts of your program and watching the details dumping out to screen? **Yes, you
know you are.** So how much time do you spend doing this? How much of your development cycle is dependent on dumping out
the contents of variables to confirm your assumptions about what they contain?
From this position, it may seem that unit testing may take longer and have uncertain outcomes simply because it involves
adding more code. You'd be right, in the sense that we should be striving to write as little code as possible on
projects. The more code there is, the more room there is for bugs, the harder it is to maintain. There's absolutely no
doubt about that. But if you're dumping the contents of variables out to the screen, you are already making assertions
about your code. All unit testing does is separate these assertions into separate runnable blocks of code, rather than
have them scattered inline with your actual program logic.
The practical and immediate advantages of unit testing are twofold. Firstly, they mean you don't have to mix your
debugging and analysis code in with your actual program code (with the need to delete, or comment it out once you're
done). Secondly, they give you a way to capture the questions you ask about your code while you're writing it, and the
ability to run those questions over and over again, with no overhead or interference from other parts of the system.
Unit testing becomes particularly useful when exploring boundary conditions or edge case behavior of your code. You can
write assertions that verify examples of how your methods will be called, and verify that they always return the right
results each time. If you make changes that have the potential to break these expected results, running the unit tests
over and over again will give you immediate feedback of any regressions.
Unit tests also function as specifications. They are a sure way to describe an API and how it works by simply running
the code and demonstrating what parameters each method call expects and each method call returns. You could think of it
as live API documentation that provides real-time information about how the code works.
Unit test assertions are best understood as **pass/fail** statements about the behavior of your code. Ideally, you want
every assertion to pass, and this is usually up by the visual metaphor of green/red signals. When things are all green,
it's all good. Red indicates failure, and provides a direct warning that you need to fix or change your code.
## Getting Started
Everyone has a different set of ideas about what makes good code, and particular preferences towards a certain style of
logic. At the same time, frameworks and programming languages provide clear conventions and design idioms that guide
code towards a certain common style.
If all this ranting and raving about the importance of testing hasn't made got you thinking that you want to write tests
then we haven't done our job well enough! But the key question still remains - *"where do I start?"*.
To turn the key in the lock and answer this question, we need to look at how automated testing fits into the different
aspects of the SilverStripe platform. There are some significant differences in goals and focus between different layers
of the system and interactions between the core, and various supporting modules.
### Sapphire Core
In open source core development, we are focussing on a large and (for the most part) stable system with existing well
defined behavior. Our overarching goal is that we do not want to break or change this existing behavior, but at the same
time we want to extend and improve it.
Testing the Sapphire framework should focus on [characterization](http://en.wikipedia.org/wiki/Characterization_Test).
We should be writing tests that illustrate the way that the API works, feeding commonly used methods with a range of
inputs and states and verifying that these methods respond with clear and predictable results.
Especially important is documenting and straighten out edge case behavior, by pushing various objects into corners and
twisting them into situations that we know are likely to manifest with the framework in the large.
### SilverStripe Modules
Modules usually encapsulate a smaller, and well defined subset of behavior or special features added on top of the core
platform. A well constructed module will contain a reference suite of unit tests that documents and verifies all the
basic aspects of the module design. See also: [modules](/topics/modules).
### Project Modules
Testing focus on client projects will not be quite so straightforward. Every project involves different personalities,
goals, and priorities, and most of the time, there is simply not enough time or resources to exhaustively predicate
every granular aspect of an application.
On application projects, the best option is to keep tests lean and agile. Most useful is a focus on experimentation and
prototyping, using the testing framework to explore solution spaces and bounce new code up into a state where we can be
happy that it works the way we want it to.
## Rules of Thumb
**Be aware of breaking existing behavior.** Run your full suite of tests every time you do a commit.
**Not everything is permanent.** If a test is no longer relevant, delete it from the repository.
## See Also
* [Getting to Grips with SilverStripe
Testing](http://www.slideshare.net/maetl/getting-to-grips-with-silverstripe-testing)

View File

@ -0,0 +1,279 @@
# Developing Themes
## Introduction
[Tutorial 1](/tutorials/1-building-a-basic-site#templates) shows you how to create page templates. This guide will help
you create your own SilverStripe website theme.
Developing your own theme in SilverStripe is a piece of cake thanks to a very straight forward and clean templating
language.
## What is a Theme?
A theme is a set of HTML/CSS/Javascript and images that can be used to provide a skin for a site. A theme does not
include any PHP: instead it should be separate from the code which allows the portability of a design. After all, this
is an MVC framework!
## Getting started - Folder Structure
To start your theme you first need to create the basic folder structure for the theme. Check out the image below for the
layout of your folders. First you need to create a folder in the themes directory called the name of your theme (we're
using "blackcandy"). Please note that underscores in the theme name are reserved to denote "sub-themes" (e.g.
"blackcandy_blog").
![themes:basicfilestructure.gif](_images/basicfilestructure.gif)
Inside your theme, you need the css, images and templates folders. Each of these folders contain parts of your theme and
keeping a good folder structure is super important. Now we have this structure we can put our CSS in the css folder,
Images in the images folder and all our HTML in the templates folder. This keeps our workspace clean and easy to use.
After you have created the templates folder you need to create 2 more folders within - Includes and Layout (Note the
uppercase initial letters). These are 2 different types of templates you will use in your theme - Includes contain
snippets of HTML that you want to break out and share between templates (for example the Header can be an include,
Footer, Navigation etc) whereas Layout templates are the base page templates. So you can have several includes in a
Layout template.
## Getting started - Core Files
### HTML Templates
Once you have created your folders you need to start to fill it out with a couple 'Core' files. First and most
importantly is we need a HTML template for our design. Read the [Tutorial 1](/tutorials/1-building-a-basic-site#templates)
and the HTML pages for more in-depth discussion about the HTML templates and how they work. At the very least
we need a Page.ss file (note the .ss extenstion - Don't worry its just HTML and any text editor will still read it). So
go ahead and create 2 Page.ss files. One in templates, the other in Layout.
![themes:basicfiles.gif](_images/basicfiles.gif)
Whats with the 2 Page.ss files? Well we have 2 so when the user visits a page they get redirected to the top level
Page.ss then, depending on what page they are on, we can have a custom template for that page in the Layout folder. If
you dont get it now, you will hopefully pick it up over the rest of this.
So you have 2 blank Page.ss files. What are we going to do with them? How bout we put some HTML in them so we can see
our theme in action. The code for mine is below.
** yourtheme/templates/Page.ss **
:::ss
<!DOCTYPE html>
<html lang="en">
<head>
<% base_tag %>
$MetaTags(false)
<title>Bob's Chicken Shack | $Title</title>
</head>
<body>
<div id="Container">
<div id="Header">
<h1>Bob's Chicken Shack</h1>
</div>
<div id="Navigation">
<% if Menu(1) %>
<ul>
<% control Menu(1) %>
<li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
</div>
<div id="Layout">
$Layout
</div>
<div id="Footer">
<p>Copyright $Now.Year - Bob's Chicken Shack.</p>
</div>
</div>
</body>
</html>
** yourtheme/templates/Layout/Page.ss **
:::ss
<h1>$Title</h1>
$Content
$Form
$PageComments
All you have to do now is tell your site to use your new theme - This is defined in the **mysite/_config.php** file
:::php
SSViewer::set_theme('mythemename');
Go to yoursite.com/?flush=1 and check it out. You should be using your new theme! Not really that awesome or amazing is
it? Next we need to add some CSS Magic!
See [Templates](/reference/themes) for more information about templates.
### CSS Files
By standard SilverStripe uses 3 CSS Files for your site -
* **layout.css** contains the layout and design of the site
* **typography.css** contains the styling for the text/fonts/links (used in both front and back ends)
* **form.css** styling for forms.
You can add more stylesheets using the template tag `<% require themedCSS(filename) %>`, which will load filename.css from
your css directory.
Note: If you're using a default install of Silverstripe and notice that you're getting layout.css, typography.css and
forms.css included without asking for them, they may be being called on lines 21-23 in mysite/code/Page.php. Remove
these three Requirements::themedCSS lines, and you will be free to add your own styles.
## Dividing your site the correct way!
Most Web page designers 10 years ago used a table-based layout to achieve a consistent look. Now, (Thankfully) there's a
different way to achieve the same look.
Using CSS and tags (including `DIV`s) reduces markup code, speeds up page downloads, separates content from
its visual presentation, and brings your code closer to web standards compliance--all while making your website more
appealing to search engine spiders.
For layout we tend to use `DIV` tags as the `DIV` tag defines a division/section in a document.
Let's have a look at part of a Page.ss for the main layout elements defining a 2 column layout.
:::ss
<div id="Container">
<div id="Header">
<!-- Header -->
</div>
<div id="Navigation">
<!-- The Main Site Nav -->
</div>
<div id="Layout">
<!-- The whole site content has to sit inside here! Anything you want to sub template (eg each page will be different, needs to be contained in $Layout. This calls the file /Layout/Page.ss or anyother sub page template -->
$Layout
</div>
<div id="Footer">
</div>
</div>
As you can see we normally wrap the site in a container. For this we use the ID 'Container'. Then we divide the main
template into sections.
:::ss
<div id="Header"><!-- markup goes here --></div>
We have the Header section which includes things like any banner images/ mastheads/ logos or any stuff that belongs at
the top of the page, This might vary on the design of the page
:::ss
<div id="Navigation"><!-- markup goes here --></div>
Next is a division for the main navigation. This may contain something like:
:::ss
<div id="Navigation">
<% if Menu(1) %>
<ul>
<% control Menu(1) %>
<li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
</div>
This is the standard for creating the main Navigation. As you can see it outputs the Menu 1 in a unordered list.
Before stepping into a control (a foreach loop) it's good practise to check if it exists first. This is not only
important in manipulating SilverStripe templates, but in any programming language!
:::ss
<% if MyFunction %>
<% control MyFunction %>
$Title
<% end_control %>
<% end_if %>
Last and probably least is the Footer division. Here is where you put all the Footer related stuff for your website.
Maybe even a nice link saying Website Powered by SilverStripe to show your support.
:::ss
<div id="Footer">
<!-- markup goes here -->
</div>
## Resources
A bunch of resources feel free to use to make your template awesome
* http://kuler.adobe.com - Kuler is a great color scheming tool
* http://blog.html.it/layoutgala/ - 40 super cool CSS layouts for you to use
* http://designmeltdown.com - Great gallery of websites. Browse through and get inspired.
* http://validator.w3.org/ - Your template must pass 'or get near' validation.
* http://famfamfam.com/lab/icons/ - free, beautiful icons.
* http://cssremix.com - Another CSS site gallery for inspiration.
* http://www.maxdesign.com.au/presentation/process/ - a good process for creating a design
## Reference
### Overriding
The templating system will search for the appropriate files in the following order:
1. mysite (or other name given to site folder)
2. themes
3. module (eg blog)
So if, for example, you had a typography.css file for a module in the module folder (eg blog/css/), in the theme module
directory (eg themes/blackcandy_blog/css/), and in your site folder (eg mysite/css/), the system would use the file
mysite/css/typography.css
Note: This only applies for CSS and template files. PHP files **do not** get overridden!
### Requirements
The `[api:Requirements::themedCSS()]` function will
do the search specified above. This avoids the need to type a full path to the css file, and also provides better
ambiguity for themes.
### Subthemes
If you have a theme called mytheme_forum, it is considered to be a 'subtheme' of the mytheme theme. This lets module
developers release extensions to popular themes that will let their module work with that theme.
A subtheme overrides the files in the module. So for instance, if you have the forum setup instead of editing the files
within the forum/ module you would create a themes/yourtheme_forum/ folder.
### ThemeDir
If you want to refer to an image or other file asset in a .ss template, use $ThemeDir. For example:
:::ss
<img src="$ThemeDir/images/log.gif" />
If your image is in a subtheme, you can refer to that with an argument to ThemeDir. For example, if your image was in
mytheme_forum, you could use the following code:
:::ss
<img src="$ThemeDir(forum)/images/log.gif" />
## Conventions, standards and guidelines
Following some set standards and conventions makes life easy for you and I.
Some conventions for SilverStripe websites, which we suggest following. Take a look at each:
* [Coding-Conventions](/misc/coding-conventions)
* [Typography](/reference/typography)
We also suggest following various [industry standards](http://www.w3.org/) and conventions.

41
docs/en/topics/themes.md Normal file
View File

@ -0,0 +1,41 @@
# Themes
## Introduction
Themes can be used to kick start your SilverStripe projects, and generally make you look good.
## Downloading
Head to the [ Themes ](http://www.silverstripe.org/themes) area of the website to check out the wide range of themes
the community has built. Each theme has a page with links you can use to preview and download it. The theme is provided
as a .tar.gz file.
## Installing
1. Unpack the contents of the zip file into the `themes` directory in your SilverStripe installation.
2. Change the site to the theme. You can do this either by:
- putting the following line in your ./mysite/_config.php: `SSViewer::set_theme("themename");`
- changing the theme in the Site Configuration panel in the CMS
3. Visit your homepage with ?flush=all appended to the URL. `http://yoursite.com?flush=all`
## Developing your own theme
See [Developing Themes](theme-development) to get an idea of how themes actually work and how you can develop your own.
## Submitting your theme to SilverStripe
If you want to submit your theme to the silverstripe directory then check
* You should ensure your templates are well structured, modular and commented so it's easy for other people to
customise them.
* Templates should not contain text inside images and all images provided must be open source and not break any copyright or license laws.
This includes any icons your template uses in the frontend or the backend CMS.
* A theme does not include any PHP files. Only CSS, HTML, Images and Javascript.
Your theme file must be in a .tar.gz format. A useful tool for this is - [7 Zip](http://www.7-zip.org/). Using 7Zip you
must select the your_theme folder and Add to archive, select TAR and create. Then after you have the TAR file right
click it -> Add to Archive (again) -> Then use the archive format GZIP.
## Discussing
Head over to the [ Themes Forum ](http://www.silverstripe.org/themes-2/)

View File

@ -0,0 +1,406 @@
# Translation
## Introduction
This page introduces developers to using the CMS for creating content in multiple languages.
Please see [i18n](/topics/i18n) for a internationalization, globalization and localization support of built-in datatypes as well
as translating templates and PHP code.
Translations can be enabled for all subclasses of `[api:DataObject]`, so it can easily be implemented into existing code
with minimal interference.
Warning: If you're upgrading from a SilverStripe version prior to 2.3.2, please migrate your datamodel before using the
extension (see below).
## Requirements
*SilverStripe 2.3.2*
## Screenshots
![](_images/translatable4_small.png)
*Translated website*
![](_images/translatable1.png)
*CMS: Language dropdown*
![](_images/translatable2.png)
*CMS: Translatable field with original value*
![](_images/translatable3.png)
*CMS: Create a new translation*
## Usage
### Configuration
#### ThroughObject::add_extension()
Enabling Translatable through *Object::add_extension()* in your *mysite/_config.php*:
:::php
Object::add_extension('SiteTree', 'Translatable');
Object::add_extension('SiteConfig', 'Translatable'); // 2.4 or newer only
#### Through $extensions
:::php
class Page extends SiteTree {
static $extensions = array(
"Translatable"
);
}
Make sure to rebuild the database through /dev/build after enabling translatable.
Use the correct set_default_locale() before building the database
for the first time, as this locale will be written on all new records.
#### Setting the default locale
Important: If the "default language" of your site is not english (en_US),
please ensure to set the appropriate default language for
your content before building the database with Translatable enabled:
:::php
Translatable::set_default_locale(<locale>);
// Important: Call add_extension() after setting the default locale
Object::add_extension('SiteTree', 'Translatable');
For the Translatable class, a "locale" consists of a language code plus a region code separated by an underscore,
for example "de_AT" for German language ("de") in the region Austria ("AT").
See http://www.w3.org/International/articles/language-tags/ for a detailed description.
To ensure that your template declares the correct content language, please see [i18n](i18n#declaring_the_content_language_in_html).
### Usage
Getting a translation for an existing instance:
:::php
$translatedObj = Translatable::get_one_by_locale('MyObject', 'de_DE');
Getting a translation for an existing instance:
:::php
$obj = DataObject::get_by_id('MyObject', 99); // original language
$translatedObj = $obj->getTranslation('de_DE');
Getting translations through Translatable::set_reading_locale().
This is *not* a recommended approach, but sometimes inavoidable (e.g. for Versioned methods).
:::php
$origLocale = Translatable::get_reading_locale();
Translatable::set_reading_locale('de_DE');
$obj = Versioned::get_one_by_stage('MyObject', "ID = 99");
Translatable::set_reading_locale($origLocale);
Creating a translation:
:::php
$obj = new MyObject();
$translatedObj = $obj->createTranslation('de_DE');
### Usage for SiteTree
Translatable can be used for subclasses of SiteTree as well.
If a child page translation is requested without the parent
page already having a translation in this language, the extension
will recursively create translations up the tree.
Caution: The "URLSegment" property is enforced to be unique across
languages by auto-appending the language code at the end.
You'll need to ensure that the appropriate "reading language" is set
before showing links to other pages on a website through $_GET['locale'].
Pages in different languages can have different publication states
through the Versioned extension.
Note: You can't get Children() for a parent page in a different language
through set_reading_locale(). Get the translated parent first.
:::php
// wrong
Translatable::set_reading_lang('de_DE');
$englishParent->Children();
// right
$germanParent = $englishParent->getTranslation('de_DE');
$germanParent->Children();
### Translating custom properties
Keep in mind that the Translatable extension currently doesn't support the exclusion of properties from being translated
- all custom properties will automatically be fetched from their translated record on the database. This means you don't
have to explicitly mark any custom properties as being translatable.
The Translatable decorator applies only to the getCMSFields() method on DataObject or SiteTree, not to any fields added
in overloaded getCMSFields() implementations. See Translatable->updateCMSFields() for details. By default, custom fields
in the CMS won't show an original readonly value on a translated record, although they will save correctly. You can
attach this behaviour to custom fields by using Translatable_Transformation as shown below.
:::php
class Page extends SiteTree {
public static $db = array(
'AdditionalProperty' => 'Text',
);
function getCMSFields() {
$fields = parent::getCMSFields();
// Add fields as usual
$additionalField = new TextField('AdditionalProperty');
$fields->addFieldToTab('Root.Content.Main', $additionalField);
// If a translation exists, exchange them with
// original/translation field pairs
$translation = $this->getTranslation(Translatable::default_locale());
if($translation && $this->Locale != Translatable::default_locale()) {
$transformation = new Translatable_Transformation($translation);
$fields->replaceField(
'AdditionalProperty',
$transformation->transformFormField($additionalField)
);
}
return $fields;
}
}
### Translating theHomepage
Every homepage has a distinct URL, the default language is /home, a German translation by default would be /home-de_DE.
They can be accessed like any other translated page. If you want to access different homepages from the "root" without a
URL, add a "locale" GET parameter. The German homepage would also be accessible through /?locale=de_DE.
For this to work, please ensure that the translated homepage is a direct translation of the default homepage, and not a
new page created through "Create page...".
### Translationgroups
Each translation can have an associated "master" object in another language which it is based on,
as defined by the "MasterTranslationID" property. This relation is optional, meaning you can
create translations which have no representation in the "default language".
This "original" doesn't have to be in a default language, meaning
a french translation can have a german original, without either of them having a representation
in the default english language tree.
Caution: There is no versioning for translation groups,
meaning associating an object with a group will affect both stage and live records.
SiteTree database table (abbreviated)
| ID | URLSegment | Title | Locale |
| -- | ---------- | ----- | ------ |
| 1 | about-us | About us | en_US |
| 2 | ueber-uns | Über uns | de_DE |
| 3 | contact | Contact | en_US |
SiteTree_translationgroups database table
| TranslationGroupID | OriginalID |
| ------------------ | ---------- |
| 99 | 1 |
| 99 | 2 |
| 199 | 3 |
### CharacterSets
Caution: Does not apply any character-set conversion, it is assumed that all content
is stored and represented in UTF-8 (Unicode). Please make sure your database and
HTML-templates adjust to this.
### "Default"languages
Important: If the "default language" of your site is not english (en_US),
please ensure to set the appropriate default language for
your content before building the database with Translatable enabled:
:::php
Translatable::set_default_locale(<locale>);
### Locales and languagetags
For the Translatable class, a "locale" consists of a language code plus a region code separated by an underscore,
for example "de_AT" for German language ("de") in the region Austria ("AT").
See http://www.w3.org/International/articles/language-tags/ for a detailed description.
Uninstalling/Disabling
Disabling Translatable after creating translations will lead to all
pages being shown in the default sitetree regardless of their language.
It is advised to start with a new database after uninstalling Translatable,
or manually filter out translated objects through their "Locale" property
in the database.
## Recipes
### Switching languages
A widget now exists to switch between languages, and is [available
here](http://www.silverstripe.org/Language-Chooser-Widget/). You can easily make your own switchers with the following
basic tools. To stay friendly to caches and search engines, each translation of a page must have a unique URL
By URL:
:::php
http://<mysite>/mypage/?locale=de_DE
By user preference (place this in your Page_Controller->init() method):
:::php
$member = Member::currentUser();
if($member && $member->Locale) {
Translatable::set_reading_locale($member->Locale);
}
### Templates
As every page has its own unique URL, language selection mostly happens explicitly: A user requests a page, which always
has only one language. But how does a user coming to your English default language know that there's a Japanese version
of this page?
By default, SilverStripe core doesn't provide any switching of languages through sessions or browser cookies. As a
SEO-friendly CMS, it contains all this information in the URL. Each page in SilverStripe is aware of its translations
through the *getTranslations()* method. We can use this method in our template to build a simple language switcher. It
shows all available translations in an unordered list with links to the same page in a different language. The example
below can be inserted in any of your templates, for example *themes/blackcandy/templates/Layout/Page.ss*.
:::php
<% if Translations %>
<ul class="translations">
<% control Translations %>
<li class="$Locale.RFC1766">
<a href="$Link" hreflang="$Locale.RFC1766"
title="$Title">
<% sprintf(_t('SHOWINPAGE','Show page in %s'),$Locale.Nice) %>
</a>
</li>
<% end_control %>
</ul>
<% end_if %>
Keep in mind that this will only show you available translations for the current page. The $Locale.Nice casting will
just work if your locale value is registered in i18n::get_common_locales().
### Page-control
If you want to put static links in your template, which link to a site by their url, normally you can use the <% control
Page(page-url) %>. For sites which use Translatable, this is not possible for more than one language, because the url's
of different pages differ.
For this case place the following function in your Page_Controller:
:::php
public function PageByLang($url, $lang) {
$SQL_url = Convert::raw2sql($url);
$SQL_lang = Convert::raw2sql($lang);
$page = Translatable::get_one_by_lang('SiteTree', $SQL_lang, "URLSegment = '$SQL_url'");
if ($page->Locale != Translatable::get_current_locale()) {
$page = $page->getTranslation(Translatable::get_current_locale());
}
return $page;
}
So, for example if you have a german page "Kontakt", which should be translated to english as "Contact", you may use:
<% control PageByLang(Kontakt,de_DE) %>
The control displays the link in the right language, depending on the current locale.\\
Example:
<% control PageByLang(Kontakt,de_DE) %>
<h2><a href="$Link" title="$Title">$Title</a></h2>
<% end_control %>
### Language Chooser Widget
You can use a widget on your website to provide a list of links for switching languages:
[download](http://silverstripe.org/Language-Chooser-Widget-2/)
### Enabling the _t() function in templates
If you're looking to use [the _t() function](http://doc.silverstripe.com/doku.php?id=i18n#the_t_function) in template
files, you'll need to [set the i18n locale](/topics/translation#setting_the_i18n_locale) first.
(The reasoning is as follows: Translatable doesn't set the i18n locale. Historically these were two separate systems,
but they're reasonably interchangeable for a front-end website. The distinction is mainly valid for the CMS, because you
want the CMS to be in English (i18n), but edit pages in different languages (Translatable).)
### Migrating from 2.1 datamodel
The datamodel of Translatable changed significantly between its original release in SilverStripe 2.1 and SilverStripe
2.3.2. See our [discussion on the
mailinglist](http://groups.google.com/group/silverstripe-dev/browse_thread/thread/91e26e1f78d3c1b4/bd276dd5bbc56283?lnk=gst&q=translatable#bd276dd5bbc56283).
To migrate a database that was built with SilverStripe 2.1.x or 2.2.x, follow these steps:
* Upgrade your SilverStripe installation to at least 2.3.2 (see [upgrading](/installation/upgrading))
* Backup your database content
* Login as an administrator
* Run http://mysite.com/dev/build
* Run http://mysite.com/dev/tasks/MigrateTranslatableTask
Please see the `[api:MigrateTranslatableTask]` for
limitations of this migration task - not all your data will be preserved.
### Setting the i18n locale
You can set the i18n locale value which is used to format dates, currencies and other regionally different values to the
same as your current page locale.
:::php
class Page_Controller extends ContentController {
public function init() {
parent::init();
if($this->dataRecord->hasExtension('Translatable')) {
i18n::set_locale($this->dataRecord->Locale);
}
}
}
### Adding a new locale
The i18n logic has lookup tables for common locales in i18n::$common_locales, which is a subset of i18n::$all_locales.
If your locale is not present here, you can simply add it through mysite/_config.php:
:::php
i18n::$common_locales['de_AT'] = 'Deutsch (Oestereich)';
This should e.g. enable you to use `$Locale.Nice` in template code.
## Related
* [translate.silverstripe.org](http://translate.silverstripe.org): Starting point for community-driven translation of the Silverstripe UI
* [i18n](i18n): Developer-level documentation of Silverstripe's i18n capabilities
* `[api:Translatable]`: DataObject-interface powering the website-content translations
* ["Translatable ModelAdmin" module](http://silverstripe.org/translatablemodeladmin-module/): An extension which allows
translations of DataObjects inside `[api:ModelAdmin]`

342
docs/en/topics/widgets.md Normal file
View File

@ -0,0 +1,342 @@
# Widgets
## Introduction
Widgets are small pieces of functionality such as showing the latest Comments or Flickr Photos. They normally display on
the sidebar of your website. To check out a what a Widget can do watch the video http://silverstripe.org/widgets and try
out the demo site http://silverstripe.com/assets/screencasts/SilverStripe-Blog-DragDrop-Widgets.swf
## How to Use A Widget
### Downloading and Contributing Widgets
* To download widgets visit [Widgets section](http://silverstripe.org/widgets)
* Upload widgets you want to share to
[http://silverstripe.org/widgets/manage/add](http://silverstripe.org/widgets/manage/add). Make sure you read the
packaging instructions at the bottom of the page about how to make your widget package.
### Installing a widget
By following the "Packaging" rules below, widgets are easily installed.
* Download the file and unzip to the main folder of your SilverStripe website, e.g. to "/widget_twitter/". The folder
will contain a few files, which generally won't need editing or reading.
* Run dev/build
* Login to the CMS and go to the 'Blog' page. Choose the "widgets" tab and drag n drop the new widget to activate it.
* Your blog will now have the widget shown.
### Adding widgets to other pages
As of 2.2.1 this is this is a way to add widgets to other pages (by default only the Blog has widgets enabled). In the
future releases we will hopefully make widgets part of SiteTree therefore available on every page. In the mean time you
have to do a couple things to get a Widget to work on a page.
First step is to add an WidgetArea to the Database to store the widget details. Then you have to edit the CMS to add a
Widget Form to manage the widgets. An example of this is below
** mysite/code/Page.php **
:::php
class Page extends SiteTree {
...
static $has_one = array(
"Sidebar" => "WidgetArea",
);
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab("Root.Content.Widgets", new WidgetAreaEditor("Sidebar"));
return $fields;
}
....
}
Then in your Template you need to call $SideBar whereever you want to render the widget
Eg for blackcandy I put this above the closing `</div>`
** themes/myThemeName/templates/Includes/Sidebar.ss **
:::ss
$Sidebar
## Writing your own widgets
To create a Widget you need at least three files - a php file containing the class, a template file of the same name and
a config file called *_config.php* (if you dont need any config options for the widget to work then you can make it
blank). Each widget should be in its own folder like widgets_widgetName/
After installing or creating a new widget, **make sure to run db/build?flush=1** at the end of the URL, *before*
attempting to use it.
The class should extend the Widget class, and must specify three static variables - $title, the title that will appear
in the rendered widget (eg Photos), $cmsTitle, a more descriptive title that will appear in the cms editor (eg Flickr
Photos), and $description, a short description that will appear in the cms editor (eg This widget shows photos from
Flickr). The class may also specify functions to be used in the template like a page type can.
If a Widget has configurable options, then it can specify a number of database fields to store these options in via the
static $db array, and also specify a getCMSFields function that returns a !FieldSet, much the same way as a page type
does.
An example widget is below:
**FlickrWidget.php**
:::php
<?php
class FlickrWidget extends Widget {
static $db = array(
"User" => "Varchar",
"Photoset" => "Varchar",
"Tags" => "Varchar",
"NumberToShow" => "Int"
);
static $defaults = array(
"NumberToShow" => 8
);
static $title = "Photos";
static $cmsTitle = "Flickr Photos";
static $description = "Shows flickr photos.";
function Photos() {
Requirements::javascript("sapphire/thirdparty/prototype/prototype.js");
Requirements::javascript("sapphire/thirdparty/scriptaculous/effects.js");
Requirements::javascript("mashups/javascript/lightbox.js");
Requirements::css("mashups/css/lightbox.css");
$flickr = new FlickrService();
if($this->Photoset == "") {
$photos = $flickr->getPhotos($this->Tags, $this->User, $this->NumberToShow, 1);
} else {
$photos = $flickr->getPhotoSet($this->Photoset, $this->User, $this->NumberToShow, 1);
}
$output = new DataObjectSet();
foreach($photos->PhotoItems as $photo) {
$output->push(new ArrayData(array(
"Title" => $photo->title,
"Link" => "http://farm1.static.flickr.com/" . $photo->image_path .".jpg",
"Image" => "http://farm1.static.flickr.com/" .$photo->image_path. "_s.jpg"
)));
}
return $output;
}
function getCMSFields() {
return new FieldSet(
new TextField("User", "User"),
new TextField("PhotoSet", "Photo Set"),
new TextField("Tags", "Tags"),
new NumericField("NumberToShow", "Number to Show")
);
}
}
?>
**FlickrWidget.ss**
:::php
<% control Photos %>
<a href="$Link" rel="lightbox" title="$Title"><img src="$Image" alt="$Title" /></a>
<% end_control %>
## Extending and Customizing
### Rendering a $Widget Individually
To call a single Widget in a page - without adding a widget area in the CMS for you to add / delete the widgets, you can
define a merge variable in the Page Controller and include it in the Page Template.
This example creates an RSSWidget with the SilverStripe blog feed.
:::php
<?php
function SilverStripeFeed() {
$widget = new RSSWidget();
$widget->RssUrl = "http://feeds.feedburner.com/silverstripe-blog";
return $widget->renderWith("WidgetHolder");
}
?>
To render the widget, simply include $SilverStripeFeed in your template:
:::ss
$SilverStripeFeed
As directed in the definition of SilverStripeFeed(), the Widget will be rendered through the WidgetHolder template. This
is pre-defined at /sapphire/templates/WidgetHolder.ss and simply consists of:
:::ss
<div class="WidgetHolder">
<h3>$Title</h3>
$Content
</div>
You can override the WidgetHolder.ss and Widget.ss templates in your theme too by adding WidgetHolder and Widget
templates to ** themes/myThemeName/templates/Includes/ **
### Changing the title of your widget
To change the title of your widget, you need to override the Title() method. By default, this simply returns the $title
variable. For example, to set your widgets title to 'Hello World!', you could use:
** widgets_yourWidget/YourWidgetWidget.php **
:::php
function Title() {
return "Hello World!";
}
but, you can do exactly the same by setting your $title variable.
A more common reason for overriding Title() is to allow the title to be set in the CMS. Say you had a text field in your
widget called WidgetTitle, that you wish to use as your title. If nothing is set, then you'll use your default title.
This is similar to the RSS Widget in the blog module.
:::php
function Title() {
return $this->WidgetTitle ? $this->WidgetTitle : self::$title;
}
This returns the value inputted in the CMS, if it's set or what is in the $title variable if it isn't.
### Forms within Widgets
*Requires SilverStripe 2.4 or newer*
To implement a form inside a widget, you need to implement a custom controller for your widget to return this form. Make
sure that your controller follows the usual naming conventions, and it will be automatically picked up by the
`[api:WidgetArea]` rendering in your *Page.ss* template.
*mysite/code/MyWidget.php*
:::php
class MyWidget extends Widget {
static $db = array(
'TestValue' => 'Text'
);
}
class MyWidget_Controller extends Widget_Controller {
function MyFormName() {
return new Form(
$this,
'MyFormName',
new FieldSet(
new TextField('TestValue')
),
new FieldSet(
new FormAction('doAction')
)
);
}
function doAction($data, $form) {
// $this->widget points to the widget
}
}
To output this form, modify your widget template.
*mysite/templates/MyWidget.ss*
:::ss
$Content
$MyFormName
Note: The necessary controller actions are only present in subclasses of `[api:Page_Controller]`. To use
widget forms in other controller subclasses, have a look at *ContentController->handleWidget()* and
*ContentController::$url_handlers*.
See an [alternative recipe for SilverStripe 2.3 or earlier](http://doc.silverstripe.org/old/recipes/widget-forms-2.3).
## But what if I have widgets on my blog currently??
If you currently have a blog installed, the widget fields are going to double up on those pages (as the blog extends the
Page class). One way to fix this is to comment out line 30 in BlogHolder.php and remove the DB entry by running a
/db/build.
** blog/code/BlogHolder.php **
:::php
<?php
class BlogHolder extends Page {
........
static $has_one = array(
// "SideBar" => "WidgetArea", COMMENT OUT
'Newsletter' => 'NewsletterType'
.......
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->removeFieldFromTab("Root.Content.Main","Content");
// $fields->addFieldToTab("Root.Content.Widgets", new WidgetAreaEditor("SideBar")); COMMENT OUT
........
Then you can use the Widget area you defined on Page.php
## Releasing Your Widget
### Packaging
For a widget to be put in our official widget database they must follow this convention - If the name of your widget was
"TwitterWidget" then:
#### File Structure for your widget
You should have a folder called widget_YourName in the top level (the one with sapphire, cms..) with all your files. See
the example below. Your widget **MUST** have at least 1 Template file, 1 PHP file, the README File
[(Example)](http://open.silverstripe.com/browser/modules/widgets/twitter/trunk/README)and an _config.php file for
configuration. If you dont need any config options for the widget to work then you still need an _config.php by you can
make it blank
The decision over whether to configure a widget in _config.php or in the CMS is important:
* If the setting is the kind of thing that a website author, familiar with common business apps such as Word and
Outlook, would understand - then make it configurable in the CMS.
* If the setting is the kind of thing that the person setting up the website - doing the design and/or development -
would understand, then make it configurable in the _config.php file.
This way, the CMS remains an application designed for content authors, and not developers.
** widget_name/_config.php **
:::php
<?php /* */ ?>
** Example Widget Structure **
![](_images/widget_demo.gif)
#### How to make the Package
* Make a tar.gz file called widgets_flickr-0.1.tar.gz (where 0.1 is the version number).
* Ensure when you "unzip" the compressed file it has everything the "widgets_flickr" folder with everything inside
it.
* If made official, it will be given these locations at silverstripe.com:
* SVN location: http://svn.silverstripe.com/open/modules/widgets/flickr/trunk
* Official download: http://www.silverstripe.com/assets/downloads/widgets/widgets_flickr-0.1.1.tar.gz

View File

@ -0,0 +1,480 @@
# Tutorial 1 - Building a Basic Site
## Overview
Welcome to the first in this series of tutorials on the SilverStripe Content Management System (CMS).
These tutorials are designed to take you from an absolute beginner to being able to build large, complex websites with
SilverStripe. We assume to begin with, that you have some XHTML, CSS and PHP knowledge. This first tutorial provides an absolute
introduction to building a simple website using SilverStripe. It will also teach you how to use the content management system at a basic level.
## What are we working towards?
We are going to create a site in which all the content can be edited in the SilverStripe CMS. It will have a two-level
navigation system, which will be generated on the fly to include all pages you add in the CMS. We will use two different
templates - one for the home page, and one for the rest of the site.
![](_images/home-small.png)![](_images/menu-two-level-small.png)
## Installation
You need to [download the SilverStripe software](http://www.silverstripe.org/stable-download) and install it to your local
machine or to a webserver.
For more infomation about installing and configuring a webserver read the [Installation instructions and videos](../installation).
If you want to follow this tutorial please choose "empty template" when installing SilverStripe. If you want a fully
featured theme then select the 'BlackCandy' option.
## Exploring the installation
After installation, open up the folder where you installed SilverStripe. If you installed on windows with WAMP, it will
likely be at *c:\wamp\wwww*.
Let's have a look at the folder structure.
| Directory | | Description |
| --------- | | ----------- |
| assets/ | | Contains images and other files uploaded via the SilverStripe CMS. You can also place your own content inside it, and link to it from within the content area of the CMS. |
| cms/ | | Contains all the files that form the CMS area of your site. Its structure is similiar to the mysite/ directory, so if you find something interesting, it should be easy enough to look inside and see how it was built. |
| sapphire/ | | The framework that builds both your own site and as the CMS that powers it. Youll be utilizing files in this directory often, both directly and indirectly. |
| mysite/ | | Contains all your sites code (mainly PHP and JavaScript) |
| themes/ | | Combines all images, stylesheets and templates powering your website into a reusable "theme" |
When designing your site you should only need to modify the *mysite*, *themes* and *assets* folders. The rest of the folders contain files and data that are not specific to any site.
## Using the CMS
The CMS is the area in which you can manage your site content. You can access the cms at http://localhost/admin. You
will be presented with a login screen. You can login with the details you provided at installation. After logging in you
should be greeted with the CMS, pictured below (we've entered some test content).
![](_images/cms-numbered.png)
1. These buttons allow you to move between the different sections in the CMS. There are three core sections in the CMS - Site Content, Files & Images and Security. Modules may have their own sections here as well, if any are installed. In this tutorial we will be focusing on the Site Content section.
2. All the pages in the site are laid out in the site tree. You can add, delete and reorganize the pages using the buttons at the top. Clicking on a page will open it in the editor on the right.
3. This section allows you to edit the content for the currently selected page, as well as changing other properties of the page such as the page name and URL. The content editor has full [WYSIWYG](http://en.wikipedia.org/wiki/WYSIWYG) abilities, allow you to change formatting and insert links, images and tables.
4. There are two copies of each page: draft & published. These buttons allow you to save your changes to the draft copy, publish your draft copy, or revert your draft copy to the published copy. By having separate draft & published copies, we can preview draft changes in the site before publishing them to the live site.
5. The navigator will open the current page in the CMS, the draft site, or the published site.
### Try it
There are three pages already created for you - "Home", "About Us" and "Contact Us", as well as a 404 page. Experiment
with the editor - try different formatting, tables and images. When you are done, click "Save" to save the page or "Save
& Publish" to post the content to the live site. In our screenshot we've entered some test content.
> Don't worry that we currently have no way of navigating from page to page without using the CMS - we will build a navigation system soon.
When you create a new page, you are given a drop down that allows you to select the page type of the page. The page type
specifies the templates used to render the page, the fields that are able to be edited in the CMS, and page specific
behavior. We will explain page types in more depth as we progress; for now, make all pages of the type "Page".
![](_images/home-first.png)
**SilverStripe's virtual URLs**
While you are on the draft or live SilverStripe site, you may notice the URLs point to files that don't exist, e.g.
http://localhost/contact. SilverStripe uses the URL field on the Meta-Data tab of the editor to look up the appropriate
page in the database.
![](_images/url.png)
When you create a new page, SilverStripe automatically creates an appropriate URL for it. For example, *About Us* will
become *about-us*. You are able to change it yourself so that you can make long titles more usable or descriptive. For
example, *Employment Opportunities* could be shortened to *jobs*. The ability to generate easy to type, descriptive URLs
for SilverStripe pages improves accessibility for humans and search engines.
You should ensure the URL for the home page is *home*. By default, SilverStripe loads the page with the URL *home*.
## Templates
All pages on a SilverStripe site are rendered using a template. A template is an HTML file augmented with special
control codes. Because of this, you can have as much control of your sites HTML code as you like.
Every page in your site has a **page type**. We will briefly talk about page types later, and go into much more detail
in tutorial two; right now all our pages will be of the page type *Page*. When rendering a page, SilverStripe will look
for a template file in the *tutorial/templates* folder, with the name `<PageType>`.ss - in our case *Page.ss*.
Open *themes/tutorial/templates/Page.ss*. It uses standard HTML with three exceptions: `<% base_tag %>`, *$Content* and
*$SilverStripeNavigator*. These template markers are processed by SilverStripe into HTML before being sent to your
browser.
`<% base_tag %>` is replaced with the HTML [base element](http://www.w3.org/TR/html401/struct/links.html#h-12.4). This
ensures the browser knows where to locate your site's images and css files.
*$Content* is replaced with the content of the page currently being viewed. This allows you to make all changes to
your site's content in the CMS.
*$SilverStripeNavigator* inserts the HTML for the navigator at the bottom of the page, which allows you to move
quickly between the CMS and the draft and published version of your page.
![The SilverStripe Navigator](_images/navigator.png)
**Flushing the cache**
Whenever we edit a template file, we need to append *?flush=1* onto the end of the URL, e.g.
http://localhost/home/?flush=1. SilverStripe stores template files in a cache for quicker load times. Whenever there are
changes to the template, we must flush the cache in order for the changes to take effect.
## Inserting the page title
Let's introduce two new template variables - *$Title* and *$MetaTags*.
*$Title* is simply replaced with the name of the page ('Page name' on the 'Main' tab in the editor).
Open *themes/tutorial/templates/Page.ss* and find the following code:
:::ss
<div id="Header">
<h1>&nbsp;</h1>
</div>
and replace it with
:::ss
<div id="Header">
<h1>$Title</h1>
</div>
*$MetaTags* adds meta tags for search engines, as well as the page title ('Title' on the 'Meta-data' tab in the
editor). You can define your metatags in the meta-data tab off the content editor in the CMS.
Add *$MetaTags* to the head so that it looks like this:
:::ss
<head>
<% base_tag %>
$MetaTags
<% require themedCSS(layout) %>
<% require themedCSS(typography) %>
<% require themedCSS(form) %>
</head>
> Don't forget to flush the cache each time you change a template by adding *?flush=1* onto the end of the URL.
Your page should now look something like this (with your own content of course):
![](_images/title.png)
## Making a Navigation System
So far we have made several pages, but we have no way to navigate between them. We can create a menu for our site using
a **control block**. Control blocks allow us to iterate over a data set, and render each item using a sub-template. The
**page control** *Menu(1)* returns the set of the first level menu items. We can then use the template variable
*$MenuTitle* to show the title of the page we are linking to.
Open up *themes/tutorial/templates/Page.ss*, and insert the following code inside `<div id="Main">`:
:::ss
<ul id="Menu1">
<% control Menu(1) %>
<li><a href="#">$MenuTitle</a></li>
<% end_control %>
</ul>
Here we've created an unordered list called *Menu1*, which *themes/tutorial/css/layout.css* will style into the menu.
Then, using a control block over the page control *Menu(1)*, we add a link to the list for each menu item.
All going to plan, your page should look like this:
![](_images/menu.png)
The menu isn't really very useful until each button links to the relevant page. We can get the link for the menu item in
question by using the *$Link* template variable.
Replace the list item line with this one:
:::ss
<li><a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a></li>
> $Title refers to *Page Name* in the CMS, whereas $MenuTitle refers to (the often shorter) *Navigation label*
## Highlighting the current page
A useful feature is highlighting the current page the user is looking at. We can do this with the template variable
*$LinkingMode*. *$LinkingMode* returns one of three values:
* *current* - This page is being visited, and should be highlighted
* *link* - The page is not currently being visited, so shouldn't be highlighted
* *section* - A page under this page is being visited so you probably want to highlight it.
> For example: if you were visiting a staff member such as "Home > Company > Staff > Bob Smith", you would want to highlight 'Company' to say you are in that section.
Highlighting the current page is easy, simply assign a css class based on the value of *$LinkingMode*. Then provide a different style for current/section in css, as has been provided for you in *tutorial/css/layout.css*.
Change the list item line in *Page.ss* so it looks like this:
:::ss
<li class="$LinkingMode">
<a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a>
</li>
You should now have a fully functional top menu
![](_images/menu-highlighted.png)
## Adding a second level
Although we have a fully functional navigation system, it is currently quite restrictive. Currently there is no way to
nest pages, we have a completely flat site. Adding a second level in SilverStripe is easy. First, let's add some pages. The "About Us" section could use some expansion.
Select "About Us", and create two new pages "What we do" and "Our History" of the type "Page" inside. You can also create the pages elsewhere on the site tree, and use the reorganize button to drag and drop the pages into place.
Either way, your site tree should now look something like this:
![](_images/2nd_level-cut.png)
Great, we now have a hierarchical site structure, but we still have no way of getting to these second level pages.
Adding a second level menu is very similar to adding the first level menu.
Open up our *Page.ss* template, and find the `<div id="ContentContainer">` tag. Underneath it, add the following code:
:::ss
<ul id="Menu2">
<% control Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a></li>
<% end_control %>
</ul>
This should look very familiar. It is exactly the same as our first menu, except we have named our linked list *Menu2*
and we are using the control *Menu(2)* instead of *Menu(1)*. As we can see here, the *Menu* control takes a single
argument - the level of the menu we want to get. Our css file will style this linked list into the second level menu,
using our usual *$LinkingMode* technique to highlight the current page.
We now have our second level menu, but we also have a problem. The menu is displayed on every page, even those that
don't have any nested pages. We can solve this problem with an **if block**. Simply surround the menu with an if block
like this:
:::ss
<% if Menu(2) %>
<ul id="Menu2">
<% control Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
The if block only includes the code inside it if the condition is true. In this case, it checks for the existence of
*Menu(2)*. If it exists then the code inside will be processed and the menu will be shown. Otherwise the code will not
be processed and the menu will not be shown.
Now that we have two levels of navigation, it would also be useful to include some "breadcrumbs".
Find *`<div id="Content" class="typography">`* and underneath it add:
:::ss
<div class="breadcrumbs">
$Breadcrumbs
</div>
Breadcrumbs are only useful on pages that aren't in the top level. We can ensure that we only show them if we aren't in
the top level with another if statement.
:::ss
<% if Level(2) %>
<div class="breadcrumbs">
$Breadcrumbs
</div>
<% end_if %>
The *Level* page control allows you to get data from the page's parents, eg if you used *Level(1)*, you could use
*$Level(1).Title* to get the top level page title. In this case, we merely use it to check the existence of a second
level page; if one exists then we include the breadcrumbs.
We now have a fully functioning two level navigation system. Both menus should be updating and highlighting as you move
from page to page. They will also mirror changes done in the SilverStripe CMS, such as renaming pages or moving them
around.
![](_images/menu-two-level.png)
## Using a different template for the home page
So far, a single template *Page.ss* is being used for the entire site. This is useful for the purpose of this
tutorial, but in a finished website we can expect there to be several page layouts.
To illustrate how we do this, we will create a new template for the homepage. This template will have a large graphical
banner to welcome visitors.
### Creating a new page type
Earlier we stated that every page in a SilverStripe site has a **page type**, and that SilverStripe will look for a
template corresponding to the page type. Therefore, the first step to get the homepage using a different template is to
create a new page type.
Each page type is represented by two php classes: a *data object* and a *controller*. Don't worry about the details of page
types right now, we will go into much more detail in tutorial two.
Create a new file *HomePage.php* in *mysite/code*. Copy the following code into it:
:::php
<?php
/**
* Defines the HomePage page type
*/
class HomePage extends Page {
static $db = array(
);
static $has_one = array(
);
}
class HomePage_Controller extends Page_Controller {
}
Every page type also has a database table corresponding to it. Every time we modify the database, we need to rebuild it.
We can do this by going to [http://localhost/dev/build?flush=1](http://localhost/dev/build?flush=1). It may take a
moment, so be patient. This add tables and fields needed by your site, and modifies any structures that have changed. It
does this non-destructively - it will never delete your data.
As we have just created a new page type, SilverStripe will add this to the list of page types in the database.
### Changing the page type of the Home page
After building the database, we can change the page type of the homepage in the CMS.
Under the "Behaviour" tab. Change it to *HomePage*, and click "Save Draft" and "Publish".
![](_images/homepage-type.png)
Our homepage is now of the page type *HomePage*. However, even though it is of the *HomePage* page type, it is still
rendered with the *Page* template. SilverStripe still renders the homepage using the *Page* template because when we
created the *HomePage* page type, we inherited from *Page*. So when SilverStripe cannot find a *HomePage* template, it
will use the *Page* template. SilverStripe always attempts to use the most specific template first, and then falls back
to the template of the page type's parents.
### Creating a new template
To create a new template, create a copy of *Page.ss* (found in *themes/tutorial/templates*) and call it *HomePage.ss*. If we flush the cache (*?flush=1*), SilverStripe should now be using *HomePage.ss* for the homepage, and *Page.ss* for the rest of the site. Now let's customize the *HomePage* template.
First, remove the breadcrumbs and the secondary menu; we don't need them for the homepage. Let's replace the title with our image. Add this line above the *Content* div:
:::ss
<div id="Banner">
<img src="themes/tutorial/images/welcome.png" alt="Homepage image" />
</div>
![](_images/home-template.png)
### Using a subtemplate
Having two templates is good, but we have a lot of identical code in the two templates. Rather than having two
completely separate templates, we can use subtemplates to specify only the part of the template that has changed.
If we compare *Page.ss* and *HomePage.ss*, we can see the only differences are within the *ContentContainer* div.
Copy the contents of the *ContentContainer* div from *themes/tutorial/templates/Page.ss* to a new file
*themes/tutorial/templates/Layout/Page.ss*, and do the same from *themes/tutorial/templates/HomePage.ss* to
*themes/tutorial/templates/Layout/HomePage.ss*.
The files should look like this:
**themes/tutorial/templates/Layout/Page.ss**
:::ss
<% if Menu(2) %>
<ul id="Menu2">
<% control Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
<div id="Content" class="typography">
<% if Level(2) %>
<div class="breadcrumbs">
$Breadcrumbs
</div>
<% end_if %>
$Content
$Form
</div>
**themes/tutorial/templates/Layout/HomePage.ss**
:::ss
<div id="Banner">
<img src="themes/tutorial/images/welcome.png" alt="Homepage image" />
</div>
<div id="Content" class="typography">
$Content
</div>
We can then delete *themes/tutorial/templates/HomePage.ss*, as it is no longer needed.
Replace the code we just copied out of *themes/tutorial/templates/Page.ss* with *$Layout*, so it looks like this:
**themes/tutorial/templates/Page.ss**
:::ss
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
<head>
<% base_tag %>
$MetaTags
<% require themedCSS(layout) %>
<% require themedCSS(typography) %>
<% require themedCSS(form) %>
</head>
<body>
<div id="Main">
<ul id="Menu1">
<% control Menu(1) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a></li>
<% end_control %>
</ul>
<div id="Header">
<h1>$Title</h1>
</div>
<div id="ContentContainer">
$Layout
</div>
<div id="Footer">
<span>Visit <a href="http://www.silverstripe.com" title="Visit www.silverstripe.com">www.silverstripe.com</a> to download the CMS</span>
</div>
</div>
$SilverStripeNavigator
</body>
</html>
> As you have just done a few template changes, remember to add *?flush=1* in your URL to flush the cache so see your changes in the browser
SilverStripe first searches for a template in the *themes/tutorial/templates* folder. Since there is no *HomePage.ss*,
it will use the *Page.ss* for both *Page* and *HomePage* page types. When it comes across the *$Layout* tag, it will
then descend into the *themes/tutorial/templates/Layout* folder, and will use *Page.ss* for the *Page* page type, and
*HomePage.ss* for the *HomePage* page type.
![](_images/subtemplates-diagram.png)
## Summary
Starting from a basic template, we have introduced template variables, controls and if blocks, and we have used these
to build a basic but fully functional site. You have also been briefly introduced to page types, and seen how they
correspond to templates and subtemplates. By using these templates, you have seen how to customize the site content
according to the page type of the page you are displaying.
In the next tutorial, [Extending a Basic Site](2-extending-a-basic-site), we will explore page types on a
deeper level, and see how you can customize your own page types to extend SilverStripe to do much more interesting
things.
[Next Tutorial >>](2-extending-a-basic-site)
## Books on SilverStripe
* [Official book on SilverStripe in English](http://www.silverstripe.org/silverstripe-book).
* [Official book on SilverStripe in German](http://www.silverstripe.org/das-silverstripe-buch).
![](_images/silverstripe-cms-book-front-cover-design-june2009preview.png)

View File

@ -0,0 +1,687 @@
# 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.png)![](_images/einstein-small.png)
## 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.png)
## 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
<?php
/**
* Defines the ArticlePage page type
*/
class ArticlePage extends Page {
static $db = array(
);
static $has_one = array(
);
}
class ArticlePage_Controller extends Page_Controller {
}
?>
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
<?php
/**
* Defines the ArticleHolder page type
*/
class ArticleHolder extends Page {
static $db = array(
);
static $has_one = array(
);
static $allowed_children = array('ArticlePage');
}
class ArticleHolder_Controller extends Page_Controller {
}
?>
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
<?php
class ArticlePage extends Page {
static $db = array(
'Date' => '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
<?php
class ArticlePage extends Page {
// ...
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Content.Main', new DateField('Date'), 'Content');
$fields->addFieldToTab('Root.Content.Main', 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:FieldSet]` object.
:::php
$fields->addFieldToTab('Root.Content.Main', new DateField('Date'), 'Content');
$fields->addFieldToTab('Root.Content.Main', 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.Main" 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.png)
## 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
<?php
class ArticlePage extends Page {
// .....
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Content.Main', $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.Main', new TextField('Author','Author Name'), 'Content');
return $fields;
}
Let's walk through these changes.
:::php
$fields->addFieldToTab('Root.Content.Main', $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.Main', 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) %>
<ul id="Menu2">
<% control Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the $Title page">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
<div id="Content" class="typography">
<% if Level(2) %>
<div class="breadcrumbs">
$Breadcrumbs
</div>
<% end_if %>
<h1>$Title</h1>
$Content
<div class="newsDetails">
Posted on $Date.Nice by $Author
</div>
</div>
The first block of code is our regular second level menu; we also have our regular breadcrumbs code here. We will see
how to remove these blocks of repetitive code in a bit.
We use *$Date* and *$Author* to access the new fields. In fact, all template variables and page controls come from
either the data object or the controller for the page being displayed. The *$Breadcrumbs* variable comes from the
*Breadcrumbs()* method of the `[api:SiteTree]` class. *$Date* and *$Author* come from the *Article* table through
your data object. *$Content* comes from the *SiteTree* table through the same data object. The data for your page is
spread across several tables in the database matched by id - e.g. *Content* is in the *SiteTree* table, and *Date* and
*Author* are in the *Article* table. SilverStripe matches these records by their ids and collates them into the single
data object.
![](_images/data-collation.png)
Rather than using *$Date* directly, we use *$Date.Nice*. If we look in the `[api:Date]` documentation, we can see
that the *Nice* function returns the date in *dd/mm/yyyy* format, rather than the *yyyy-mm-dd* format stored in the
database.
![](_images/news.png)
Now we'll create a template for the article holder: we want our news section to show a list of news items, each with a
summary.
**themes/tutorial/templates/Layout/ArticleHolder.ss**
:::ss
<div id="Content" class="typography">
$Content
<ul id="NewsList">
<% control Children %>
<li class="newsDateTitle"><a href="$Link" title="Read more on &quot;{$Title}&quot;">$Title</a></li>
<li class="newsDateTitle">$Date.Nice</li>
<li class="newsSummary">$Content.FirstParagraph <a href="$Link" title="Read more on &quot;{$Title}&quot;">Read more &gt;&gt;</a></li>
<% end_control %>
</ul>
</div>
Here we use the page control *Children*. As the name suggests, this control allows you to iterate over the children of a
page, which in this case is our news articles. The *$Link* variable will give the address of the article which we can
use to create a link, and the *FirstParagraph* function of the `[api:HTMLText]` field gives us a nice summary of the
article.
![](_images/articleholder.png)
Remember that the visual styles are not part of the CMS, they are defined in the tutorial CSS file.
### Using include files in templates
The second level menu is something we want in most, but not all, pages so we can't put it in the base template. By
putting it in a separate file in the *tutorial/templates/Includes* folder, we can use `<% include templatename %>` to
include it in our other templates. Separate the second level menu into a new file *themes/tutorial/templates/Includes/Menu2.ss*.
**themes/tutorial/templates/Includes/Menu2.ss**
:::ss
<% if Menu(2) %>
<ul id="Menu2">
<% control Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the $Title page">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
And then replace the second level menu with `<% include Menu2 %>` in *Page.ss* and *ArticlePage.ss* like so:
**themes/tutorial/templates/Layout/Page.ss**, **themes/tutorial/templates/Layout/ArticlePage.ss**
:::ss
<% include Menu2 %>
<div id="Content" class="typography">
...
Do the same with the breadcrumbs:
**themes/tutorial/templates/Includes/Breadcrumbs.ss**
:::ss
<% if Level(2) %>
<div class="breadcrumbs">
$Breadcrumbs
</div>
<% end_if %>
**themes/tutorial/templates/Layout/Page.ss**, **themes/tutorial/templates/Layout/ArticlePage.ss**
:::ss
...
<div id="Content" class="typography">
<% include Breadcrumbs %>
...
You can make your templates more modular and easier to maintain by separating commonly-used pieces into include files.
### Changing the icons of pages in the CMS
Let's now make a purely cosmetic change that nevertheless helps to make the information presented in the CMS clearer.
Add the following field to the *ArticleHolder* and *ArticlePage* classes:
:::php
static $icon = "themes/tutorial/images/treeicons/news";
And this one to the *HomePage* class:
:::php
static $icon = "themes/tutorial/images/treeicons/home";
This will change the icons for the pages in the CMS.
> Note: that the corresponding filename to the path given for $icon will end with **-file.gif**,
> e.g. when you specify **news** above, the filename will be **news-file.gif**.
![](_images/icons2.png)
### Allowing comments on news articles
A handy feature built into SilverStripe is the ability for guests to your site to leave comments on pages. We can turn
this on for an article simply by ticking the box in the behaviour tab of a page in the CMS. Enable this for all your
*ArticlePage*s.
![](_images/comments.png)
We then need to include *$PageComments* in our template, which will insert the comment form as well as all comments left
on the page.
**themes/tutorial/templates/Layout/ArticlePage.ss**
:::html
...
<div class="newsDetails">
Posted on $Date.Nice by $Author
</div>
$PageComments
...
You should also prepare the *Page* template in the same manner, so comments can be enabled at a later point on any page.
![](_images/news-comments.png)
It would be nice to have comments on for all articles by default. We can do this with the *$defaults* array. Add this to
the *ArticlePage* class:
:::php
static $defaults = array(
'ProvideComments' => true
);
You can set defaults for any of the fields in your data object. *ProvideComments* is defined in *SiteTree*, so it is
part of our *ArticlePage* data object.
## Showing the latest news on the homepage
It would be nice to greet page visitors with a summary of the latest news when they visit the homepage. This requires a
little more code though - the news articles are not direct children of the homepage, so we can't use the *Children*
control. We can get the data for the news articles by implementing our own function in *HomePage_Controller*.
**mysite/code/HomePage.php**
:::php
...
function LatestNews($num=5) {
$news = DataObject::get_one("ArticleHolder");
return ($news) ? DataObject::get("ArticlePage", "ParentID = $news->ID", "Date DESC", "", $num) : false;
}
...
This function simply runs a database query that gets the latest news articles from the database. By default, this is
five, but you can change it by passing a number to the function. See the `[api:DataObject]` documentation for
details. We can reference this function as a page control in our *HomePage* template:
**themes/tutorial/templates/Layout/Homepage.ss**
:::ss
...
$Content
<ul id="NewsList">
<% control LatestNews %>
<li class="newsDateTitle"><a href="$Link" title="Read more on &quot;{$Title}&quot;">$Title</a></li>
<li class="newsDateTitle">$Date.Nice</li>
<li class="newsSummary">$Content.FirstParagraph<a href="$Link" title="Read more on &quot;{$Title}&quot;">Read more &gt;&gt;</a></li>
<% end_control %>
</ul>
...
When SilverStripe comes across a variable or page control it doesn't recognize, it first passes control to the
controller. If the controller doesn't have a function for the variable or page control, it then passes control to the
data object. If it has no matching functions, it then searches its database fields. Failing that it will return nothing.
The controller for a page is only created when page is actually visited, while the data object is available when the
page is referenced in other pages, e.g. by page controls. A good rule of thumb is to put all functions specific to the
page currently being viewed in the controller; only if a function needs to be used in another page should you put it in
the data object.
![](_images/homepage-news.png)
## Creating a RSS feed
An RSS feed is something that no news section should be without. SilverStripe makes it easy to create RSS feeds by
providing an `[api:RSSFeed]` class to do all the hard work for you. Create the following function in the
*ArticleHolder_Controller*:
:::php
function rss() {
$rss = new RSSFeed($this->Children(), $this->Link(), "The coolest news around");
$rss->outputToBrowser();
}
This function simply creates an RSS feed of all the news articles, and outputs it to the browser. If you go to
[http://localhost/news/rss](http://localhost/news/rss) you will see our RSS feed. What happens here is that
when there is more to a URL after the page's base URL - "rss" in this case - SilverStripe will call the function with
that name on the controller if it exists.
Depending on your browser, you should see something like the picture below. If your browser doesn't support RSS, you
will most likely see the XML output instead.
![](_images/rss-feed.png)
Now all we need is to let the user know that our RSS feed exists. The `[api:RSSFeed]` in your controller, it will be
called when the page is requested. Add this function to *ArticleHolder_Controller*:
:::php
function init() {
RSSFeed::linkToFeed($this->Link() . "rss");
parent::init();
}
This automatically generates a link-tag in the header of our template. The *init* function is then called on the parent
class to ensure any initialization the parent would have done if we hadn't overridden the *init* function is still
called. In Firefox you can see the RSS feed link in the address bar:
![](_images/rss.png)
## Adding a staff section
Now that we have a complete news section, let's move on to the staff section. We need to create *StaffHolder* and
*StaffPage* page types, for an overview on all staff members and a detail-view for a single member. First let's start
with the *StaffHolder* page type.
**mysite/code/StaffHolder.php**
:::php
<?php
class StaffHolder extends Page {
static $db = array(
);
static $has_one = array(
);
static $allowed_children = array('StaffPage');
}
class StaffHolder_Controller extends Page_Controller {
}
Nothing here should be new. The *StaffPage* page type is more interesting though. Each staff member has a portrait
image. We want to make a permanent connection between this image and the specific *StaffPage* (otherwise we could simply
insert an image in the *$Content* field).
**mysite/code/StaffPage.php**
:::php
<?php
class StaffPage extends Page {
static $db = array(
);
static $has_one = array(
'Photo' => 'Image'
);
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab("Root.Content.Images", new ImageField('Photo'));
return $fields;
}
}
class StaffPage_Controller extends Page_Controller {
}
Instead of adding our *Image* as a field in *$db*, we have used the *$has_one* array. This is because an *Image* is not
a simple database field like all the fields we have seen so far, but has its own database table. By using the *$has_one*
array, we create a relationship between the *StaffPage* table and the *Image* table by storing the id of the respective
*Image* in the *StaffPage* table.
We then add an *ImageField* in the *getCMSFields* function to the tab "Root.Content.Images". Since this tab doesn't exist,
the *addFieldToTab* function will create it for us. The *ImageField* allows us to select an image or upload a new one in
the CMS.
![](_images/photo.png)
Rebuild the database ([http://localhost/dev/build?flush=1](http://localhost/dev/build?flush=1)) and open the CMS. Create
a new *StaffHolder* called "Staff" in the "About Us" section, and create some *StaffPage*s in it.
![](_images/create-staff.png)
### Creating the staff section templates
The staff section templates aren't too difficult to create, thanks to the utility methods provided by the *Image* class.
**themes/tutorial/templates/Layout/StaffHolder.ss**
:::ss
<% include Menu2 %>
<div id="Content" class="typography">
<% include Breadcrumbs %>
$Content
<ul id="StaffList">
<% control Children %>
<li>
<div class="staffname"><a href="$Link">$Title</a></div>
<div class="staffphoto">$Photo.SetWidth(50)</div>
<div class="staffdescription"><p>$Content.FirstSentence</p></div>
</li>
<% end_control %>
</ul>
</div>
This template is very similar to the *ArticleHolder* template. The *FirstSentence* method of the `[api:Text]` class
will resize the image before sending it to the browser. The resized image is cached, so the server doesn't have to
resize the image every time the page is viewed.
![](_images/staff-section.png)
The *StaffPage* template is also very straight forward.
**themes/tutorial/templates/Layout/StaffPage.ss**
:::ss
<% include Menu2 %>
<div id="Content" class="typography">
<% include Breadcrumbs %>
<div id="StaffPhoto">
$Photo.SetWidth(150)
</div>
$Content
</div>
Here we also use the *SetWidth* function to get a different sized image from the same source image. You should now have
a complete staff section.
![](_images/einstein.png)
## Summary
In this tutorial we have explored the concept of page types. In the process of creating and extending page types you
have been introduced to many of the concepts required to build a site with SilverStripe.
[Next Tutorial >>](3-forms)

View File

@ -0,0 +1,418 @@
# Tutorial 3 - Forms
## Overview
This tutorial is intended to be a continuation of the first two tutorials, and will build on the site produced in those
two tutorials.
This tutorial explores forms in SilverStripe. It will look at coded forms. Forms which need to be written in PHP.
Another method which allows you to construct forms via the CMS is by using the [userforms module](http://silverstripe.org/user-forms-module).
A UserDefinedForm is much quicker to implement, but lacks the flexibility of a coded form.
## What are we working towards?
We will create a poll on the home page that asks the user their favourite web browser, and displays a bar graph of the
results.
![tutorial:pollresults-small.png](_images/pollresults-small.png)
## Creating the form
We will be creating a form for a poll on the home page.
The poll will ask the user's name and favourite web browser, and then collate the results into a bar graph. We create
the form in a method on *HomePage_Controller*.
*mysite/code/HomePage.php*
:::php
class HomePage_Controller extends Page_Controller {
// ...
function BrowserPollForm() {
// Create fields
$fields = new FieldSet(
new TextField('Name'),
new OptionsetField('Browser', 'Your Favourite Browser', array(
'Firefox' => 'Firefox',
'Chrome' => 'Chrome',
'Internet Explorer' => 'Internet Explorer',
'Safari' => 'Safari',
'Opera' => 'Opera',
'Lynx' => 'Lynx'
))
);
// Create actions
$actions = new FieldSet(
new FormAction('doBrowserPoll', 'Submit')
);
return new Form($this, 'BrowserPollForm', $fields, $actions);
}
...
}
...
Let's step through this code.
:::php
// Create fields
$fields = new FieldSet(
new TextField('Name'),
new OptionsetField('Browser', 'Your Favourite Browser', array(
'Firefox' => 'Firefox',
'Chrome' => 'Chrome',
'Internet Explorer' => 'Internet Explorer',
'Safari' => 'Safari',
'Opera' => 'Opera',
'Lynx' => 'Lynx'
))
);
First we create our form fields.
We do this by creating a `[api:FieldSet]` and passing our fields as arguments. The first field is a new
`[api:TextField]` with the name 'Name'.
There is a second argument when creating a field which specifies the text on the label of the field. If no second
argument is passed, as in this case, it is assumed the label is the same as the name of the field.
The second field we create is an `[api:OptionsetField]`. This is a dropdown, and takes a third argument - an
array mapping the values to the options listed in the dropdown.
:::php
$actions = new FieldSet(
new FormAction('doBrowserPoll', 'Submit');
);
After creating the fields, we create the form actions. Form actions appear as buttons at the bottom of the form.
The first argument is the name of the function to call when the button is pressed, and the second is the label of the
button.
Here we create a 'Submit' button which calls the 'doBrowserPoll' method, which we will create later.
All the form actions (in this case only one) are collected into a `[api:FieldSet]` object the same way we did with
the fields.
:::php
return new Form($this, 'BrowserPollForm', $fields, $actions);
Finally we create the `[api:Form]` object and return it.
The first argument is the controller that contains the form, in most cases '$this'. The second is the name of the method
that returns the form, which is 'BrowserPollForm' in our case. The third and fourth arguments are the
FieldSets containing the fields and form actions respectively.
After creating the form function, we need to add the form to our home page template.
Add the following code to the home page template, just before the Content `<div>`:
*themes/tutorial/templates/Layout/HomePage.ss*
:::ss
...
<div id="BrowserPoll">
<h2>Browser Poll</h2>
$BrowserPollForm
</div>
<div id="Content">
...
Add the following code to the form style sheet:
*themes/tutorial/css/form.css*
:::css
/* BROWSER POLL */
#BrowserPoll {
float: right;
margin: 20px 10px 0 0;
width: 20%;
}
form fieldset {
border:0;
}
#BrowserPoll .message {
display: block;
color:red;
background:#ddd;
border:1px solid #ccc;
padding:5px;
margin:5px;
}
#BrowserPoll h2 {
font-size: 1.5em;
color: #0083C8;
}
#BrowserPoll .field {
padding:3px 0;
}
#BrowserPoll .Actions {
padding:5px 0;
}
#BrowserPoll .bar {
background-color: #015581;
}
This CSS code will ensure that the form is formatted and positioned correctly. All going according to plan, if you visit
[http://localhost/home?flush=1](http://localhost/home?flush=1) it should look something like below.
![](_images/pollform.png)
## Processing the form
Great! We now have a browser poll form, but it doesn't actually do anything. In order to make the form work, we have to
implement the 'doBrowserPoll' method that we told it about.
First, we need some way of saving the poll submissions to the database, so we can retrieve the results later. We can do
this by creating a new object that extends from `[api:DataObject]`.
If you recall, in tutorial two we said that all objects that inherit from DataObject and that add fields are stored in
the database. Also recall that all pages extend DataObject indirectly through `[api:SiteTree]`. Here instead of
extending SiteTree (or `[api:Page]`) to create a page type, we extend DataObject directly.
*mysite/code/BrowserPollSubmission.php*
:::php
<?php
class BrowserPollSubmission extends DataObject {
static $db = array(
'Name' => 'Text',
'Browser' => 'Text'
);
}
If we then rebuild the database ([http://localhost/db/build?flush=1](http://localhost/db/build?flush=1)), we will see
that the *BrowserPollSubmission* table is created. Now we just need to define 'doBrowserPoll' on *HomePage_Controller*.
*mysite/code/HomePage.php*
:::php
class HomePage_Controller extends Page_Controller {
// ...
function doBrowserPoll($data, $form) {
$submission = new BrowserPollSubmission();
$form->saveInto($submission);
$submission->write();
Director::redirectBack();
}
}
A function that processes a form submission takes two arguments - the first is the data in the form, the second is the
`[api:Form]` object.
In our function we create a new *BrowserPollSubmission* object. Since the name of our form fields and the name of the
database fields are the same we can save the form directly into the data object.
We call the 'write' method to write our data to the database, and 'Director::redirectBack()' will redirect the user back
to the home page.
## Form validation
SilverStripe forms all have automatic validation on fields where it is logical. For example, all email fields check that
they contain a valid email address. You can write your own validation by subclassing the *Validator* class.
SilverStripe provides the *RequiredFields* validator, which ensures that the fields specified are filled in before the
form is submitted. To use it we create a new *RequiredFields* object with the name of the fields we wish to be required
as the arguments, then pass this as a fifth argument to the Form constructor.
Change the end of the 'BrowserPollForm' function so it looks like this:
** mysite/code/HomePage.php **
:::php
function BrowserPollForm() {
...
// Create validator
$validator = new RequiredFields('Name', 'Browser');
return new Form($this, 'BrowserPollForm', $fields, $actions, $validator);
}
If we then open the homepage and attempt to submit the form without filling in the required fields an error will be
shown.
![](_images/validation.png)
## Showing the poll results
Now that we have a working form, we need some way of showing the results.
The first thing to do is make it so a user can only vote once per session. If the user hasn't voted, show the form,
otherwise show the results.
We can do this using a session variable. The `[api:Session]` class handles all session variables in SilverStripe.
First modify the 'doBrowserPoll' to set the session variable 'BrowserPollVoted' when a user votes.
*mysite/code/HomePage.php*
:::php
...
HomePage_Controller extends Page_Controller {
...
function doBrowserPoll($data, $form) {
$submission = new BrowserPollSubmission();
$form->saveInto($submission);
$submission->write();
Session::set('BrowserPollVoted', true);
Director::redirectBack();
}
...
}
Then we simply need to check if the session variable has been set in 'BrowserPollForm()', and to not return the form if
it is.
:::php
function BrowserPollForm() {
if(Session::get('BrowserPollVoted')) {
return false;
}
...
If you visit the home page now you will see you can only vote once per session; after that the form won't be shown. You
can start a new session by closing and reopening your browser (or if you're using Firefox and have installed the [Web
Developer](http://chrispederick.com/work/web-developer/) extension, you can use its Clear Session Cookies command).
Although the form is not shown, you'll still see the 'Browser Poll' heading. We'll leave this for now: after we've built
the bar graph of the results, we'll modify the template to show the graph instead of the form if the user has already
voted.
We now need some way of getting the data from the database into the template.
In the second tutorial we got the latest news articles for the home page by using the 'DataObject::get' function. We
can't use the 'DataObject::get' function here directly as we wish to count the total number of votes for each browser.
By looking at the documentation for 'DataObject::get', we can see that it returns a `[api:DataObjectSet]`
object. In fact, all data that can be iterated over in a template with a page control is contained in a DataObjectSet.
A `[api:DataObjectSet]` is a set of not just DataObjects, but of ViewableData, which the majority of
SilverStripe's classes (including DataObject) inherit from. We can create a DataObjectSet, fill it with our data, and
then create our graph using a page control in the template. Create the function 'BrowserPollResults' on the
*HomePage_Controller* class.
** mysite/code/HomePage.php **
:::php
function BrowserPollResults() {
$submissions = DataObject::get('BrowserPollSubmission');
$total = $submissions->Count();
$doSet = new DataObjectSet();
foreach($submissions->groupBy('Browser') as $browser => $data) {
$percentage = (int) ($data->Count() / $total * 100);
$record = array(
'Browser' => $browser,
'Percentage' => $percentage
);
$doSet->push(new ArrayData($record));
}
return $doSet;
}
This introduces a few new concepts, so let's step through it.
:::php
$submissions = DataObject::get('BrowserPollSubmission');
First we get all of the *BrowserPollSubmission*s from the database. This returns the submissions as a
DataObjectSet, which contains the submissions as *BrowserPollSubmission* objects.
:::php
$total = $submissions->Count();
We get the total number of submissions, which is needed to calculate the percentages.
:::php
$doSet = new DataObjectSet();
foreach($submissions->groupBy('Browser') as $browser => $data) {
$percentage = (int) ($data->Count() / $total * 100);
$record = array(
'Browser' => $browser,
'Percentage' => $percentage
);
$doSet->push(new ArrayData($record));
}
Now we create an empty DataObjectSet to hold our data and then iterate over the 'Browser' submissions field. The 'groupBy'
method of DataObjectSet splits our DataObjectSet by the 'Browser' field passed to it. The percentage of submissions for each
browser is calculated using the size of the DataObjectSet. It puts these new DataObjectSets into an array indexed
by the value of the field. The `[api:ArrayData]` class wraps an array into a ViewableData object, so we finally create a new
ArrayData object, which we can add to our *$doSet* DataObjectSet of results.
:::php
return $doSet;
After we have iterated through all the browsers, the DataObjectSet contains all the results, which is then
returned.
The final step is to create the template to display our data. Change the 'BrowserPoll' div in
*themes/tutorial/templates/Layout/HomePage.ss* to the below.
:::ss
<div id="BrowserPoll">
<h2>Browser Poll</h2>
<% if BrowserPollForm %>
$BrowserPollForm
<% else %>
<ul>
<% control BrowserPollResults %>
<li>
<div class="browser">$Browser: $Percentage%</div>
<div class="bar" style="width:$Percentage%">&nbsp;</div>
</li>
<% end_control %>
</ul>
<% end_if %>
</div>
Here we first check if the *BrowserPollForm* is returned, and if it is display it. Otherwise the user has already voted,
and the poll results need to be displayed.
We use the normal tactic of putting the data into an unordered list and using CSS to style it, except here we use inline
styles to display a bar that is sized proportionate to the number of votes the browser has received. You should now have
a complete poll.
![](_images/pollresults.png)
## Summary
In this tutorial we have explored forms, and seen the different approaches to creating and using forms. Whether you
decide to use the [userforms module](http://silverstripe.org/user-forms-module) or create a form in PHP depends on the situation and flexibility
required.
[Next Tutorial >>](4-site-search)

View File

@ -0,0 +1,202 @@
# Tutorial 4 - Site Search
## Overview
This is a short tutorial demonstrating how to add search functionality to a SilverStripe site. It is recommended that
you have completed the earlier tutorials, especially the tutorial on forms, before attempting this tutorial. While this
tutorial will add search functionality to the site built in the previous tutorials, it should be straight forward to
follow this tutorial on any site of your own. If you are adding the search form to the tutorial site, please get
[this updated css file](http://doc.silverstripe.org/src/github/master/sapphire/docs/en/tutorials/_images/layout.css) and place it in *themes/tutorial/css* (as layout.css) and this
![search file tree icon](_images/search-file.gif) search file tree icon and place it in *themes/tutorial/images/treeicons* (as
search-file.gif).
## What are we working towards?
We are going to add a search box on the top of the page. When a user types something in the box, they are taken to a
results page.
![](_images/searchresults-small.png)
## Creating the search form
The Search Form functionality has been altered over time. Please use the section which applies to your SilverStripe
version.
### 2.4 and newer
SilverStripe 2.4 does not come bundled with the search engine enabled. To enable the search engine you need to include
the following code in your mysite/_config.php file
:::php
FulltextSearchable::enable();
After including that in your _config.php you will need to rebuild the database by visiting http://yoursite.com/dev/build
in your web browser. This will add the fulltext search columns.
The actual search form code is already provided in FulltextSearchable so when you add the enable line above to your
_config you can add your form as $SearchForm.
### 2.3
SilverStripe 2.3 came bundled with the code as well as a MySQL Search engine. If you are using the blackcandy theme you
should have everything you need already to have a search. If you are using the tutorial theme then you can simply skip
down to 'Adding the search form' as the PHP code is already provided in Page.php. If it is not then you can follow the
instructions below as well.
### 2.2
If you are using SilverStripe 2.2 or earlier then you need to define your own code. The first step in implementing
search on your site is to create a form for the user to type their query. Create a function named *SearchForm* on the
*Page_Controller* class (//mysite/code/Page.php//).
:::php
class Page_Controller extends ContentController {
function SearchForm() {
$searchText = isset($this->Query) ? $this->Query : 'Search';
$fields = new FieldSet(
new TextField("Search", "", $searchText)
);
$actions = new FieldSet(
new FormAction('results', 'Go')
);
return new SearchForm($this, "SearchForm", $fields, $actions);
}
}
## Adding the search form
We then just need to add the search form to the template. Add *$SearchForm* to the 'Header' div in
*themes/tutorial/templates/Page.ss*.
*themes/tutorial/templates/Page.ss*
:::ss
<div id="Header">
$SearchForm
<h1>$Title</h1>
</div>
![](_images/searchform.png)
## Showing the results
Next we need to create the *results* function.
*mysite/code/Page.php*
:::php
class Page_Controller extends ContentController {
...
function results($data, $form){
$data = array(
'Results' => $form->getResults(),
'Query' => $form->getSearchQuery(),
'Title' => 'Search Results'
);
$this->Query = $form->getSearchQuery();
return $this->customise($data)->renderWith(array('Page_results', 'Page'));
}
}
First we populate an array with the data we wish to pass to the template - the search results, query and title of the
page. The final line is a little more complicated.
When we call a function by its url (eg http://localhost/home/results), SilverStripe will look for a template with the
name `PageType_function.ss`. As we are implementing the *results* function on the *Page* page type, we create our
results page template as *Page_results.ss*. Unfortunately this doesn't work when we are using page types that are
children of the *Page* page type. For example, if someone used the search on the homepage, it would be rendered with
*Homepage.ss* rather than *Page_results.ss*. SilverStripe always looks for the template from the most specific page type
first, so in this case it would use the first template it finds in this list:
* HomePage_results.ss
* HomePage.ss
* Page_results.ss
* Page.ss
We can override this list by using the *renderWith* function. The *renderWith* function takes an array of the names of
the templates you wish to render the page with. Here we first add the data to the page by using the 'customise'
function, and then attempt to render it with *Page_results.ss*, falling back to *Page.ss* if there is no
*Page_results.ss*.
## Creating the template
Lastly we need to create the template for the search page. This template uses all the same techniques used in previous
tutorials. It also uses a number of pagination variables, which are provided by the `[api:DataObjectSet]`
class.
*themes/tutorial/templates/Layout/Page_results.ss*
:::ss
<div id="Content" class="searchResults">
<h2>$Title</h2>
<% if Query %>
<p class="searchQuery"><strong>You searched for &quot;{$Query}&quot;</strong></p>
<% end_if %>
<% if Results %>
<ul id="SearchResults">
<% control Results %>
<li>
<a class="searchResultHeader" href="$Link">
<% if MenuTitle %>
$MenuTitle
<% else %>
$Title
<% end_if %>
</a>
<p>$Content.LimitWordCountXML</p>
<a class="readMoreLink" href="$Link" title="Read more about &quot;{$Title}&quot;">Read more about &quot;{$Title}&quot;...</a>
</li>
<% end_control %>
</ul>
<% else %>
<p>Sorry, your search query did not return any results.</p>
<% end_if %>
<% if Results.MoreThanOnePage %>
<div id="PageNumbers">
<% if Results.NotLastPage %>
<a class="next" href="$Results.NextLink" title="View the next page">Next</a>
<% end_if %>
<% if Results.NotFirstPage %>
<a class="prev" href="$Results.PrevLink" title="View the previous page">Prev</a>
<% end_if %>
<span>
<% control Results.Pages %>
<% if CurrentBool %>
$PageNum
<% else %>
<a href="$Link" title="View page number $PageNum">$PageNum</a>
<% end_if %>
<% end_control %>
</span>
<p>Page $Results.CurrentPage of $Results.TotalPages</p>
</div>
<% end_if %>
</div>
Then finally add ?flush=1 to the URL and you should see the new template.
![](_images/searchresults.png)
## Summary
This tutorial has demonstrated how easy it is to have full text searching on your site. To add search to a SilverStripe
site, only a search form and a results page need to be created.
[Next Tutorial >>](5-dataobject-relationship-management)

View File

@ -0,0 +1,794 @@
# Tutorial 5 - Dataobject Relationship Management
## Overview
In the [second tutorial](2-extending-a-basic-site) we have learned how to add extrafields to a page type thanks
to the *$db* array and how to add an image using the *$has_one* array and so create a relationship between a table and
the *Image* table by storing the id of the respective *Image* in the first table. This tutorial explores all this
relations between [DataObjects](/topics/datamodel#relations) and the way to manage them easily.
## What are we working towards?
To simulate these relations between objects, we are going to simulate the management via the CMS of the **[Google Summer
Of Code 2007](http://www.silverstripe.com/google-summer-of-code-2007-we-are-in/)** that SilverStripe was part of.
To do this, we are gonna use the following objects :
* Project : Project on SilverStripe system for the GSOC
* Student : Student involved in the project
* Mentor : SilverStripe developer
* Module : Module used for the project
This is a table which sums up the relations between them :
| Project | Student | Mentor | Modules |
| ------- | ------- | ------ | ------------------
| i18n Multi-Language | Bernat Foj Capell | Ingo Schommer | Cms, Sapphire, i18n, Translation |
| Image Manipulation | Mateusz Ujma | Sam Minnee | Cms, Sapphire, ImageManipulation |
| Google Maps | Ofir Picazo Navarro | Hayden Smith | Cms, Sapphire, Maps |
| Mashups | Lakshan Perera | Matt Peel | Cms, Sapphire, MashUps |
| Multiple Databases | Philipp Krenn | Brian Calhoun | Cms, Sapphire, MultipleDatabases |
| Reporting | Quin Hoxie | Sam Minnee | Cms, Sapphire, Reporting |
| Security & OpenID | Markus Lanthaler | Hayden Smith | Cms, Sapphire, auth_openid |
| SEO | Will Scott | Brian Calhoun | Cms, Sapphire, googleadwords, googleanalytics |
| Usability | Elijah Lofgren | Sean Harvey | Cms, Sapphire, UsabilityElijah |
| Safari 3 Support | Meg Risen | Sean Harvey | Cms, Sapphire, UsabilityMeg |
## GSOC Projects
Before starting the relations management, we need to create a *ProjectsHolder* class where we will save the GSOC Project
pages.
*tutorial/code/ProjectsHolder.php*
:::php
<?php
class ProjectsHolder extends Page {
static $allowed_children = array( 'Project' );
}
class ProjectsHolder_Controller extends Page_Controller {
}
## Project - Student relation
**A project can only be done by one student.**
**A student has only one project.**
This relation is called a **1-to-1** relation.
The first step is to create the student and project objects.
*tutorial/code/Student.php*
:::php
<?php
class Student extends DataObject {
static $db = array(
'FirstName' => 'Text',
'Lastname' => 'Text',
'Nationality' => 'Text'
);
function getCMSFields_forPopup() {
$fields = new FieldSet();
$fields->push( new TextField( 'FirstName', 'First Name' ) );
$fields->push( new TextField( 'Lastname' ) );
$fields->push( new TextField( 'Nationality' ) );
return $fields;
}
}
*tutorial/code/Project.php*
:::php
<?php
class Project extends Page {
static $has_one = array(
'MyStudent' => 'Student'
);
}
class Project_Controller extends Page_Controller {}
This code will create a relationship between the *Project* table and the *Student* table by storing the id of the
respective *Student* in the *Project* table.
The second step is to add the table in the method *getCMSFields* which will allow you to manage the *has_one* relation.
:::php
class Project extends Page {
...
function getCMSFields() {
$fields = parent::getCMSFields();
$tablefield = new HasOneComplexTableField(
$this,
'MyStudent',
'Student',
array(
'FirstName' => 'First Name',
'Lastname' => 'Family Name',
'Nationality' => 'Nationality'
),
'getCMSFields_forPopup'
);
$tablefield->setParentClass('Project');
$fields->addFieldToTab( 'Root.Content.Student', $tablefield );
return $fields;
}
}
Lets walk through the parameters of the *HasOneComplexTableField* constructor.
1. **$this** : The first object concerned by the relation
2. **'MyStudent'** : The name of the second object of the relation
3. **'Student'** : The type of the second object of the relation
4. **array(...)** : The fields of the second object which will be in the table
5. **'getCMSFields_forPopup'** : The method which will be called to add, edit or only show a second object
You can also directly replace the last parameter by this code :
:::php
new FieldSet(
new TextField( 'FirstName', 'First Name' ),
new TextField( 'Lastname' ),
new TextField( 'Nationality' )
);
<div class="tip" markdown='1'>
Don't forget to rebuild the database using *dev/build?flush=1* before you
proceed to the next part of this tutorial.
</div>
Now that we have created our *Project* page type and *Student* data object, lets add some content.
Go into the CMS and create one *Project* page for each project listed [above](#what-are-we-working-towards) under a
*ProjectsHolder* page named **GSOC Projects** for instance.
![tutorial:gsoc-project-creation.png](_images/gsoc-project-creation.png)
As you can see in the tab panel *Student*, the adding functionality is titled *Add Student*. However, if you want to
modify this title, you have to add this code in the *getCMSFields* method of the *Project* class :
:::php
$tablefield->setAddTitle( 'A Student' );
Select now one of the *Project* page that you have created, go in the tab panel *Student* and add all the students
listed [above](#what-are-we-working-towards) by clicking on the link **Add A Student** of your
*HasOneComplexTableField* table.
![tutorial:gsoc-student-creation.png](_images/gsoc-student-creation.png)
After having added all the students, you will see that, in the tab panel *Student* of all the *Project* pages, the
*HasOneComplexTableField* tables have the same content.
For each *Project* page, you can now affect **one and only one** student to it ( see the
[list](#What_are_we_working_towards?) ).
![tutorial:gsoc-project-student-selection.png](_images/gsoc-project-student-selection.png)
You will also notice, that you have the possibility to **unselect** a student which will make your *Project* page
without any student affected to it.
**At the moment, the *HasOneComplexTableField* table doesn't manage totally the *1-to-1* relation because you can easily
select the same student for two ( or more ) differents *Project* pages which corresponds to a *1-to-many* relation.**
To use your *HasOneComplexTableField* table for a **1-to-1** relation, make this modification in the class *Project* :
:::php
class Project extends Page {
...
function getCMSFields() {
...
$tablefield->setParentClass('Project');
$tablefield->setOneToOne();
$fields->addFieldToTab( 'Root.Content.Student', $tablefield );
return $fields;
}
}
Now, you will notice that by checking a student in a *Project* page, you will be unable to select him again in any other
*Project* page which is the definition of a **1-to-1** relation.
## Student - Mentor relation
**A student has one mentor.**
**A mentor has several students.**
This relation is called a **1-to-many** relation.
The first step is to create the mentor object and set the relation with the *Student* data object.
*tutorial/code/Mentor.php*
:::php
<?php
class Mentor extends Page {
static $db = array(
'FirstName' => 'Text',
'Lastname' => 'Text',
'Nationality' => 'Text'
);
static $has_many = array(
'Students' => 'Student'
);
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab( 'Root.Content.Main', new TextField( 'FirstName' ) );
$fields->addFieldToTab( 'Root.Content.Main', new TextField( 'Lastname' ) );
$fields->addFieldToTab( 'Root.Content.Main', new TextField( 'Nationality' ) );
return $fields;
}
}
class Mentor_Controller extends Page_Controller {}
:::php
class Student extends DataObject {
...
static $has_one = array(
'MyMentor' => 'Mentor'
);
}
This code will create a relationship between the *Student* table and the *Mentor* table by storing the id of the
respective *Mentor* in the *Student* table.
The second step is to add the table in the method *getCMSFields* which will allow you to manage the *has_many* relation.
:::php
class Mentor extends Page {
...
function getCMSFields() {
$fields = parent::getCMSFields();
...
$tablefield = new HasManyComplexTableField(
$this,
'Students',
'Student',
array(
'FirstName' => 'FirstName',
'Lastname' => 'Family Name',
'Nationality' => 'Nationality'
),
'getCMSFields_forPopup'
);
$tablefield->setAddTitle( 'A Student' );
$fields->addFieldToTab( 'Root.Content.Students', $tablefield );
return $fields;
}
}
To know more about the parameters of the *HasManyComplexTableField* constructor, [check](#project_-_student_relation)
those of the *HasOneComplexTableField* constructor.
<div class="tip" markdown='1'>
Don't forget to rebuild the database using *dev/build?flush=1* before you
proceed to the next part of this tutorial.
</div>
Now that we have created our *Mentor* page type, go into the CMS and create one *Mentor* page for each mentor listed
[above](#what-are-we-working-towards) under a simple *Page* named
**Mentors** for instance.
![tutorial:gsoc-mentor-creation.png](_images/gsoc-mentor-creation.png)
For each *Mentor* page, you can now affect **many** students created previously ( see the
[list](#What_are_we_working_towards?) ) by going in the tab panel *Students*.
![tutorial:gsoc-mentor-student-selection.png](_images/gsoc-mentor-student-selection.png)
You will also notice, that by checking a student in a *Mentor* page, you will be unable to select him again in any other
*Mentor* page which is the definition of a **1-to-many** relation.
As the *HasOneComplexTableField* table, you also have the possibility not to select any student which will make your
*Mentor* page without any student affected to it.
## Project - Module relation
**A project uses several modules.**
**A module is used by several projects.**
This relation is called a **many-to-many** relation.
The first step is to create the module object and set the relation with the *Project* page type.
*tutorial/code/Module.php*
:::php
class Module extends DataObject {
static $db = array(
'Name' => 'Text'
);
static $belongs_many_many = array(
'Projects' => 'Project'
);
function getCMSFields_forPopup() {
$fields = new FieldSet();
$fields->push( new TextField( 'Name' ) );
return $fields;
}
}
:::php
class Project extends Page {
...
static $many_many = array(
'Modules' => 'Module'
);
}
This code will create a relationship between the *Project* table and the *Module* table by storing the ids of the
respective *Project* and *Module* in a another table named **Project_Modules**.
The second step is to add the table in the method *getCMSFields* which will allow you to manage the *many_many*
relation.
:::php
class Project extends Page {
...
function getCMSFields() {
$fields = parent::getCMSFields();
...
$modulesTablefield = new ManyManyComplexTableField(
$this,
'Modules',
'Module',
array(
'Name' => 'Name'
),
'getCMSFields_forPopup'
);
$modulesTablefield->setAddTitle( 'A Module' );
$fields->addFieldToTab( 'Root.Content.Modules', $modulesTablefield );
return $fields;
}
}
To know more about the parameters of the *ManyManyComplexTableField* constructor,
[check](#project_-_student_relation) those of the *HasOneComplexTableField*
constructor.
Don't forget to rebuild the database using
[http://localhost:3000/db/build?flush=1](http://localhost:3000/db/build?flush=1) before you proceed to the next part of
this tutorial.
Select now one of the *Project* page, go in the tab panel *Modules* and add all the modules listed
[above](#what-are-we-working-towards) by clicking on the link **Add A
Module** of your *ManyManyComplexTableField* table.
![tutorial:gsoc-module-creation.png](_images/gsoc-module-creation.png)
For each *Project* page, you can now affect **many** modules created previously ( see the
[list](#What_are_we_working_towards?) ) by going in the tab panel
*Modules*.
![tutorial:gsoc-project-module-selection.png](_images/gsoc-project-module-selection.png)
You will also notice, that you are able to select several times a *Module* on different *Project* pages which is the
definition of a **many-to-many** relation.
As the *HasOneComplexTableField* and *HasManyComplexTableField* table, you also have the possibility not to select any
module which will make your *Project* page without any module affected to it.
## Displaying the data on your website
Now that we have created all the *Page* and *DataObject* classes necessary and the relational tables to
manage the [relations](../topics/datamodel#relations) between them, we would like to see these relations on the website.
We will see in this section how to display all these relations but also how to create a template for a *DataObject*.
For every kind of *Page* or *DataObject*, you can access to their relations thanks to the **control** loop.
**__1. GSOC Projects__**
Let's start with the *ProjectsHolder* page created before. For this template, we are will display the same table than
[above](#what-are-we-working-towards).
![tutorial:gsoc-projects-table.png](_images/gsoc-projects-table.png)
*tutorial/templates/Layout/ProjectsHolder.ss*
:::ss
<div class="typography">
<% if Menu(2) %>
<% include SideBar %>
<div id="Content">
<% end_if %>
<% if Level(2) %>
<% include BreadCrumbs %>
<% end_if %>
<h2>$Title</h2>
$Content
<table>
<thead>
<tr>
<th>Project</th>
<th>Student</th>
<th>Mentor</th>
<th>Modules</th>
</tr>
</thead>
<tbody>
<% control Children %>
<tr>
<td>$Title</td>
<td>
<% if MyStudent %>
<% control MyStudent %>
$FirstName $Lastname
<% end_control %>
<% else %>
No Student
<% end_if %>
</td>
<td>
<% if MyStudent %>
<% control MyStudent %>
<% if MyMentor %>
<% control MyMentor %>
$FirstName $Lastname
<% end_control %>
<% else %>
No Mentor
<% end_if %>
<% end_control %>
<% else %>
No Mentor
<% end_if %>
</td>
<td>
<% if Modules %>
<% control Modules %>
$Name &nbsp;
<% end_control %>
<% else %>
No Modules
<% end_if %>
</td>
</tr>
<% end_control %>
</tbody>
</table>
$Form
$PageComments
<% if Menu(2) %>
</div>
<% end_if %>
</div>
*tutorial/templates/Includes/SideBar.ss*
You might want to move the include above the typography div in your layouts to get rid of the bullets.
:::ss
<% if Menu(2) %>
<ul id="Menu2">
<% control Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a></li>
<% end_control %>
</ul>
<% end_if %>
**__2. Project__**
We know now how to easily access and show [relations](../topics/datamodel#relations) between *DataObject* in a template.
We can now do the same for every *Project* page by creating its own template.
![tutorial:gsoc-project.png](_images/gsoc-project.png)
*tutorial/templates/Layout/Project.ss*
:::ss
<div class="typography">
<% if Menu(2) %>
<% include SideBar %>
<div id="Content">
<% end_if %>
<% if Level(2) %>
<% include BreadCrumbs %>
<% end_if %>
<h2>$Title</h2>
$Content
<h3>Student</h3>
<% if MyStudent %>
<% control MyStudent %>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<h3>Mentor</h3>
<% if MyMentor %>
<% control MyMentor %>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<% end_control %>
<% else %>
<p>This student doesn't have any mentor.</p>
<% end_if %>
<% end_control %>
<% else %>
<p>There is no any student working on this project.</p>
<% end_if %>
<h3>Modules</h3>
<% if Modules %>
<ul>
<% control Modules %>
<li>$Name</li>
<% end_control %>
</ul>
<% else %>
<p>This project has not used any modules.</p>
<% end_if %>
$Form
$PageComments
<% if Menu(2) %>
</div>
<% end_if %>
</div>
What we would like now is to create a special template for the *DataObject* *Student* and the *Page* *Mentor* which will
be used when we will call directly the variable in the *Project* template. In our case, we will use the same template
because these two classes have the same fields ( FirstName, Surname and Nationality ).
*tutorial/templates/Includes/GSOCPerson.ss*
:::ss
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
Now the template is created, we need to establish the link between the *Student* and *Mentor* classes with their common
template.
To do so, add this code in the two classes. This will create a control on each of those objects which can be called
from templates either within a control block or dot notation.
*tutorial/code/Student.php, tutorial/code/Mentor.php*
:::php
function PersonalInfo() {
$template = 'GSOCPerson';
return $this->renderWith( $template );
}
We can now modify the *Project* template.
:::ss
...
<% if MyStudent %>
$MyStudent.PersonalInfo
<h3>Mentor</h3>
<% control MyStudent %>
<% if MyMentor %>
$MyMentor.PersonalInfo
<% else %>
<p>This student doesn't have any mentor.</p>
<% end_if %>
<% end_control %>
<% else %>
<p>There is no any student working on this project.</p>
<% end_if %>
...
In the *Project* template, it has been really easy to display the **1-to-1** relation with a *Student* object just by
calling the variable **$MyStudent**. This has been made possible thanks to the code below present in the *Project*
class.
:::php
static $has_one = array(
'MyStudent' => 'Student'
);
However, in the *Student* class, there is no any code relating to the **1-to-1** relation with a *Project* *Page*. So
how to access it from a *Student* *DataObject* ?
**__3. Mentor__**
In this template, we are gonna try to access the *Project* details from a *Student* *DataObject*.
What we want to do is to access to the *Project* page in the same way than we have done for the other relations
**without modifying the relations between *Page* and *DataObject* and the database structure**.
![tutorial:gsoc-mentor.png](_images/gsoc-mentor.png)
To do so, we have to create a function in the *Student* class which will return the *Project* linked with it. Let's call
it *MyProject* for instance.
:::php
class Student extends DataObject {
...
function MyProject() {
return DataObject::get( 'Project', "`MyStudentID` = '{$this->ID}'" );
}
}
We can now use this value in the same way that we have used the other relations.
That's how we can use this function in the *Mentor* template.
*tutorial/templates/Layout/Mentor.ss*
:::ss
<div class="typography">
<% if Menu(2) %>
<% include SideBar %>
<div id="Content">
<% end_if %>
<% if Level(2) %>
<% include BreadCrumbs %>
<% end_if %>
<h2>$Title</h2>
$Content
<h3>Personal Details</h3>
<p>First Name: <strong>$FirstName</strong></p>
<p>Lastname: <strong>$Lastname</strong></p>
<p>Nationality: <strong>$Nationality</strong></p>
<h3>Students</h3>
<% if Students %>
<table>
<thead>
<tr>
<th>Student</th>
<th>Project</th>
</tr>
</thead>
<tbody>
<% control Students %>
<tr>
<td>$FirstName $Lastname</td>
<td>
<% if MyProject %>
<% control MyProject %>
$Title
<% end_control %>
<% else %>
No Project
<% end_if %>
</td>
</tr>
<% end_control %>
</tbody>
</table>
<% else %>
<p>There is no any student working with this mentor.</p>
<% end_if %>
$Form
$PageComments
<% if Menu(2) %>
</div>
<% end_if %>
</div>
## Summary
This tutorial has demonstrated how easy it is to manage all the type of relations between *DataObject* objects in the
CMS and how to display them on the website.
## Download the code
You can download all the [complete code](http://doc.silverstripe.org/src/github/master/sapphire/docs/en/tutorials/_images/tutorial5-completecode.zip) of this tutorial.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,435 @@
/* Global Resetting */
html{
width: 100%;
height: 100%;
background:url(../images/body_bg.gif) repeat;
}
body {
width: 100%;
height: 100%;
font-size: 62.5%;
/* reset font-sizes to 1em == 10px */
}
* {
font-size: 1em;
/* reset font-sizes to 1em == 10px */
padding: 0;
margin: 0;
font-family:Verdana,Helvetica,sans-serif;
list-style:none;
}
a img{
border:0;
}
.clear{
clear:both;
}
/* Layout CSS */
#Main {
margin:20px auto;
width:900px;
}
#Header {
background:url(../images/blueback.gif) bottom left repeat-x;
border-left:1px solid #ccc;
border-right:1px solid #ccc;
clear:left;
}
#Header h1 {
color:#fff;
font-size:1.5em;
line-height:4.5em;
padding-left:20px;
}
#Menu1 {
padding:10px 50px 0;
}
#Menu1 li {
float:left;
margin-left:2px;
background:url(../images/menu1_right.gif) no-repeat right top;
}
#Menu1 li.current,
#Menu1 li.section {
background:url(../images/menu1_right_on.gif) no-repeat right top;
}
#Menu1 li a {
display:block;
color:#fff;
font-weight:bold;
font-size:1.1em;
text-decoration:none;
padding:5px 15px;
background:url(../images/menu1_left.gif) no-repeat left top;
}
#Menu1 li a:hover {
color:#d2ebff;
}
#Menu1 li.current a,
#Menu1 li.section a {
background:url(../images/menu1_left_on.gif) no-repeat left top;
color:#d2ebff;
}
#ContentContainer {
background:#f5f5f5 url(../images/ss_watermark.gif) bottom left no-repeat;
padding-top:20px;
padding-bottom:20px;
overflow: auto;
}
#Banner {
text-align: center;
}
#Menu2 {
margin-left: 20px;
width: 17em;
float:left;
background:#f0f0f0;
border:1px solid #ddd;
padding:10px 10px 10px 10px;
}
#Menu2 li {
padding-left:15px;
background:url(../images/menu2_arrow.gif) no-repeat left center;
}
#Menu2 a {
color:#333;
font-weight:bold;
font-size:1.1em;
line-height:1.6em;
text-decoration:none;
}
#Menu2 a:hover {
text-decoration:underline;
}
#Menu2 li.current a,
#Menu2 li.section a {
color:#0083C8;
}
#Content {
float: left;
margin: 0px 20px;
width:70%;
}
div.breadcrumbs {
margin-bottom:10px;
font-size:1em;
color:#666;
}
div.breadcrumbs a {
text-decoration:none;
}
#Footer {
background:#015581;
clear:both;
text-align:right;
padding-right:20px;
border:1px solid #ccc;
border-top:0;
}
#Footer span {
color:#ccc;
font-size:1.1em;
line-height:2em;
font-weight:bold;
padding-left:20px;
background:url(../images/ss_logo.gif) no-repeat;
}
#Footer a {
color:#fff;
}
#Footer a:hover {
text-decoration:none;
}
/* The rest of this file is for the second tutorial */
#NewsList,
#StaffList {
background:#f0f0f0;
border:1px dotted #ccc;
padding:10px;
}
#NewsList li,
#StaffList li {
margin: 0;
list-style-type: none;
}
#NewsList li.newsDateTitle span {
color:#666;
line-height:2em;
}
#NewsList li.newsDateTitle a {
font-size:1.3em;
font-weight:bold;
color:#0083C8;
text-decoration:none;
padding-left:20px;
background:url(../images/treeicons/news-file.gif) no-repeat left center;
}
#NewsList li.newsDateTitle a:hover {
border-bottom:1px dotted #0083C8;
}
#NewsList li.newsSummary {
margin-bottom:20px;
}
#NewsList li.newsSummary span {
font-size:1.1em;
line-height:1.5em;
color:#333;
}
#NewsList li.newsSummary a.readMoreLink {
color:#0083C8;
text-decoration:none;
}
#NewsList li.newsSummary a.readMoreLink:hover {
border-bottom:1px dotted #0083C8;
}
div.newsDetails {
margin-bottom:10px;
}
div.newsDetails p {
color:#666;
margin:0;
font-size:1em;
}
div.pageComments {
background:#f0f0f0;
border:1px dotted #ccc;
padding:10px;
}
#StaffList .staffname {
clear: both;
padding-left: 60px;
height: 1.2em;
}
#StaffList .staffphoto {
float: left;
margin-left: 3px;
margin-top: -1.2em;
}
#StaffList .staffphoto img {
border:1px solid #AAA;
}
#StaffList .staffdescription {
margin-left: 60px;
margin-bottom:30px;
}
#StaffPhoto {
float: left;
margin-right: 10px;
}
#StaffPhoto img {
border:1px solid #AAA;
}
#PageComments {
list-style:none;
background:#e9e9e9;
border:1px solid #ccc;
border-bottom:0;
padding:0;
margin:0;
}
#PageComments li {
list-style:none;
padding:5px;
margin:0;
font-size:1em;
border-bottom:1px dotted #bbb;
}
#PageComments li p span {
font-style:italic;
}
#PageComments a.deletelink {
font-weight:bold;
}
#PageNumbers {
font-weight:bold;
color:#333;
font-size:1.1em;
text-align:center;
padding:5px;
border:1px solid #ddd;
background:#e9e9e9;
}
#PageNumbers * {
padding:0 5px;
line-height:1.5em;
}
#PageNumbers a {
color:#0083C8;
text-decoration:none;
}
#PageNumbers a:hover {
text-decoration:underline;
}
#BrowserPoll {
width: 200px;
float: right;
margin-right: 20px;
margin-top: 20px;
}
#BrowserPoll h2 {
color:#0083C8;
font-size:1.2em;
}
#BrowserPoll ul {
margin: 0;
}
#BrowserPoll li {
list-style-type: none;
margin: 0;
}
#BrowserPoll .browser {
color:#333;
line-height:1.5em;
font-size:1.1em;
}
#BrowserPoll .bar {
background-color: #015581;
}
#BrowserPoll form {
width:100%;
}
#BrowserPoll form fieldset{
border:0;
}
#BrowserPoll .message {
color:red;
background:#ddd;
border:1px solid #ccc;
padding:5px;
margin:5px;
}
#BrowserPoll span.message {
width: 100%;
}
#BrowserPoll form div {
margin-top:10px;
width:100%;
}
#BrowserPoll form label {
font-size:1.1em;
color:#333;
}
#BrowserPoll form label.left {
float:left;
}
#BrowserPoll form label.FormHeading {
font-size:1.3em;
color:#ff7200;
font-weight:bold;
}
#BrowserPoll form input.text,
#BrowserPoll form textarea,
#BrowserPoll form select {
width:100%;
color:#000;
background:#f8f8f8;
border:1px solid #aaa;
padding:3px;
}
#BrowserPoll form input.numeric {
width:20px;
background:#f0f0f0;
border:1px solid #aaa;
padding:3px;
color:#000;
margin-right:4px;
}
#BrowserPoll form input.year {
width:35px;
}
#BrowserPoll form p.Actions {
text-align:right;
padding:0 22px 15px 0;
}
#BrowserPoll form p.Actions input {
padding:2px;
}
#BrowserPoll form ul.optionset {
padding-top: 15px;
padding-left: 15px;
}
#BrowserPoll form ul.optionset li {
list-style-type: none;
}
#Header form {
float:right;
width:160px;
margin:25px 25px 0px 25px;
}
#Header form * {
display:inline !important;
}
#Header form div {
}
#Header form input.text {
width:110px;
color:#000;
background:#f0f0f0;
border:1px solid #aaa;
padding:3px;
}
#Header form input.action {
font-weight:bold;
}
.searchResults h2 {
font-size:2.2em;
font-weight:normal;
color:#0083C8;
margin-bottom:15px;
}
.searchResults p.searchQuery {
color:#333;
margin-bottom:10px;
}
.searchResults ul#SearchResults li {
margin-bottom:20px;
}
ul#SearchResults p {
font-size:1.1em;
font-weight:normal;
line-height:2em;
color:#333;
}
ul#SearchResults a.searchResultHeader {
font-size:1.3em;
font-weight:bold;
color:#0083C8;
text-decoration:none;
margin:20px 0 8px 0;
padding-left:20px;
background:url(../images/treeicons/search-file.gif) no-repeat left center;
}
ul#SearchResults a {
text-decoration:none;
color:#0083C8;
}
ul#SearchResults a:hover {
border-bottom:1px dotted #0083C8;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,23 @@
# Written Tutorials
* [Tutorial 1: Building a basic site](1-building-a-basic-site): An introduction to building a site with
SilverStripe
* [Tutorial 2: Extending a basic site](2-extending-a-basic-site): A tutorial that builds on "Building a basic
site"
* [Tutorial 3: Forms](3-forms): An introduction to forms in SilverStripe.
* [Tutorial 4: Site Search](4-site-search): Learn how to add search to your site.
* [Tutorial 5: Dataobject Relationship Management](5-dataobject-relationship-management): Learn how to create
a simple data relationships
# Video tutorials
* [Installing on Linux](http://silverstripe.org/assets/screencasts/Tutorial-InstallingLinux-DM08.swf)
* [Installing on Mac OSX (using MAMP)](http://silverstripe.org/assets/screencasts/Tutorial-InstallingMAMP-SW08.swf)
* [Installing a module (e.g. a blog)](http://silverstripe.org/assets/screencasts/Tutorial-InstallingBlogModule-DM08.swf)
* [Customising the CMS (adding new fields)](http://silverstripe.org/assets/screencasts/Tutorial-ChangingFields-DM08.swf)
# Help: If you get stuck
* [Common Problems](/installation/common-problems): Review some existing solutions to common problems.
* [SilverStripe Forums](http://www.silverstripe.com/silverstripe-forum/): Head over to the forums and ask the community
for help