Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

"injector" / "useCustomClass" will not work on form class?


Go to End


8 Posts   2205 Views

Avatar
Entar

Community Member, 23 Posts

6 July 2015 at 10:10am

Hello guys,

I am trying to override or completely replace some functionality of the FORM class, according to http://docs.silverstripe.org/en/3.1/developer_guides/extending/injector/ it recently became possible to override classes with your own clasess utilizing injector. However I don't quite get how can I use injector to override FORM class, it simply does not work at all.

I've tried this:

Config::inst()->update('Injector', 'Form', array(
    'class' => 'MyForm'
));

and this:

Injector:
  Form:
    class: MyForm

None of this options work and I have no idea why.

Also I've tried older way:

Object::useCustomClass('Form', 'MyForm', true);

Which will not work and never worked for forms that were created other way than Object::create().

So my question is - is there ANY way I can replace or override a form class?

Avatar
Devlin

Community Member, 344 Posts

7 July 2015 at 12:39am

Injector will only work through the Object::create() factory method.

Injector:
  Form:
    class: MyForm

class MyForm extends Form {
	
}

class Page_Controller extends ContentController {
	private static $allowed_actions = array(
		'MyForm',
	);

	public function MyForm() {
		$form = Form::create();
		echo $form->class // MyForm
		return $form;
	}
}

Avatar
Entar

Community Member, 23 Posts

7 July 2015 at 7:46pm

thanks Devlin, however my question stays...

Avatar
Devlin

Community Member, 344 Posts

7 July 2015 at 9:55pm

Edited: 07/07/2015 10:22pm

So my question is - is there ANY way I can replace or override a form class?

It does work, if you're using the factory method....

edit: Maybe I'm missing something in your post, could you elaborate please.

Avatar
Entar

Community Member, 23 Posts

8 July 2015 at 7:45am

hi Devlin,

I am sorry for not being specific. I understand that only a factory created forms may be overridden. Problem is - mostly forms are created in external addons / plugins (i.e ss shop, memberprofiles etc) this modules usually implement forms using "new Form(...)" instead of Form::create, this makes Form::useCustomClass() useless.

Avatar
Pyromanik

Community Member, 419 Posts

8 July 2015 at 9:56am

Edited: 08/07/2015 10:12am

What Devlin is trying to say is that you're overlooking fundamentals of programming in PHP.

There is NO possible way to override the functionality of 'new ClassName', ever. This is a fundamental thing at language level, there is no entry point for dependency injection to happen at all. You cannot change the type of thing that is returned, unlike say Javascript (where 'classes' are actually just factory methods anyway, because it uses prototypal inheritance).

Object::create() invokes Injector, requesting an object of type <classname>, which implements dependency injection, so on so forth.

You can call injector directly via Injector::inst()->get('ClassName') if you like, but as with any (class based OOP) language, ever, you must use the dependency injector otherwise you just end up with EXACTLY what you asked for, every time.

TL;DR:
new MyForm is a php language construct. No way to change what it does.
MyForm::create makes a call to SilverStripe's dependency injection implementation (Injector).

Thing::create() has been the way to construct almost everything in SilverStripe for 3 years now. Any module that does not do this is either very poorly constructed, or very out of date (unmaintained), or some combination of the two.
It is unfortunate, but this is the nature of open source (you could always fix it and submit a pull request! :) )

Another reason could be that you're using an outdated version of the module (and/or SS). E.g. you mentioned ss-shop, which just made a new release
Using composer is a good way to ensure you have versions compatible with your version of SilverStripe (hopefully the latest one!)

Avatar
Entar

Community Member, 23 Posts

8 July 2015 at 11:32am

Edited: 08/07/2015 11:35am

Thanks for a good explanation Pyromanik. I must re-read the basics :)

Class::create is not that commonly used as you say, simple search thru the code (well, my project code) shows about 100 occurrences of new Form(...). It can be found in most well known modules (i.e shop - I just checked it and it has couple of them; omnipay; blog; cms) and even the framework itself (HTMLEditorField, UploadField, GridField). And yes I am using composer, so my modules are up to date mostly...

The way forms are built right now in SS is not sufficient and requires customizations all the time (to work with bootstrap for example or HTML5 new thingies or to simply have N columns Y rows layout instead of plain one column sky scraper - is still some work). I've seen unclecheese's module that makes forms compatible with bootstrap, however it requires use of custom BootstrapForm, which is not convenient in case of multiple project dependencies like shop, blog etc which will force you to customize all the classes which create forms old way... sometimes this places are even not extendable.

Good point I've got in this conversation is that probably someone has to go over all the popular modules + framework itself and refactor this tiny bit of form creation, seems easy enough and probably it will be done by me soon :)

Avatar
Pyromanik

Community Member, 419 Posts

8 July 2015 at 9:16pm

In order for Thing::create() to work, Thing must inherit from Object. There are a few things in SilverStripe that don't, and a few things that don't but have their own thin implementation (GridFieldComponent comes to mind). The new keyword will of course be used in places, especially in Injector itself. Also for things like new <thing>Exception, etc.
There are areas of low impact where new is used, this is mostly down to old code (and the fact that it's of low impact).