I have a question about how the prestashop hooks work's.
My Buddy asked me to prepare a simple module for him (the module is called "srodkipomocnicze").
The module is prepared (form with an available assortment ...).
Now I can not cope with connecting this module to the "displayHome" hook in proper position.
The problem is that the module is displayed but it is displayed at the very beginning of the page. It is displayed/listed in the correct position in the backend of the page but not on the frontend.
I tried to change its order, i.e. under the slide, before the slide etc., unchanged. the effect can be seen here http://dawid.kapka.net.pl/dawid/
Below the install function and screenshot
public function install() {
if (Shop::isFeatureActive()) {
Shop::setContext(Shop::CONTEXT_ALL);
}
if (!parent::install() || !$this->registerHook('displayHome')) {
return false;
}
$this->installDb();
return true;
}
public function displayFront(){
.....
echo $display;
}
public function hookDisplayHome(){
return $this->displayFront();
}
screenshot
On the target page, the module will be on one of the subpages and only there.
Thanks in advance
Related
I am trying to make it so that all of my page and module references can autocomplete in intellij.
Due to some sort of bug I am unable to do this like one normally would. (see here for more details: How to have geb static content recognized form test script )
In order to work around the above mentioned bug. I opted to create "getters" for all of my static content.
for example:
The Page:
class MyPage extends Page{
static content = {
tab {$(By.xpath("somexpath")}
}
Navigator tab(){
return tab
}
}
The Script:
//imagine we are in the middle of a feature method here
def test = at MyPage
test.tab().click()
So all of the above code works as I expect it to, and I want to redo my pages like this so that I can have autocomplete from the script side. Problems occur when I try to use this same technique for modules.
For example:
class MyPage extends Page{
static content = {
mod {module(new MyModule())}
}
MyModule mod(){
return mod
}
}
If I try and access mod from the script like so
//imagine we are in the middle of a feature method here
def test = at MyPage
test.mod().someModContentMaybe().click()
I get the following error:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'MyPage' -> mod: 'MyModule' with class 'geb.content.TemplateDerivedPageContent' to class 'MyModule'
If I try to do the following in the page object:
class MyPage extends Page{
static content = {
mod {module(new MyModule())}
}
MyModule mod(){
return new MyModule()
}
}
I get the following error when attempting to access the module from the script:
geb.error.ModuleInstanceNotInitializedException: Instance of module class MyModule has not been initialized. Please pass it to Navigable.module() or Navigator.module() before using it.
I guess it wants me to take an instantiated Navigator Object and and to call module(MyModule) but I am not sure how this works or how one would decide which Navigator Object to call module from.
All in all, I just want to be able to autocomplete module Names and static content from my scripts.
The Book of Geb's section about modules answers your question. You should not manually call the module's constructor, but instead instead use the syntax described right at the beginning of the chapter. This solution gets rid of the exception and also solves the code completion problem for me:
static content = {
mod { module MyModule }
}
Now that the exception is gone here is how to add the getter you asked for:
def myModule() { mod }
You're getting a GroovyCastException when returning content that contains a module from a method whose return type is a class which extends geb.Module because navigators and modules returned from content definitions get wrapped in geb.content.TemplateDerivedPageContent.
You can unwrap them using the as keyword as explained in the manual section about unwrapping modules returned from the content DSL. So, for one of your examples it would look like this:
MyModule mod(){
mod as MyModule
}
I think the problem is you content block. Modules are defined via Navigators' module method:
static content = {
mod { $("div.module").module(MyModule)
}
So no constructor calling required.
In my controller, via service, I get from DB a list of the names of widgets (eg. chart, calendar, etc). Every widget implements WidgetInterface and may need other services as its own dependencies. The list of widgets can be different for each user, so I don't know which widgets / dependencies I will need in my controller. Generally, I put dependencies via DI, using factories, but in this case I don't know dependencies at the time of controller initialization.
I want to avoid using service locator directly in controller. How can I manage that issue? Should I get a list of the names of widgets in controller factory? And depending on widgets list get all dependencies and put them to controller?
Thanks, Tom
Solution
I solved my issue in a way that suggested Kwido and Sven Buis, it means, I built my own Plugin Manager.
Advantages: I do not need use service locator directly in controller and I have clear and extensible way to get different kinds of widgets.
Thank you.
Create your own Manager, like some sort of ServiceManager, for your widgets.
class WidgetManager extends AbstractPluginManager
Take a look at: Samsonik tutorial - pluginManager. So this way you can inject the WidgetManager and only retrieve the widgets from this manager as your function: validatePlugin, checks whether or not the fetched instance is using the WidgetInterface. Keep in mind that you can still call the parent ServiceManager.
Or keep it simple and build a plugin for your controller that maps your widget names to the service. This plugin can then use the serviceLocator/Manager to retrieve your widget(s), whether they're created by factories or invokableFactories. So you dont inject all the widget directly but only fetch them when they're requested. Something realy simplistic:
protected $map = [
// Widget name within the plugin => Name or class to call from the serviceManager
'Charts' => Widget\Charts::class,
];
public function load($name)
{
if (array_key_exists($name, $this->map)) {
return $this->getServiceManager()->get($this->map[$name]);
}
return null;
}
Injecting all the Widgets might be bad for your performance so you might consider something else, as when the list of your widgets grow so will the time to handle your request.
Hope this helped you and pushed you in some direction.
This indeed is a interesting question. You could consider using Plugins for the widgets, which can be loaded on the fly.
Depency injection is a good practise, but sometimes, with dynamic content, impossible to implement.
Another way to do this, is to make your own widget-manager. This manager then can load the specific widgets you need. The widget-manager can be injected into the controller.
Edit:
As you can see above, same idea from #kwido.
I would use a separate service and inject that into the controller.
interface UserWidgetServiceInterface
{
public function __construct(array $widgets);
public function getWidget($name);
}
The controller factory
class MyControllerFactory
{
public function __invoke(ControllerManager $controllerManager, $name, $requestedName)
{
$serviceLocator = $controllerManager->getServiceLocator();
$userWidgetService = $serviceLocator->get('UserWidgetService');
return new MyController($userWidgetService);
}
}
Then the logic to load the widgets would be moved to the UserWidgetServiceFactory.
public function UserWidgetServiceFactory
{
public function __invoke(ServiceManager $serviceLocator, $name, $requestedName)
{
$userId = 123; // Load from somewhere e.g session, auth service.
$widgetNames = $this->getWidgetNames($serviceLocator, $userId);
$widgets = $this->loadWidgets($serviceManager, $widgetNames);
return new UserWidgetService($widgets);
}
public function getWidgetNames(ServiceManager $sm, $userId)
{
return ['foo','bar'];
}
public function loadWidgets(serviceManager $sm, array $widgets)
{
$w = [];
foreach($widgets as $widgetName) {
$w[$widgetName] = $sm->get($widgetName);
}
return $w;
}
}
The call to loadWidgets() would eager load all the widgets; should you wish to optimise this you could register your widgets as LazyServices
I am trying to learn ZF2. I know that there are better methods to create notifications but as I said this is for learning purpose.
My idea is to save the notifications in the database. This is simple I can do it. My question is about how to show them. I have a partial for the header menu , I want to display them there.
I dont know if i am on the right track i currently have a view helper which i create via factory.
class TestMe extends AbstractHelper
{
protected $html;
public function __invoke($name = 'Unnamed')
{
// if($this->view->hasIdentity()){
// $user = $this->view->identity();
// }
//$this->testJS();
return "$name , this is Zend Framework 2 View Helper";
}
protected function htmlIt(){
}
protected function testJS($loggedIn = false){
$js = '';
$js .= <<<JS
alert('test');
JS;
$view = $this->getView();
$view->inlineScript()->prependScript($js);
}
}
I know this is nothing but I cant understand what is good an wrong. My idea is to pass ot the view helper an array with notifications for the user and display them. So I need a service for making calls to the database or there is another way?
ZF2 already has an Notification Helper Plugin. Have a Look at http://framework.zend.com/manual/current/en/modules/zend.view.helpers.flash-messenger.html
But if you really want to do it on your own, you may want to create an Controller Plugin http://framework.zend.com/manual/current/en/modules/zend.mvc.plugins.html.
There is a nice Tutorial for that here: http://lab.empirio.no/custom-controller-plugin-in-zf2.html
How are you supposed to conditionally display menu items based on roles in the Bootstrap Sample project? I was thinking of doing the following
Implement INavigatonRouteFilter - really just implementing the shouldRemove(Route navigationRoutes) method - by getting the default controller/action for the route and seeing if the user is authorized
Call NavigationRoutes.Filters.Add(myAuthorizationFilter) after configuring the NavigationRoutes in App_Start
There are two problems I see with this approach:
I don't actually know how to do the first step unless I add in a bunch of conditional statements to check for Controller's name explicitly
This seems like it could make NavigationRoutes.Filters very hard to deal with once there are a lot of filters or a desire for more modularity later on
I don't know that I've explained the problem clearly enough, but basically I want to use what is provided in the Bootstrap sample to implement authorization-based navigation menu display if at all possible. Using INavigationRouteFilter just seemed like the most natural way to do so.
For those looking for an answer or at least a quick fix.
Here's what I've come up with after 5 minutes and I most certainly haven't though about any side effects this may have.
routes.MapNavigationRoute<HomeController>("Index", c => c.Index())
.FilterRoute(() => !WebSecurity.IsAuthenticated);
You can either do all your filtering in your call to FilterRoute() or you can add more extension methods to save you some characters.
I'm thinking of .RequireRole("Adiministrators"); that calls WebSecurity.RequireRoles() in turn (or HttpContext.Current.User.IsInRole()) etc.
public static NavigationRouteBuilder FilterRoute(this NavigationRouteBuilder builder, Func<bool> func)
{
var currentRoute = builder._parent;
NavigationRoutes.Filters.Add(new BootstrapAuthorizationFilter(builder, x =>
{
if (x == currentRoute)
return func();
else
return false;
}));
return builder;
}
and BootstrapAuthorizationFilter is just a class implementing INavigationRouteFilter that calls func() in its ShouldRemove() method
public class BootstrapAuthorizationFilter : INavigationRouteFilter
{
private NavigationRouteBuilder builder;
private Func<NamedRoute, bool> func;
public BootstrapAuthorizationFilter(NavigationRouteBuilder builder, Func<NamedRoute, bool> func)
{
this.builder = builder;
this.func = func;
}
public bool ShouldRemove(Route navigationRoutes)
{
if (navigationRoutes is NamedRoute)
return func(navigationRoutes as NamedRoute);
return false;
}
}
Clearly nothing fancy and I'm not sure if I'd use it in production.
But I think is simple enough and works (for the cases I tested).
Having said that, I hope the new routing functionality is going to be released soon :)
I have a quick question here. Can any one please help me to sort out this problem.
I'm new to windows Phone. I'm developing an Application where i can change my Font styles for the entire application . I have three different Resource file to set three different types of font styles. The resource file are set to application in App.xaml.cs file. Now i need to support to change the styles in Application run time from Application Changestyles page. So i need to call the method in app.xaml.cs from changestyles.xaml.cs page.
private void LoadResourceDictionary()
{
var dictionaries = new ResourceDictionary();
string source = String.Format("/Testapp;component/Large.xaml");
var themeStyles = new ResourceDictionary { Source = new Uri(source, UriKind.Relative) };
dictionaries.MergedDictionaries.Add(themeStyles);
App.Current.Resources = dictionaries;
ResourceDictionary appResources = App.Current.Resources;
}
I need to call this method to set the another resource to my application in run time.
Is it possible to resolve this issue?
Make this method public static and you can call it from everywhere: App.LoadResourceDictionary();
Here is a generic how to based on the code I needed for an app I am writing. I know the circumstances are slightly different, but it may help someone else who is after a similar solution:
In MainPage.xaml you create a method as follows:
public static void InMainPage()
{
System.Diagnostics.Debug.WriteLine("Hi I am a method in MainPage.xaml.cs");
}
Now in App.xaml.cs you can call it in any method as such:
MainPage.InMainPage();
AND IT WORKS FOR YOU CIRCUMSTANCE IN THE REVERSE DIRECTION
In App.xaml.cs you create a method as follows:
public static void InAppXaml()
{
System.Diagnostics.Debug.WriteLine("Hi I am a method in App.xaml.cs");
}
Now in Mainpage.xaml.cs you can call it in any method as such:
App.InAppXaml();
Tested and works well. Hope it helps!