Zend2 isolated module configs - zend-framework2

It seem that all config settings defined in Module.php in getConfig method are merged globally across the application. It's pretty weird for my case, because I need different configs for each module: database settings, some factories and view_manager settings which are currently overridden by the last module loaded. How can I use configs exclusive for some module is scope of $this->getServiceLocator()->get('Config') in that module. The only thoughts I have now are to merge my module config with $this->getServiceLocator()->get('Config') on dispatch event, if that is the only case, what priority is better to use so I can utilize all settings: view_manager, service_manager ect?
For me the ideal solution will be if configs settings in scope of some namespace will be used only under that namespace.

You can nest your configuration values as deeply as you like.
Imaging you've got a module called "mymodule", and it needs to connect to a special, module-specific database (distinct from the main DB for the overall application). You would do something like this:
mymodule.global.php.dist:
return array(
'mymodule' => array(
'db' => array('host'=>'localhost', ... )
)
)
Then just make sure that myModule is looking at $config['mymodule']['db'], and not $config['db']

You can get the configuration settings of the module in this way:
$moduleManager = $this->getServiceLocator()->get('ModuleManager');
$applicationModule = $moduleManager->getModule('Application');
$applicationConfig = $applicationModule->getConfig();

Related

Ruby/Rails organizing and loading constants for an entire module

This question may just be for Ruby, but it was from working on a Rails that spurred me asking this question.
Suppose I am creating a new module so that I can better organize correlated/coupled code. Let's call this module amazing_feature and all of it's classes/submodules are located in the app/services directory. So according to code loading principles, the entire module should be in the app/services/amazing_feature directory in order to be loaded properly.
Let's say that I have two classes for this module:
# app/services/amazing_feature/thing_one.rb
module AmazingFeature
class ThingOne
...
end
end
# app/services/amazing_feature/thing_two.rb
module AmazingFeature
module ThingTwo
...
end
end
There are some constants that I would like to be available for all of the classes/submodules within module AmazingFeature, as well as being available from the AmazingModule namespace for any external code (eg, other controllers and models, in the Rails point of view). For example, if I want to define MY_CONSTANT = 1, then it would be accessible as just MY_CONSTANT within the module and as AmazingFeature::MY_CONSTANT from outside the module.
So the question is, how can I actually accomplish this in Ruby or Rails? There are thoughts that I've had, approaches that think may work, or approaches that I have seen elsewhere, such as other SOF posts:
Make a file directly in app/services for the module that associate the constants directly to the module. I don't prefer this approach because it feels weird putting a file coupled to the module outside of its subdirectory.
# app/services/amazing_feature.rb
module AmazingFeature
MY_CONSTANT = 1
end
Load the constants globally as a Rails initializer (ie, in config/initializers). I also have the same dislike for this approach as above.
Create a Constants module in the subdirectory so that the constants are colocated with all other code for the module. I just don't know how to properly associate these constants to the parent module, so there is a missing piece in this code example.
# app/services/amazing_feature/constants.rb
module AmazingFeature
module Constants
MY_CONSTANT = 1
end
end
# Now what??? :(
Some other approach? I'm at a loss here.
Thank you.
You can do whatever you want of course, but take some inspiration from popular gems:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record.rb
https://github.com/sparklemotion/nokogiri/blob/master/lib/nokogiri.rb
https://github.com/heartcombo/devise/blob/master/lib/devise.rb
It is normal to rely on Ruby autoloaders to map the names of your constants (AmazingFeature) to file names that contain those constants. So AmazingFeature could map to load/path/amazing_feature.rb and AmazingFeature::Greatness could map to load/path/amazing_feature/greatness.rb.
I'd advise doing this and pretty soon it won't feel weird :)
I think this is a good idea:
# app/services/amazing_feature/constants.rb
module AmazingFeature
module Constants
MY_CONSTANT = 1
end
include AmazingFeature::Constants
end
module AmazingModule
include AmazingFeature::Constants
end
# Then
AmazingFeature::MY_CONSTANT # => 1
AmazingModule::MY_CONSTANT # => 1

Namespacing within `app` directory

In our app directory, we want some of the sub-directories to contain namespaced classes, and some that contain top-level classes. For example:
app/models/user.rb defines ::User
app/operations/foo.rb defines ::Operations::Foo
app/operations/user/foo.rb defines ::Operations::User::Foo
Our application.rb contains the following configuration:
config.paths = Rails::Paths::Root.new(Rails.root)
config.paths.add 'app/models', eager_load: true
config.paths.add 'app', eager_load: true
This works fine in most cases, but sometimes in development mode and with Rails' autoreloading turned on, this leads to the wrong classes being loaded. For instance ::User is mistaken for Operations::User and vice-versa.
Is there a way to configure this behavior so that it works without any errors?
If not, the only workaround I can think of is to create a second directory for "namespaced" classes, along the lines of app and app_namespaced. Or else app/namespaced, since app-level code should reside within app. But these seem like ugly workarounds to me.
Edit: A little example as asked for by #dgilperez:
# app/models/user.rb
class User
end
# app/models/group.rb
class Group
def some_method
# Since we're in a top-level namespace, User should always
# resolve to ::User. But, depending on some seemingly random
# factors, it sometimes resolves to Operations::User.
User.new
end
end
# app/operations.rb
module Operations
end
# app/operations/user/create.rb
module Operations::User
class Create
def some_method
# Here, as expected, I need to prefix with "::" as
# 'User' would refer to the module we're currently in.
# That's fine and works.
::User.new
end
end
end
Yes, this is a downside of rails' autoloading. By default, it loads everything from /app, but first level of directory structure is not part of the names. It's so that app/models/user.rb can define User, not require it to be Models::User.
You don't need to mess with the load paths. Several approaches/workarounds available here.
In my current project we just double the namespacing directory. Meaning that if we want to define ServiceObjects::User::Import, we put it into app/service_objects/service_objects/user/import.rb
I personally prefer a variation of that approach, which is to put all "non-standard" stuff into app/lib (can be app/custom or anything you want). This way, there's no weird duplication of directory names and all custom code is nicely contained.

Call functions/variables/tables from a separate file in Lua

I'm currently working on a fairly detailed project in Lua, specifically using LOVE2D. I'm currently using require'file' in order to access different parts of my project, but this seems like very poor form. I've ran into the problem of overwriting tables from different files with the same name. There must be a professional, cleaner way to do this, but I haven't been able to find one. Can somebody help me?
Using require is the right way to do it.
Think of a module as a function that gets executed when it's loaded. It's return value is cached and returned on subsequent require calls. Just like you would use local variables to limit the scope in a function, you can do the same in a module.
I'm guessing your modules are implemented as global tables:
mymodule = {}
function mymodule.foo()
return 'bar'
end
And you load the module like:
require 'mymodule'
Just change the module table to a local variable and return it:
local mymodule = {}
function mymodule.foo()
return 'bar'
end
return mymodule
Then, you can load the module with any name you choose:
local mymodule = require 'mymodule'
Since you don't create global variables you don't have to worry about overwriting other modules.
The example used above is from the Module Tutorial on the lua-users.org website. Check it out for more info about creating modules. Also, How to write Lua modules in a post-module() world is also worth reading.

Adding to Rails.application.config before initializers run

I want to inject a custom property (hash map) into my Rails.application.config. It seems that the way to do it is simply to assign a new variable in environment.rb:
Rails.application.config.feature_map = { :email => true }
I need to access this map through various places in my application, like the user model, controllers, and rake tasks.
Other gems, like devise, also need access to this. The problem is that adding it to environment.rb seems to be too early in the application life-cycle.
I have code in initializers/devise.rb like this:
if Rails.application.config.feature_map[:email] = true
The server complains that this field doesn't exist.
I also use it to add additional validation in my user model:
if Rails.application.config.feature_map.enabled?(:username)
validates_length_of :username, :in => 3..50
I also get a runtime error here about undefined feature Rails.application.config.feature_map
Where can I move this so that I can access it as early as in initializers and in my model class? I tried moving it into a new initializers/feature_map.rb file, but that didn't work either.
Put it in config/application.rb:
module MyRailsApp
class Application < Rails::Application
config.feature_map = ActiveSupport::OrderedOptions.new
config.feature_map.email = true
end
end
Anything you set in there will be default for all environments, but can be overridden per environment in config/environments/*.rb.
Gems like Figaro and .env will help you load up your config even before the loading of initializer.rb
Unless there is a strong reason that you wouldn't wanna use environment variables, I would recommend using either of those gems since they are the recommended way of adding your custom configs.
Edit: See Jimmy Cuadra's answer above, which I ended up going with.
I found an alternative solution: this answer to manipulate the order of initializers.
I can rename my initializer to 00_feature_map.rb and it loads first.

Symfony sfGuardPlugin: disable default routes

I'm using the sfGuardPlugin in symfony 1.4 and I'm wondering how to get rid of its "default" routes. I mean by that the "guard/users", "guard/permissions" and "guard/groups" routes.
Indeed I have designed my own backend without admin generator, and I've recreated these three pages with customs urls. So how can I disable the access to the default sfGuard pages ?
app.yml:
all:
sf_guard_plugin:
routes_register: false
as stated in the documentation.
You should update the file
/config/sfDoctrineGuardPluginConfiguration.class.php
to the lasted version.
Before the lasted update, despite the documentation, the routes did get registed anyway.
It seems you are using the previous version of this file.
To desactivate these 3 modules : you just have to remove the sfGuardGroup, sfGuardUser, sfGuardPermission from the settings.yml for backend application.
all:
.settings:
enabled_modules: [default, sfGuardAuth, sfGuardGroup, sfGuardUser, sfGuardPermission]
In order to keep only the authentification module
all:
.settings:
enabled_modules: [default, sfGuardAuth]
However I have no idea what default is.
If you (i) still want to use the modules provided by the plugin, (ii) using your own routes, (iii) preventing people from using the default sfGuard routes and (iv) still have the default /:module/:action route (which is rather useful), you can override the sfGuardRouting class, which is here
plugins/sfGuardPlugin/lib/routing/sfGuardRouting.class.php
You can simply copy this file to your
lib/
directory and then play with the methods. For instance I just commented all the code of all methods of the class (since I made my own routes in my apps/myApp/config/routing.yml file) for the modules of the sfGuardPlugin), like this
class sfGuardRouting
{
static public function listenToRoutingLoadConfigurationEvent(sfEvent $event)
{
// $r = $event->getSubject();
// preprend our routes
// $r->prependRoute('sf_guard_signin', new sfRoute('/guard/login', array('module' => 'sfGuardAuth', 'action' => 'signin')));
// $r->prependRoute('sf_guard_signout', new sfRoute('/guard/logout', array('module' => 'sfGuardAuth', 'action' => 'signout')));
}
}

Resources