Helpers
Permalink 2 users found helpful
Ok, I've tried hours to figure out how can I use my old 5.6 (not talking about built-in helpers) helpers in 5.7.
Or is there a better way to use similar approach as old helpers? I would like to access my classes from several places.
Or is there a better way to use similar approach as old helpers? I would like to access my classes from several places.
@Mainio
The "legacy" method should be encouraged as it is the abstraction that hides the implementation detail. Form over function again!.Sigh.
The "legacy" method should be encouraged as it is the abstraction that hides the implementation detail. Form over function again!.Sigh.
OK, where did you read that? I haven't had much look at the docs.
Doesn't the IoC container also hide the implementation detail?
Why is the "Loader" class under the "Legacy" folder in the core? I don't think putting stuff in a "Legacy" folder would be encouraging their use... Although I might be wrong but it does sound very strange to me.
And what's the main benefit of using the legacy loader? I didn't quite get your point.
EDIT:
Additionally, why is core using Core::make() to get the helpers if its use is not encouraged? Or it's actually using both ways but in the refactored stuff it's using Core::make().
Doesn't the IoC container also hide the implementation detail?
Why is the "Loader" class under the "Legacy" folder in the core? I don't think putting stuff in a "Legacy" folder would be encouraging their use... Although I might be wrong but it does sound very strange to me.
And what's the main benefit of using the legacy loader? I didn't quite get your point.
EDIT:
Additionally, why is core using Core::make() to get the helpers if its use is not encouraged? Or it's actually using both ways but in the refactored stuff it's using Core::make().
@Mainio
Perhaps I should clarify.
It should be encouraged, but it will not be because I prefer function over form. The Loader::helper has been implemented as an abstraction to make it backwards compatible and it removes the requirement for the developer to know how to resolve the helper paths/namespaces and creates the routes. Basically they have implemented the helper API with the new architecture but conceptually it sits above where they want you to be programming.
Perhaps I should clarify.
It should be encouraged, but it will not be because I prefer function over form. The Loader::helper has been implemented as an abstraction to make it backwards compatible and it removes the requirement for the developer to know how to resolve the helper paths/namespaces and creates the routes. Basically they have implemented the helper API with the new architecture but conceptually it sits above where they want you to be programming.
Strikes me as a step backwards. 2 files and classes plus an on_start handler where we used to just declare a helper class and call Loader::helper.
Does such complexity really mark progress and a superior architecture?
Does such complexity really mark progress and a superior architecture?
@jtf Loader::helper went from this: https://github.com/concrete5/concrete5/blob/master/web/concrete/core... to this: https://github.com/concrete5/concrete5-5.7.0/blob/develop/web/concre...
That is orders of magnitude less complex. @manio is not correct in saying that helpers have become "services", there is no construct in the core named "service". Service providers simply manage registering groups of related instructions. The only difference here is that helpers are no longer IMPLICIT, they are explicitly defined by whoever expects to provide them.
Here's an example of the power of the new setup:
@jtf I highly suggest you look into IOC and SOLID and come to these conclusions yourself.
@phallanx, we should not be encouraging any of the loader functions, they are deprecated because they are not intended to be used. I'm of the mind that the \Loader class should go away, it was added simply because the core used \Loader everywhere, and has become more and more useless as we've converted to stronger more explicit loading methods.
That is orders of magnitude less complex. @manio is not correct in saying that helpers have become "services", there is no construct in the core named "service". Service providers simply manage registering groups of related instructions. The only difference here is that helpers are no longer IMPLICIT, they are explicitly defined by whoever expects to provide them.
Here's an example of the power of the new setup:
\Core::bind('helper/count_helper', function($app, $base=10, $start_int=0) { switch ($base) { case 2: return new \My\Site\Counter\BinaryCounter($start_int); case 10: return new \My\Site\Counter\DecimalCounter($start_int); } throw new \My\Site\Counter\InvalidBaseException($base); });
@jtf I highly suggest you look into IOC and SOLID and come to these conclusions yourself.
@phallanx, we should not be encouraging any of the loader functions, they are deprecated because they are not intended to be used. I'm of the mind that the \Loader class should go away, it was added simply because the core used \Loader everywhere, and has become more and more useless as we've converted to stronger more explicit loading methods.
@Korvin: OK, thanks for the clarifying the point on services. Although, I'm not sure how to explain that correctly, I could update the post.
My understanding was solely based on what I've heard from @Andrew:
http://andrewembler.com/posts/5-7-preview-developer-changes/...
I also probably heard him say something similar in some clip.
My understanding was solely based on what I've heard from @Andrew:
http://andrewembler.com/posts/5-7-preview-developer-changes/...
Dispatcher extends the Laravel IoC Container, allowing for sensible binding of services (which replace helpers) for lazy loading and overriding.
I also probably heard him say something similar in some clip.
Definitely a misnomer, helpers are no different than any other class and shouldn't be seen as such. There is nothing specifically wrong about your post other than alluding that service providers exist to register helpers :)
Service providers are just there to package up common items that need to be registered in runtime.
Service providers are just there to package up common items that need to be registered in runtime.
@Korvin: Thanks for the clarifying vol. 2.
I don't think I explicitly stated that service providers are solely for registering helpers, so I don't think I need to edit the post. Let me know if you feel so and I can do so.
I don't think I explicitly stated that service providers are solely for registering helpers, so I don't think I need to edit the post. Let me know if you feel so and I can do so.
@jtf
Also to add, that not all of that is necessary when defining a helper, just like stated in the original post. You could do the singleton biding straight in your Package controller, as said in the post.
I don't think it's conceptually any harder than the old way. But this gives you a lot more control.
Also to add, that not all of that is necessary when defining a helper, just like stated in the original post. You could do the singleton biding straight in your Package controller, as said in the post.
I don't think it's conceptually any harder than the old way. But this gives you a lot more control.
This is wrong. Deprecated methods and classes should be discouraged.
@Korvin
Can you clarify where I have encouraged deprecated methods, so that I can correct the original post?
Can you clarify where I have encouraged deprecated methods, so that I can correct the original post?
This was a response to @phallanx
OK, thanks.
When I followed exactly these steps, I get an error that says, "Class '.../PackageServiceProvider' not found".
Is there something I missed?
Is there something I missed?
An old classic on some of these concepts linked below. It's Java but a lot of the modern PHP concepts are from Java land so the "when" and "whys" are still applicable.
http://martinfowler.com/articles/injection.html...
http://martinfowler.com/articles/injection.html...
@mkly
Who was it that was saying PHP is *not* Java?
This is more of a design decision over re-factoring module interfaces (using 3rd party components). A better discussion of the issues and the lessons learnt pertaining to what has happened in 5.7 from the addon developers perspective comes from the Python world which is a far better comparison to PHP than Java.
https://www.youtube.com/watch?v=o9pEzgHorH0#t=567...
Who was it that was saying PHP is *not* Java?
This is more of a design decision over re-factoring module interfaces (using 3rd party components). A better discussion of the issues and the lessons learnt pertaining to what has happened in 5.7 from the addon developers perspective comes from the Python world which is a far better comparison to PHP than Java.
https://www.youtube.com/watch?v=o9pEzgHorH0#t=567...
@Phallanx
How about keeping these points in their own topic, I've seen these come up in several threads now from multiple people. I think it's better to argue about the decisions in a central location than trying to convince everyone individually to change their minds.
I created one here:
http://www.concrete5.org/community/forums/5-7-discussion/5.7-archit...
And how about keeping the one-on-one debates in some other communication channel. A fight always needs at least two people, so that's not solely towards you.
How about keeping these points in their own topic, I've seen these come up in several threads now from multiple people. I think it's better to argue about the decisions in a central location than trying to convince everyone individually to change their minds.
I created one here:
http://www.concrete5.org/community/forums/5-7-discussion/5.7-archit...
And how about keeping the one-on-one debates in some other communication channel. A fight always needs at least two people, so that's not solely towards you.
Thanks some great information in here,
How would I go about overwriting a core service/helper
In this instance I would like to replace the Sharing service to use custom classes instead of the Font Awesome classes it currently uses.
I've attempted to use the information above to register it as a service and load that from my new block override but currently experiencing a few issues getting it working as I would expect.
As I am attempting to use a custom version of the Sharing service I assume that I can change the path in the bootstrap/app? (or from within my package).
How would I go about overwriting a core service/helper
In this instance I would like to replace the Sharing service to use custom classes instead of the Font Awesome classes it currently uses.
I've attempted to use the information above to register it as a service and load that from my new block override but currently experiencing a few issues getting it working as I would expect.
As I am attempting to use a custom version of the Sharing service I assume that I can change the path in the bootstrap/app? (or from within my package).
Can you post the code? It might help to see what's wrong.
I've successfully replaced the image helper in core with this call in the /application/bootstrap/app.php (that you also referred to):
EDIT: In fact, that's not the old image 'helper' but I think that's good for reference. If you want to replace the image helper the key would be 'helper/image'.
I've successfully replaced the image helper in core with this call in the /application/bootstrap/app.php (that you also referred to):
$app->bind('html/image', '\Application\Src\Html\Image');
EDIT: In fact, that's not the old image 'helper' but I think that's good for reference. If you want to replace the image helper the key would be 'helper/image'.
I have attempted a couple of ways, so this might get a little messy with me trying to explain, each method I have attempted separately.
Method 1, add to the bootstrap to try and override the actual call? figured this would be a good start and a safe way if it worked? as I did not need to change the block
//No idea if the params are required I don't think so but it would not work either way
Method 2, Try over riding the block and service files
The old structure was
//concrete/src/Sharing/SocialNetwork
I have copied the SocialNetwork folder into the following and renamed it just to try keeping things simple(ish)
//application/src/service/social
and also into my package
//packages/my_package/src/service/social
Then in the block I am overriding I have changed the use from
Method 3,
I also attempted to load in as a new service similar to the method you described further up and in the SocialServiceProvider.php (located in services, in both application/src and the package equivalent)
Each method I end up with the following error
Does that make sense?, to boil it all down I want to change this function in the
And then also amend the getService function.
Thanks for your help
Method 1, add to the bootstrap to try and override the actual call? figured this would be a good start and a safe way if it worked? as I did not need to change the block
//in bootstrap/app Core::bind('\Concrete\Src\Sharing\SocialNetwork', function($app, $params) { return new \Application\Src\Service\Social\Link($params[0]); });
//No idea if the params are required I don't think so but it would not work either way
Method 2, Try over riding the block and service files
The old structure was
//concrete/src/Sharing/SocialNetwork
I have copied the SocialNetwork folder into the following and renamed it just to try keeping things simple(ish)
//application/src/service/social
and also into my package
//packages/my_package/src/service/social
Then in the block I am overriding I have changed the use from
Method 3,
I also attempted to load in as a new service similar to the method you described further up and in the SocialServiceProvider.php (located in services, in both application/src and the package equivalent)
namespace Concrete\Package\my_packge\Src; defined('C5_EXECUTE') or die("Access Denied."); use \Concrete\Core\Foundation\Service\Provider as ServiceProvider; class SocialServiceProvider extends ServiceProvider { public function register() { $pkgHandle = 'my_package'; $singletons = array( 'helper/social' => '\Concrete\Package\MyPackage\Src\Service\Social\Link', ); foreach($singletons as $key => $value) { $this->app->singleton('/packages/' . $pkgHandle . '/' . $key, $value); $this->app->singleton($pkgHandle . '/' . $key, $value); }
Viewing 15 lines of 17 lines. View entire code block.
Each method I end up with the following error
Class \Concrete\Package\MyPackage\Src\Service\Social\Link does not exist or Class 'Application\Src\Service\Social\Link' not found
Does that make sense?, to boil it all down I want to change this function in the
// concrete/src/service/social/Service public function getServiceIconHTML() { return '<i class="block ' . $this->getIcon() . '"></i>'; } //To instead output public function getServiceIconHTML() { return '<i class="custom-class ' . $this->getIcon() . '"></i>'; }
And then also amend the getService function.
Thanks for your help
What is the end goal of that override? I.e. what are you trying to do?
I would like to be able to use custom icons instead of the default font-awesome ones. The code changes the class applied so I can link this to our current spritemap.
Assuming this worked I also wanted to replicate the functionality and include our own logo library of items that the user can re-order and add/remove items to the list. Similar to the current functionality of the Social Link block (If that makes sense)
I would normally use a number of image blocks within a stack. I would like to be able to do the following using foundation instead of bootstrap, however the assets we have are within a spritemap and I don't really want to add the html to a block or redactor, relying on the content editor to not muck up the layout.
Assuming this worked I also wanted to replicate the functionality and include our own logo library of items that the user can re-order and add/remove items to the list. Similar to the current functionality of the Social Link block (If that makes sense)
I would normally use a number of image blocks within a stack. I would like to be able to do the following using foundation instead of bootstrap, however the assets we have are within a spritemap and I don't really want to add the html to a block or redactor, relying on the content editor to not muck up the layout.
<ul class="small-block-grid-3 large-block-grid-6 logos"> <li><span class="logo logo-bmw"></span></li> <li><span class="logo logo-mini"></span></li> <li><span class="logo logo-vw"></span></li> </ul>
OK, in this case I would probably use the 2nd one of your solutions, if this is only for your specific block and does not need to apply globally.
I would as well create an own class but I would simply extend the core class. This way you don't have to copy the whole class:
I think this should work OK, or at least I don't see any problem in it. If it's not, the problem might be where you're using it.
I haven't personally looked into the social links block but just guessing that it's using some external class which then uses the core's own Link class and not yours.
There's also one way I've found so far to override whole core classes, but it's really hacky and bad convention (although it's the only option I know), so I would rather not share it here. I think there should be a better solution coming at some point, or at least I've seen some discussions.
I would as well create an own class but I would simply extend the core class. This way you don't have to copy the whole class:
I think this should work OK, or at least I don't see any problem in it. If it's not, the problem might be where you're using it.
I haven't personally looked into the social links block but just guessing that it's using some external class which then uses the core's own Link class and not yours.
There's also one way I've found so far to override whole core classes, but it's really hacky and bad convention (although it's the only option I know), so I would rather not share it here. I think there should be a better solution coming at some point, or at least I've seen some discussions.
Okay, there must be an easier way:
5.6.x:
Create class, create methods, include with:
Now THAT's simple. What's the equivalent with no extra mumbo jumbo for 5.7? Like it was in 5.6. Don't tell me it doesn't exist. Steps forward should simplify things, not complicate them, right? Right??
5.6.x:
Create class, create methods, include with:
$rh = Loader::helper('rating');
Now THAT's simple. What's the equivalent with no extra mumbo jumbo for 5.7? Like it was in 5.6. Don't tell me it doesn't exist. Steps forward should simplify things, not complicate them, right? Right??
$rh = \Core::make('helper/rating');
Is being a software Architect/Engineer that of a pauper of old? Kings and Queens want it 'simpler', while the populace (ie: 'classes') are to aspire to be less like a King and more socialist in their aspirations (Inversion Of Control) for the greater good (Composer) and for posterity (Dependencies). Rather than waitng for the KIng's (procedual) decree to tell them who/what/where, the forest of squatters is to prepare themselves in the best manner in anticipation of the King's request.
@mkly, whilst thou has prepared a fine response it doth take a few more keystrokes to implement! Off with your head! :)
(Sorry, I've been reading too much code.)
@mkly, whilst thou has prepared a fine response it doth take a few more keystrokes to implement! Off with your head! :)
(Sorry, I've been reading too much code.)
Not the built in helpers. That's easy as before.
It's about the own helpers.
It's about the own helpers.
1. Place your services (i.e. helpers) in your package's /src/Service folder, e.g. for a service named "Praise" /src/Service/Praise.php
2. Create your service class (this can be a copy of your old helper with new naming)
Should look something like this:
3. Create a service provider in your src-folder. E.g. /src/PackageServiceProvider.php.
The contents of that should be something like this:
This is by the way optional step, you could also register the singletons without a service provider but this example just follows the conventions set by the core. In core, these are registered in service providers.
4. Initiate the service provider in your package.
5. Use it where you wish:
This naming convention of the singleton (i.e. your_package/helper) is my own since I think this is much more convenient than what the core proposes for loading any package specific singletons. I guess this is just up to the package developer to decide since I don't think there are any existing conventions / suggestions for this.
With this example, you could also use the old style loading of the helper if you want but the new style is encouraged. But just for the record, this would work too:
6. ???
7. Profit!