PlayFramework instantiate object in current request scope? - scala

I am currently active PlayFramework learner who came from world of PHP.
For example I have a Head block object in my app, which should hold title, charset encoding, meta information, etc. Something similar to Magento blocks, but without XML declaration
package blocks.Page
object Head {
var title: String = "";
}
In Application.index() method I have
blocks.Page.Head.title
Ok(views.html.application.index());
And finally in html template
#import blocks.Page.Head
<title>#Head.title</title>
However, blocks.Page.Head object is defined for entire application scope, not for single request. This object is the same for each request.
What is the right way to do, what I am trying to do? I can create container with all blocks and instantiate it with each request, then just pass to all templates. But I have a feeling that this is wrong way.

Just use usual class instead of object and pass instance to template as parameter.
Like this:
package blocks.Page
case class Head(title: String = "")
Controller:
val head = Head("Blah")
Ok(views.html.application.index(head))
And template will looks like:
#(head: blocks.Page.Head)
...
<title>#head.title</title>

I know the feeling when coming from a request-oriented language like PHP :). However, consider application-wide access as a gift of a VM (in PHP we need to go the extra mile of using some bytecode and data caching tool like APC or eAccellerator).
I would probably create a blockManager class which gives you static access to blocks by name/tag/id from the template: Block.get("MyBlock"). Then you can define and later modify your caching / storing strategy (holding in memory vs. loading from storage) without affecting your templates.

Related

AEM - How to pass data to a component

Usually an AEM component is retrieving its data from a JCR node, but I was wondering whether it's possible to pass data to it in HTL. Sure, there's data-sly-resource, but as far as I know this way you can only pass a JCR node.
So in an actual case I've got data in a model that's retrieved from elsewhere. Yet I'd like to use existing components. I'm aware that the data must at least match the component-types' model.
But what if the component I'd like to use is using an model that got its data injected like
#Inject
#Optional
String[] itemList;
So in my stubborn thoughts it should be possible to somehow pass a string array like
<div data-sly-resource="${myModel.aStringArray # resourceType='my/component' }"></div>
But like mentioned above this seems to be meant for passing nodes only.
Is there any way to accomplish passing data directly to a component (other than creating a template)?
You can pass additional information in the form of request attributes or selectors
Selectors
Selectors are the most straight forward of passing simple information. This is an array of strings that can be passed. This is quite useful to data that can act as flags ex:
Variant/Mode of the component
index of the component in a list if it is being included in a loop.
ID of the parent when building things like accordion, tabs
This approach is an abuse of selectors, but IMHO as long as you know what you are doing this shouldn't be a major concern.
<article data-sly-resource="${'path/to/resource' # selectors=['s1', 's2']}"></article>
You can add, replace or remove selectors while including the component. Checkout the documentation for the syntax. https://docs.adobe.com/content/help/en/experience-manager-htl/using/htl/block-statements.html#resource
Request Attributes
This option allows you to add custom request attributes to the component request. This can be used to pass objects as parameters to the component while including them.
These are standard http request attributes with convince of scoping them to a particular instance of script/resource inclusion. To use this you will end up needing a model class or use-js as there is little support to compose the data to be passed along in sightly.
<sly data-sly-use.settings="com.adobe.examples.htl.core.hashmap.Settings"
data-sly-include="${ 'productdetails.html' # requestAttributes=settings.settings}" />
https://docs.adobe.com/content/help/en/experience-manager-htl/using/htl/block-statements.html#request-attributes
There is another way. You can pass additional parameters to the Sling Model on initialization using data-sly-use. For example:
<div data-sly-use.model="${'com.model.Teaser' # test='abc'}"
You can read then the variable "test" in model from request:
#PostConstruct
private void initModel() {
String value = request.getAttribute("test");
// value is 'abc'
}
In order this to work correctly you need to make sure your Sling Model is adaptable from request #Model(adaptables = SlingHttpServletRequest.class}

GWT-Jackson-APT fails on $wnd.window JSON web-worker code for encoding strings

Finally having gotten GWT-Jackson-APT processors working and properly generating code for my classes, the one remaining hiccup I have is that for some reason gwt-jackson-apt uses the window JSON stringify (& parse) function.
$wnd.window.JSON.stringify(STRING)
The problem is that due to this being on a web-worker, $wnd.window is not defined. Even though JSON.stringify() is available in web-worker, the result is that the code won't run correctly, even though if I modify it to be just JSON.stringify() before uploading it works pefectly.
Is there a clean way to redefine which of these functions gets used in this instance?
What is the best means of going about fixing this so that my web-worker code doesn't try to call the functions that are not available in their context.
The library right now uses the elemental2 version of JSON Global.JSON.stringify
and if we look at the implementation of the JSON in the Global class we will find that it is assigned to the window instance here :
#JsType(isNative = true, name = "window", namespace = JsPackage.GLOBAL)
public class Global {
public static JSONType JSON;
}
when this is used as Global.JSON.stringify(someJsonObject) from GWT java code when compile it will produce $wnd.window.JSON.stringify(someJsonObject) or something very similar.
in order to fix this we need to access the native JSON in a different way that does not link it the current window instance.
one solution to this is to use JsInterop to interface directly with the JSON, something like this
#JsType(isNative = true, namespace = JsPackage.GLOBAL)
public class JSON {
public native static String stringify(Object jsonObj);
}
with this implementation we can use the JSON without the window prefix and when we use it in java like this JSON.stringify(someJsonObject) and notice how we no longer use the one from Global we end up with a generated Js that looks like this $wnd.JSON.stringify(someJsonObject)
i run a small test and implemented this JSON in the jackson-apt lib and switched to use the new implementation instead of using Global.JSON and all tests passed.
to me this looks like a good issue to be reported on the project repository. and i will apply the fix ASAP.

Add Arguments to Rythm template using Java

I'm writing a MVC portlet framework and I plan to use Rythm inside my views. I would like to pass various arguments to the view and was wondering if there is a way to declare these arguments for the view using Java at runtime? I know that I can declare arguments in the view using the #args tag and that I can add custom tags from Java, but I wanted to do something similar to how ASP.NET MVC passes helper classes (HtmlHelper #Html, UrlHelper #Url, Object #Model) to the view.
If all the arguments you planned to pass to the view are global (i.e. they applied to all render session and to all templates) then you should treated them as implicit variables, meaning template author don't need to declare them but they are free to use them. Examples of implicit variables are session, request, context etc.
For how to declare implicit variables, you can refer to:
Spring-rythm
Actframework
For how to configure Rythm engine with your implicit variable, refer to
Spring-rythm
ActFramework
For how to inject implicity variables into rythm engine for each render session, you can also refer to:
Spring-rythm
Actframework
For things like HtmlHelper my recommendation is to provide reusable rythm template as tags instead of Java object. Because you need to render html snippet, thus using rythm is a natural way to go instead of let the Java code to output the content.
For things like UrlHelper if it is all about String manipulation, you can go straight with Java code, but probably the public static method is more appropriate than helper instance

AS3 targeting controller class variable using string

I'm looking for a way of condensing some of my AS3 code to avoid almost duplicate commands.
The issue is that I have multiple variables with almost the same name e.g. frenchLanguage, englishLanguage, germanLanguage, spanishLanguage
My Controller class contains public static variables (these are accessed across multiple classes) and I need a way to be able to call a few of these variables dynamically. If the variables are in the class you are calling them from you can do this to access them dynamically:
this["spanish"+"Language"]
In AS3 it's not possible to write something like:
Controller.this["spanish"+"Language"]
Is there any way to achieve this? Although everything is working I want to be able to keep my code as minimal as possible.
It is possible to access public static properties of a class this way (assuming the class name is Controller as in your example:
Controller['propertyName']
I'm not sure how this helps to have "minimal code", but this would be a different topic/question, which might need some more details on what you want to achive.
Having said that, I like the approach DodgerThud suggests in the comments of grouping similar values in a (dynamic) Object or Dictonary and give it a proper name.
Keep in mind, that if the string you pass in as the key to the class or dynamic object is created from (textual) user input you should have some checks for the validity of that data, otherwise your programm might crash or expose other fields to the user.
It would make sense to utilize a Dictionary object for a set of variables inherited: it provides a solid logic and it happens to work...
I do not think this is what you are trying to accomplish. I may be wrong.
Classes in AS3 are always wrapped within a package - this is true whether you have compiled from Flash, Flex, Air, or any other...
Don't let Adobe confuse you. This was only done in AS3 to use Java-Based conventions. Regardless, a loosely typed language is often misunderstood, unfortunately. So:
this["SuperObject"]["SubObject"]["ObjectsMethod"][ObjectsMethodsVariable"](args..);
... is technically reliable because the compiler avoids dot notation but at runtime it will collect a lot of unnecessary data to maintain those types of calls.
If efficiency becomes an issue..
Use:
package packages {
import flash.*.*:
class This implements ISpecialInterface {
// Data Objects and Function Model
// for This Class
}
package packages {
import...
class ISpecialInterface extends IEventDispatcher

Testing view rendering with mock objects in Zend Framework

I have a controller action that calls a model that fetches a JSON object from a web service. The JSON object is converted to a PHP object via a mapper class and used in my view.
What I'd like to do is to write a unit test that mocks the web service response, calls my mapper class to map the response to my PHP object and then uses that object in my view. This way, I can use assertQueryContentContains() to check to see if the values are being properly mapped to my object and populated in my view.
What is the best way to do this?
So far, I've got this in my unit test class:
$view->search_session = new Zend_Session_Namespace('search');
Zend_Registry::set('is_mobile', false);
$view = new Zend_View();
$view->setScriptPath(APPLICATION_PATH . '/views/scripts/');
$view->addHelperPath(APPLICATION_PATH . '/views/helpers');
$layout = Zend_Layout::getMvcInstance()->setLayoutPath(APPLICATION_PATH . '/layouts/scripts/')->setLayout('layout-internal');
$layout->setView($view);
$mapper = new ListingDetailMapper();
$listing = $mapper->map($this->_createMockListing(), new ListingDetail());
$view->listing = $listing;
$this->getResponse()->setBody($layout->render());
$this->assertQueryContentContains('h3.fn', 'Test Business');
The problem that I have with this is that I'm having to setup everything manually that would normally be setup in my bootstrap or configuration file if I were to dispatch the request normally.
Is there a way to inject my mock object into my view, so I can render the view automatically as it would if I dispatched the controller action using $this->dispatch()?
Or, should I somehow be mocking the model class that would normally return the web service response and somehow inject that into my controller?
It seems like I'm working a little too hard by having to recreate my environment as if I had called $this->dispatch(). Plus, it kind of defeats the purpose of testing if you aren't using the same setup code as you would in a real environment.
You need to decide what type of test this is. Right now it's trying to be a unit test. From reading what you say in your question,
it kind of defeats the purpose of testing if you aren't using the same setup code as you would in a real environment
it sounds like you want to be doing a system test.
If you want to do a system test then start using use dispatch() fully. You will have to automate your database/datastore to import and remove test data at the same time.
If you are trying to do a unit test then your view script is making it hard for you. The view script should not really be aware of the layout. If you can fix that then you can clean that code up. Your view script should not be aware of Zend_Registry. Don't forget Zend_Registry is just a global variable hiding behind a pattern name. I would also say it should not be aware of Zend_Session. Any of the data these classes provide should be either set by the controller or in a view helper. If you can fix those you can clean up that code.
There is also a fundamental principle to keep in mind, that the more dependencies a piece of code has, the more work it will be to set up testing for it. Right now your view script has a lot of dependencies and that is why it is more work to unit test it.