I'm new to Robotlegs, and somewhat struggling with the first steps.
To learn the ropes I followed the first part of Joel Hooks' introduction and am now trying to create the same in RL2.
My current questions/problems are:
Which method has replaced the startup() in the Context
In the Context I can no longer just use "mediatorMap"; Do I need to create a MediatorMap Instance for this?
In the few RL2 example out there, many devs use the IConfig to configure their main Context; is this required, a good convention or optional.
..and in which way, is the Context 'configured' through this?
I spent the best part of the day looking for solutions. I apologize if I missed the obvious.
Thanks in advance for any incite.
part of the main class (mxml)
xmlns:context="contexts.*"
<fx:Declarations>
<rl:ContextBuilder>
<context:HelloWorldContext/>
</rl:ContextBuilder>
</fx:Declarations>
and the (non-compling) context .as
public class HelloWorldContext extends Context
{
public function HelloWorldContext()
{
this.install(MVCSBundle);
this.configure(HelloWorldConfig);
mediatorMap.map(ButtonView).toMediator(ButtonMediator); // Error: mediatorMap not defined
}
}
Which method has replaced the startup() in the Context In the Context
use context.install to install extension that you want to use.
most common one is MVCSBundle.
use context.configure with (new ContextView) argument will start your context initialization.
I can no longer just use "mediatorMap"; Do I need to create a
MediatorMap Instance for this?
you can inject IMediatorMap anywhere you need it, like in config
[Inject]
public var injector:IInjector;
[Inject]
public var mediatorMap:IMediatorMap;
[Inject]
public var commandMap:ISignalCommandMap;
In the few RL2 example out there, many
devs use the IConfig to configure their main Context; is this
required, a good convention or optional. ..and in which way, is the
Context 'configured' through this?
you can create your own config. Usually, in there you will map your commands, mediators and injections. You create one [PostConstruct] method which will call all theese stuff:
If you implement IConfig inside config, you dont need [PostConstruct] tag, because robotlegs will call configure function automatically once the dependencies have been injected.
[PostConstruct]
public function init():void {
context.logLevel = LogLevel.DEBUG;
// injector.fallbackProvider = new DefaultFallbackProvider();
mapSignalCommands();
mapMediators();
mapInjection();
context.afterInitializing(afterInit);
}
in your case you will have
_context:IContext;
public function MainApp()
{
_context = new Context();
_context.install(MVCSBundle);
_context.configure(HelloWorldConfig,new ContextView(this));
}
mediator thing goes to config on mapMediators();
Related
As the title says, is there a way to alter the ResourceManager's getStringArray() in a way that it splits the resources by semicolon, not comma?
The actual method can be found in the ResourceManagerImpl class, which can be found in in the package mx.resources.
Overriding that method would be fine, but ideally I'd like to write my own getStringArray with a variable separator, however, there seems to be no way of extending either the ResourceManager or ResourceManagerImpl class to somehow add that method.
Anyone got a clue what to do here?
The problem is not that you can't extend ResourceManagerImpl since it's not final, but rather that you have to be able to register your implementation with the application instead of the default one. And doing this is a bit tricky.
So first create your implementation:
public class MyResourceManager extends ResourceManagerImpl {
private static var instance:IResourceManager;
static public function getInstance():IResourceManager
{
if (!instance) instance = new MyResourceManager();
return instance;
}
override public function getStringArray(bundleName:String,
resourceName:String,
locale:String = null):Array {
//do your stuff
}
}
So we've overriden the getStringArray method. Notice that we've done the same for getInstance, because we want it to return a new instance of MyResourceManager instead of ResourceManagerImpl (we don't have to mark override because it's a static method). Also, you may have to write some import statements manually, because some of the classes you're using are marked as 'excluded'.
Now we have to tell Flex to use MyResourceManager instead of ResourceManagerImpl. We can do this with the following code:
import mx.core.Singleton;
Singleton.registerClass("mx.resources::IResourceManager", MyResourceManager);
The problem is that we have to do this before Flex registers ResourceManagerImpl, because you can't override it once it's registered. For this we need to create a custom preloader in which we do the registering (sadly, the Application's 'preinitialize' phase is not early enough).
public class RegisteringPreloader extends DownloadProgressBar {
override public function initialize():void {
super.initialize();
Singleton.registerClass("mx.resources::IResourceManager",
MyResourceManager);
}
}
Now assign the custom preloader to the application and we're done:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
preloader="RegisteringPreloader" >
For further info I refer you to a fairly similar, but somewhat more elaborate answer that I wrote for a different question: Is there a way to listen for events on the pop up manager class?
Just for the record: if you want to provide your localization with array of strings containing commas, it is way easier to use getObject method of IResourceManager.
In your properties file:
my.beloved.strings: ["That's it, string one", "Okay, string two"]
In your code:
var strings:Array = _resourceManager.getObject(_bundleId, 'my.beloved.strings') as Array;
var stringOne:String = strings[0];
You don't have to override anything this way.
I'm using robot legs, I've got a bunch of ServiceResponses that extends a base class and have a dependency on a Parser, IParser. I need to wire in a parser specific to the subclass. Here's an example:
ModuleConfigResponse extends SimpleServiceResponse and implements IServiceResponse.
The initial part is easy to wire in the context, here's an example:
injector.mapClass(IServiceResponse, ModuleConfigResponse);
injector.mapClass(IServiceResponse, SimpleServiceResponse, "roomconfig");
..etc
Each Response uses a parser that is used by the baseclass:
injector.mapValue(IParser, ModuleConfigParser, "moduleconfig");
injector.mapValue(IParser, RoomConfigParser, "roomconfig");
The question is how to tie these together. The base class could have:
[Inject]
public var parser : IParser
But I can't define the type ahead of time. Im wondering if there a nice way of wiring this in the context. For the moment I've decided to wire this up by instanciating responses in a ResponseFactory instead so that I pay pass the parser manually in the constructor.
injector.mapValue(IParser, ModuleConfigParser, "moduleconfig");
I realised that not everything can be mapped in the context, RL trapped me into this way of thinking. But I've realised that its far better to map a factory to produce these objects which have very specific dependencies, than littler the codebase with marker interfaces or strings :)
one solution is to have the following in your base class:
protected var _parser : IParser
Then for instance in ModuleConfigResponse
[Inject(name='moduleconfig')]
public function set parser( value : IParser ) : void{
_parser = value;
}
But TBH, using named injections is STRONGLY discouraged, you might as well use a marker interface:
public interface IModuleConfigParser extends IParser{}
the base class stays the same, but ModuleConfigResponse would then use:
[Inject]
public function set parser( value : IModuleConfigParser ) : void{
_parser = value;
}
I have the following packages:
spark
spark.engine
Within spark I have a class SeCore; and within spark.engine I have SeStepper and SeKeyboard.
What I'm trying to achieve is have SeCore as being the only class that can create an instance of SeStepper or SeKeyboard. This can be achieved by moving SeCore into the spark.engine package and making the other two classes internal, but I'd like to have SeCore in the spark package if possible.
I've tried making my own namespace to handle this, like so:
package spark.engine
{
import spark.namespaces.spark_core;
use namespace spark_core;
spark_core class SeStepper extends SeObject
{
//
}
}
However I get the error:
1116: A user-defined namespace attribute can only be used at the top
level of a class definition.
Are there any other approaches I can take to achieve what I'm after?
99% of the time, marking anything as 'internal' is a bad idea. It's better to have a naming convention for 'off-limits' classes and members, and allow developers to go there at their own risk. Marking things as 'internal' or 'private' is something that should only be done rarely, and with great forethought.
However, you could enforce this behavior at run time by using a read-only property in SeCore and checking its value from SeStepper and SeKeyboard.
Following is pseudocode, haven't used AS3 in a while.
In SeCore
private var _createAuthorized = false;
public function get CreateAuthorized():boolean {return _createAuthorized;}
private function createSeStepper(){
_createAuthorized = true;
var obj = new SeStepper(this)
_createAuthorized = false;
return obj;
}
in SeStepper
public function SeStepper(core:SeCore){
if (!core.CreateAuthorized) throw new Error("Only SeCore can do this");
}
I can't agree with the answer, i mean making things public is way to invite hackers. I can execute any public functions in any flash running on my computer in any context i want, i can even override their execution in memory since they are easy to find, whereas doing something like that with private/internal functions is almost impossible.
I am new to Zend framework and I have a problem.
I created a controller abstract class which implements the functions like:
protected function AddError($message) {
$flashMessenger = $this->_helper->FlashMessenger;
$flashMessenger->setNamespace('Errors');
$flashMessenger->addMessage($message);
$this->view->Errors = $flashMessenger->getMessages();
}
protected function activateErrors()
{
$flashMessenger = $this->_helper->FlashMessenger;
$flashMessenger->setNamespace('Errors');
$this->view->Errors = $flashMessenger->getMessages();
}
So for each controller I am able to use
$this->AddError($error);
And then I render $error in layout.
So I want not to deal with flashMesenger in every controller.
but I have to execute the activateErrors when each action is executed.
for example
I have an controller test
class TestController extends MyController {
public function indexAction() {
$this->AddError("Error 1");
$this->AddError("Error 2");
$this->activateErrors();
}
public function index1Action() {
$this->AddError("Esdsd 1");
$this->AddError("sddsd 2");
$this->activateErrors();
}
}
Is there a way that I could execute this activateErrors in each action for every controller at the end of action without duplicating the code.
I mean I do not want to include this code at every action. Maybe there is a way to include it in my abstract class MyController.
Anybody any Idea?
thanks
What about using a postDispatch hook, in your parent MyController ?
Quoting that page :
Zend_Controller_Action specifies two
methods that may be called to bookend
a requested action, preDispatch() and
postDispatch(). These can be useful in
a variety of ways: verifying
authentication and ACL's prior to
running an action (by calling
_forward() in preDispatch(), the action will be skipped), for instance,
or placing generated content in a
sitewide template (postDispatch()).
Maybe this might do the trick ?
I actually contributed an enhancement to FlashMessenger which provides a lot of the functionality you're looking for.
A database application that I'm currently working on, stores all sorts of settings in the database. Most of those settings are there to customize certain business rules, but there's also some other stuff in there.
The app contains objects that specifically do a certain task, e.g., a certain complicated calculation. Those non-UI objects are unit-tested, but also need access to lots of those global settings. The way we've implemented this right now, is by giving the objects properties that are filled by the Application Controller at runtime. When testing, we create the objects in the test and fill in values for testing (not from the database).
This works better, in any case much better than having all those objects need some global Settings object --- that of course effectively makes unit testing impossible :) Disadvantage can be that you sometimes need to set a dozen of properties, or that you need to let those properties 'percolate' into sub-objects.
So the general question is: how do you provide access to global application settings in your projects, without the need for global variables, while still being able to unit test your code? This must be a problem that's been solved 100's of times...
(Note: I'm not too much of an experienced programmer, as you'll have noticed; but I love to learn! And of course, I've already done research into this topic, but I'm really looking for some first-hand experiences)
You could use Martin Fowlers ServiceLocator pattern. In php it could look like this:
class ServiceLocator {
private static $soleInstance;
private $globalSettings;
public static function load($locator) {
self::$soleInstance = $locator;
}
public static function globalSettings() {
if (!isset(self::$soleInstance->globalSettings)) {
self::$soleInstance->setGlobalSettings(new GlobalSettings());
}
return self::$soleInstance->globalSettings;
}
}
Your production code then initializes the service locator like this:
ServiceLocator::load(new ServiceLocator());
In your test-code, you insert your mock-settings like this:
ServiceLocator s = new ServiceLocator();
s->setGlobalSettings(new MockGlobalSettings());
ServiceLocator::load(s);
It's a repository for singletons that can be exchanged for testing purposes.
I like to model my configuration access off of the Service Locator pattern. This gives me a single point to get any configuration value that I need and by putting it outside the application in a separate library, it allows reuse and testability. Here is some sample code, I am not sure what language you are using, but I wrote it in C#.
First I create a generic class that will models my ConfigurationItem.
public class ConfigurationItem<T>
{
private T item;
public ConfigurationItem(T item)
{
this.item = item;
}
public T GetValue()
{
return item;
}
}
Then I create a class that exposes public static readonly variables for the configuration item. Here I am just reading the ConnectionStringSettings from a config file, which is just xml. Of course for more items, you can read the values from any source.
public class ConfigurationItems
{
public static ConfigurationItem<ConnectionStringSettings> ConnectionSettings = new ConfigurationItem<ConnectionStringSettings>(RetrieveConnectionString());
private static ConnectionStringSettings RetrieveConnectionString()
{
// In .Net, we store our connection string in the application/web config file.
// We can access those values through the ConfigurationManager class.
return ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ConnectionKey"]];
}
}
Then when I need a ConfigurationItem for use, I call it like this:
ConfigurationItems.ConnectionSettings.GetValue();
And it will return me a type safe value, which I can then cache or do whatever I want with.
Here's a sample test:
[TestFixture]
public class ConfigurationItemsTest
{
[Test]
public void ShouldBeAbleToAccessConnectionStringSettings()
{
ConnectionStringSettings item = ConfigurationItems.ConnectionSettings.GetValue();
Assert.IsNotNull(item);
}
}
Hope this helps.
Usually this is handled by an ini file or XML configuration file. Then you just have a class that reads the setting when neeed.
.NET has this built in with the ConfigurationManager classes, but it's quite easy to implement, just read text files, or load XML into DOM or parse them by hand in code.
Having config files in the database is ok, but it does tie you to the database, and creates an extra dependancy for your app that ini/xml files solve.
I did this:
public class MySettings
{
public static double Setting1
{ get { return SettingsCache.Instance.GetDouble("Setting1"); } }
public static string Setting2
{ get { return SettingsCache.Instance.GetString("Setting2"); } }
}
I put this in a separate infrastructure module to remove any issues with circular dependencies.
Doing this I am not tied to any specific configuration method, and have no strings running havoc in my applications code.