I've come to realise that most things are possible with SilverStripe, it's just finding out how...
I'm sure I must be able to constrain in some way the types of pages administrators are able to create in the CMS. For example, following on from the second tutorial, we have a News page which is of type ArticleHolder, which contains a number of ArticlePages. As it stands, though, there is nothing stopping me creating any other type of page as a subpage of the News page. Is there any way that firstly I can ensure that the News page type cannot be changed from ArticleHolder, and secondly that only pages of type ArticlePage can be created as children of the News page?
Yes there is, but this doesn't provide the constraint. My News page is defined as an ArticleHolder page type, and the ArticleHolder class contains the following:
static $allowed_children = array('ArticlePage');
But in the CMS there is nothing to stop me (or more importantly, a non-technical administrator) from creating a completely different type of page as a subpage of my News page - there is nothing restricting the user to just the ArticlePage type, and no error is returned if you do create a subpage of the 'wrong' type and save it.
ThatÂ´s not possible. I tried it with one of my projects. If I select a diffrent page type it will be created but no nested as a child of my holder. If it does so there must be some error in your code.
Look into the $can_create variable and it's big brother the can_create() function.
In the access tab of each page in the admin area you can also set access rules. Combine this with groups in the Security tab (very top of admin area) and you can have a fair amount of control over what can be done by specific user accounts.
That said $allowed_children, when properly set, should prevent a new page of the wrong type being placed under a page of type ArticleHolder. Even if it is working properly though a new page will be created at the root level or under whatever page has been set as that type's $default_parent. Personally I think an error should be generated for the user so that they can make their own choice about what should happen.
It may well be that it doesn't get created as a child of the holder, I haven't tested that far. But this is surely a nicety which is likely to escape any non-technical users, who will apparently be able to create sub-pages which then don't show up.
As far as I know, there's no satisfying solution to this problem.
The can_create member is utterly useless. You should override the canCreate method, however I'm currently not aware of a way to figure out what Page the user selected in the SiteTree. Without that knowledge, you won't be able to return the proper value from "canCreate".
As baba-papa already pointed out, there are the static members $allowed_children and $default_child which can help you to minimize issues. Nothing is stopping the user from changing a created Site to another type though...
If you really want to enforce a certain page type in some situations, I'd probably override the onBeforeWrite method. There you could check the page-type, figure out if it matches the allowed type of the parent page and if not, issue an error, or automatically change/reset the type to an acceptable value.