Reputation: 1914
I noticed that in some cases, when you write a class that extends an existing class, you need to declare the class extension in the config.yml file.
For example, I recently wrote this code to remove the "help" button in the CMS back-end.
mysite/code/Tweak.php
class Tweak extends LeftAndMainExtension
{
public function init()
{
parent::init();
/* Remove help link */
CMSMenu::remove_menu_item('Help');
}
}
mysite/code/Config.yml
LeftAndMain:
extensions:
- Tweak
Question 1: Why do some class extensions need to be declared in config.yml? And why is this extra step not necessary for other class extensions (eg extending DataObject or Page_Controller)?
Question 2: Specific question about above code, why am I declaring Tweaks as an extension to LeftAndMain in the config file, but in the php file I'm actually extending LeftAndMainExtension?
Upvotes: 2
Views: 860
Reputation: 1746
You are actually talking about two basic OO patterns here.
This is pretty much the standard way in many languages including PHP and Java for a custom class to inherit some logic from another class and be able to declare its own ala:
class MyObject extends DataObject {
}
There is nothing specific to SilverStripe in this, it's native (PHP) in this case.
When you subclass Extension
or any one of its subclasses e.g. DataExtension
, SiteTreeExtension
or LeftAndMainExtension
as per your example, you're "decorating" an existing class and the current library's or framework's implementation of the "Decorator" pattern.
In SilverStripe a big difference between these two approaches is that for subclassing, your new class will create a new table in the database (where you declare a $db
static in it). Using the decorator (An Extension
subclass declared in YML or via the $extension
static in the class itself) a new table is not created, you're simply able to "tack-on" new fields and logic onto existing objects and their tables.
A common example of the utility of the later approach is the Member
class. Subclassing it, won't help you much in modifying / customising SilverStripe's membership and permissions system, Decorating it will.
See the dedicated page on this feature of SilverStripe: https://docs.silverstripe.org/en/3.3/developer_guides/extending/extensions/
Upvotes: 8
Reputation: 24406
Question 1: Why do some class extensions need to be declared in config.yml? And why is this extra step not necessary for other class extensions (eg extending DataObject or Page_Controller)?
There's an important distinction here between PHP and SilverStripe terminology.
In SilverStripe, an Extension is a framework feature that is implemented in SilverStripe which allows you to modify the behaviour of an Object without having access to anything other than what's public. It's similar to Ruby in this respect.
In PHP, you use the extends
keyword to define a sub-class of an existing class.
In your example you're using the LeftAndMainExtension
, which is a SilverStripe "Extension" - this lets you modify the behaviour of the CMS menu in SilverStripe's admin area, while it doesn't literally extend (in PHP terms) the LeftAndMain
class.
Question 2: Specific question about above code, why am I declaring Tweaks as an extension to LeftAndMain in the config file, but in the php file I'm actually extending LeftAndMainExtension?
As above, this is how SilverStripe's extension system works. It basically follows the following process:
extends
(PHP keyword) Extension
at some point in the inheritance (you use LeftAndMainExtension
, which extends Extension
). For DataObjects you use DataExtension
instead.LeftAndMain
The naming is deliberate so you can group Objects and their relevant Extensions together easily/visually:
Convention is for extension class names to end in Extension. This isn't a requirement but makes it clearer
- SilverStripe developer documentation
Note I've been deliberately capitalising Extension to denote that it is a SilverStripe Extension class, not a PHP extension of a class (class Foo extends Bar
).
For an example of how the framework performs this process, it's basically like this:
Object::add_extension()
) for extensions$this->owner
as the current Object so extensions can access public methods and properties from itUpvotes: 8