currently I'm thinking on how to implement a plugin-feature for my symfony2 application.
My goals are as following:
Basically the plugin should be a bundle (at least service, event listener, routing, entities, migrations, views and controllers need to be registerable)
The AppKernel should not be touched in any way by the end user or the application
Plugins should provide meta information (title, description, screenshot/image, author etc)
plugins should be managed from the backend (activation, deactivation, installation, deletion, update etc)
plugins may come from different sources (Core, Community, Local as in shopware maybe) and should be seperated by save path
working autoload without running composer again
My problem would be something like: How to load a bundle after the Kernel is already loaded (since the information on which plugins are active should reside inside the database ideally and not inside some file on the hard disk but may be cached).
I did not found a bundle or a cook book entry on this topic. Is there a best practice managing something like this? Maybe I'm thinking in the wrong direction.
I hope there is someone who might have a helpful idea and the kind of knowledge on symfony2 which I do not have.
PS: There is no code yet since this is just some thinking on the concept on how to handle this.
The AppKernel returns the registered bundles as an array, so assuming that the storage method you're using to determine active plugins isn't tied to Symfony (i.e. you can access it before the application is fully bootstrapped), then it should be as easy as adding something like this to your AppKernel.php:
public function registerBundles()
{
...
...
$bundles = array_merge($bundles, MyApp\PluginManager::getPluginBundles());
...
return $bundles;
}
Providing the plugin metadata could be done in various ways (maybe just a defined location / directory in the plugin files that holds txt / image files), but loading all that should be easy once you have the plugin management stuff (and can easily get the installed plugins, etc) done.
Related
I have created a handler class that derives from AbstractProcessingHandler. I've seen that I can put it in src/MyNamespace/MyBundle/Monolog/, but it worries me a bit because this handler is used in several others bundles where I log data. So the other bundles will need MyBundle to work properly, only because of this handler.
I tried to put my handler class in lib/ but it does not seem to work (maybe I have to do something special with Autoload?).
Or should I create a new bundle specifically for this handler?
Edit: I can't really place my custom handler class in vendor/monolog/monolog/src/Monolog/Handler because then I would not be able to add it to my git repository: there is a conflict because this folder is managed by another git repository (created by Composer)
On Monolog's end there is really no restriction on where to put it or how you call it. The key is only that it implements monolog's HandlerInterface or extends from one of the existing handlers.
Now it depends what your handler is, if it's generic stuff that other people could use you could submit it as a pull request to monolog.
If not, you can either create an own composer package for it, or put it in src/Acme/Monolog/FooHandler or something like that, so it stays in your application but is clearly out of a bundle. The downside is that you need to configure it as a service in one of your bundles, so you still have some sort of dependency on a bundle there.
Maybe having it as its own bundle would make sense then. But it's quite a lot of boilerplate for just one class.
If all your bundles are application specific and very unlikely to be extracted out of it, having cross-bundles dependencies is fine though IMO.
The dependency is anyway not very strong since one bundle could contain the handler and configure it. The other bundles can still log to monolog, even if the handler isn't present, they can log. It just won't go to that specific handler. Nothing should break.
As you see, it's just a lot of trade-offs, and it's hard to say which solution is the most fitting without knowing more about your project.
If you want to have your handler class in lib/ you will need to add the lib/ folder to your composer.json autoload section. For example:
"autoload": {
"psr-0": { "": ["src/", "lib/"] }
}
Take a look at the Composer documentation:
Basic Usage
Autoload
I think the common approach here is to use a "Bridge" dir in your Bundle with a clear dependency. If you have other bundles that rely on this, what we've done is create a ServiceBundle which is basically for all shared services across all bundles within the application. This might not work well for you if you have plans of distributing this bundle, but may otherwise.
I understand that this question may be vague, I will try my best to explain my problem and hopefully can get lots of insights from the experienced and hopefully this will not be closed.
I'm writing a PHP web app framework based on Symfony 2's components and bundles, my question may not relate to that however. The framework is intended to be open to 3rd party plugins, these plugins will have their own config files (yaml) and the person who install these plugins should be able to override these settings locally.
I also have to make sure that each time the person perform the plugin upgrade operation, it should be easy to loop over the list of "upgrade patches" to upgrade the plugin's settings while still retaining the local settings.
I imagine I can have a local, app's specific plugins.yml file which store something like this:
pluginA:
somesettings: value
somesettings2: value2
This app's specific settings file will allow user to override any default settings. And then each plugin can contain an "upgrade" class that will contain all the patches for each version, the framework will identify the current installed path and will loop through each "upgrade patch" and perform actions until it reach the most current version.
Does this sound like a good option, or if there is something else I should look into? How do I have configuration settings that can be overridden can be upgraded easily? Please let me know if you need more details.
It seems to me that you are looking to achieve something that actually core Symfony allows to do - i. e. to let other users override / implement custom parts of an already existing bundle.
If so, maybe this answer can give a good idea on how to achieve that using the ClassLoader Component (Symfony 2.0) or Composer (Symfony 2.1):
How can I override Core Symfony2 Classes?
The challenge:
I want to modularize my library folder in my zend framework app. This is fine, if you want to put everything in the same namespace such "App_." But the problem comes in when you have a dozen packages such as a SignUp package, ACL Package, Navigation Package, Foo Package etc. Now each packages has some view helpers, some controller plugins, some action helpers plus some other base classes. You could add each view helper path individually, but that could junk up your application.ini file/ bootstrap.
So the question is, is anyone aware of 'Plugin Package' loader for ZF?
To clarify, it would be nice to have a resource plugin that you pass the package name, it adds the namespace, registers some default options like helper paths and then you can configure it to add helpers to Action Helper brokers. Each plugin package might have to have its own ini file or an init class that where the programmer could initialize the plugin package. Any thoughts or knowledge of something like this would be appreciated.
Your question is difficult to find a solution to. ZF doesn't seem to be used in the manner you wish.
For example you want the following packages
Navigation
ACL
Sign Up
These are all completely separate and don't all 'plugin' to ZF in a similar manner.
Navigation needs to be stored and built for each request that needs the package, the navigation object then needs to be used in Zend_View objects or perhaps not. What happens when the navigation is referenced in a view but it doesn't exist?
The ACL package is so specific, it integrates into ZF in a lot of different ways, it needs a Zend_Controller_Plugin, it needs a way of meaningful way of storing and building the Zend_Acl object for querying on an application to application basis.
Sign Up needs a controller, an action and a form which is passed to Zend_View and the form needs to be process. This then needs to be plugged into your ACL object, presumably a database and perhaps various other parts of your site it it requires more specific permissions that fall outside of the use for ACL
Its not impossible to do what you want, but there must be a better way. It almost sounds like your trying to build a CMS with optional, plug-able packages?
The ACL issue I have resolved by having a Library of controllers, helpers, models, forms, etc. A Zend_Controller_Plugin runs and attempts to log in the user, this plugin is run for every app I create, it works well uses an ACL object format which I have used for a while.
For Sign Up I have a RegisterController in my Library, if my application requires registration it has its own RegisterController which extends the RegisterController in the Library. If the application doesn't need registration then it doesn't have its own RegisterController.
I hope that helps, I really think that doing this in the abstracted way suggested isn't worth it and will never be so solid and tight you can truly rely on it because each application is specific.
Generally, in this case you should use modules which are already modularized instead of modularizing the library.
modules/
signup/
models/
plugins/
The default module resource autoloader is configured by default to load plugins:
See: http://framework.zend.com/manual/en/zend.loader.autoloader-resource.html:
If you really need to modularize the library, the customized autoloader will be the best solution (there is an easy to extend abstract autoloader).
You may also consider separate library for each module, added to your include path (not recommended, because it will slow down the app):
modules/
signup/
models/
library/
I am using this awesome framework during 6 months and I learnt a lot about it, but I wonder if it's possible to create an internal structure to simulate modules like in Codeigniter. I know there is the possibility to use plugins for that, but it seems too difficult to connect it together and pass info between them.
My goal is to get a joomla like modules, but how can i do that without changing the cakephp core? is that possible?
What I am doing for the project I have going on right now is to have the following
In my bootstrap.php
<?php
....
App::build( array(
'plugins' => array(
join( DS, array( null, 'Users', 'abryant', 'Sites', 'appName', 'tools' )),
),
...
));
?>
Then, I keep all of my utility plugins in the tools plugin folder. This is for plugins that you use as internal utilities that don't provide controller / action pairs. IE plugins for behaviors, components, stuff from github etc.
One of the plugins I always grab for my stuff is Eventful which allows you to handle event dispatching and receiving using event classes similar to controllers or models.
Then build a main AppController that has a corresponding AppControllerEvent class in the folder the instructions tell you to use. You can then keep your plugins folder clean for modules which provide controllers, views or some other direct user interaction.
You can use Eventful to broadcast events from plugins down to the App at the AppModel, or AppController sort of level. If you think about this carefully you can use an app level event to ask for responses from installed plugins and then cycle through a set of events to register blocks or inject information into the set view variables.
A lot opens up when you use events and think about how the events communicate with your app.
Well, you are right. Modules in Joomla are independent packages of code wich works like packages in linux (modules maybe depends on other modules), but all of them work over a core functionality. What I want to do is write a core over the CakePHP framework, wich includes the functionality to manage all kind of modules in the system, but I don't know what is the best way to modify CakePHP core to handle this situation...
I did this before with Codeigniter, and because of that I thought to come back to Codeigniter, but Cakephp helps me to create apps in less time... If it may be possible, it would be a great system.
Every module code should be inside its own directory, which includes a controller directory, models, views, config, etc... like a mini CakePHP app that extends the modified CakePHP core. I thought it can be done with plugins, but the way to interconnect them and pass info between them don't seem the best way to do it.
I hope you understand my explanation, sorry for my english.
Initially it seems very difficult, but I think it is the best solution for this problem.
Did you code plugins for all your modules? Or did you code the core in controllers, models, etc.. and extra modules inside plugins? It is weird to me to work this way in CakePHP.
I'll try to code all the modules apart, I mean a core plugin, settings plugin, modules plugin (to manage the other plugins), etc... And probably I'll use bootstraping.
Thank you very much for your answers and sorry for my bad explanation of my problem, but my idea was so general that I couldn't explain it better.
I have way too many modules in my application. Currently my modules are namespaced, but what I'd like to do is have a directory structure so I can get rid of this redundant and annoying namespacing.
For instance, for modules named "xModule1, xModule2, xModule3", I'd like to have a directory structure like this:
-x
-module1
-actions and templates
-module2
-actions and templates
-module3
- actions and templates
Surely the developers at symfony know that people would like to use their framework to develop large applications. So how is module organization like this done?
I've done a lot of work in Java/Spring, and because source is component scanned, you can arrange your controllers and jsp files in nicely organized hierarchies. Is this somehow possible with Symfony?
No, this is not possible with Symfony. The structure of your modules and their actions and templates is expected in a fixed file system layout and I haven't heard anything about that changing.
I've run into the same problem you're facing where a very large site ended up with 30+ modules in a single application. At first it seemed cumbersome but after dealing with it for a while I found that the single location to search for a specific module was in fact beneficial instead of having to guess through sub-structures until I got what I was after. Seeing that structure grow and grow also pushes me to respect adding new modules only when it's absolutely necessary, folding new functionality into existing modules and refactoring existing modules to work with new enhancements whenever possible.
Symfony does have auto-loading features that will work for your library folders however, allowing you to have lib/one/two/three/Object.class.php or any other structure you see fit.
If you have so many modules, you could consider to move some functionality into plugins (i.e. create your own plugins).
The benefit is that you can use this functionality also in other projects.
Or you can group your modules into applications. You can have as many applications as you want, not only backend and frontend.
I've wondered about the same thing, especially as many configuration files need to be set either at application level or individual module level. It could useful to be able to cascade configurations to a set of modules.
As mentioned above, it seems the available solutions are:
deal with lots of modules
create separate applications (which will create some wieldy duplication)
refactor your modules to be as efficient as practical (i.e. multiple controllers & views per module)