January 30, 2009

no themes patch!

I’ve spend some time today playing around with the isEnableZMThemes setting and the consequences.

The main issue so far is that even though Zen Cart templates work fine now, quite a few plugins are useless, because they manipulate the final HTML via the call to ZMPlugins::filterResponse().

To fix this, I created a new file patch today. It’s the first since quite a long time which goes to show that things have been rather stable for a while.

The new patch will modify includes/application_bottom.php and insert a single (rather long) new line. That line contains the full response filtering and event handling code required to make plugins work.

For example, the page_stats plugin is now able to inject the page stats into Zen Cart templates and even page caching does work!

So, from 0.9.5 on it will be possible to cache the  HTML repsonse from a Zen Cart template using any of the available caching implementations (xcache, memcache, file) to speed up page delivery!

This brings us a lot closer to a stripped version of ZenMagick that does not include theme code and only supports plugins and admin enhancements. I wonder if that would be good to go back to the zen-cart site as add-on

widgets

Tags: , , , , , ,
Filed under: ZenMagick — DerManoMann @ 1:20 am

In my last post I mentioned widgets. Today I’d like to write a bit more about what they will be in the context of ZenMagick.

Without beeing to much affected by other applications use of widgets (I’ve never used a WordPress widget, for example), my idea of a widget is that of a self contained piece UI and code. (more…)

January 29, 2009

plugin news

Tags: , , , , , , , , ,
Filed under: ZenMagick — DerManoMann @ 1:15 am

I figured it is time to write an update on plugin development. Since most work these days is on plugins (and the corresponding changes to core to make them work, of course!), that’s where most of my spare time goes.

A number of different things are happening at the same time, thus slowing things down a bit..

  • Product associations
    I haven’t made much progress here. My initial investigaion into jquery 1.3 was not very successful – I guess it will need some more time for plugin coders to catch up with the new version.
    Only progress is that there is now an Ajax controller that allows to lookup existing associations. Next step will be to implement creating/updating associations and then I should be able to finally work on the general UI and hook it all up.
  • Settings
    After an email conversation with one of our clients I have started working on a settings plugin. The plan is to have a nice UI to create new settings rather than editing the global local.php file.
    Of course, this did not go without creating some unexpected work! To make things look nice and customizable, I’ve started working on something that has been on my list for a while: widgets.
    Widgets are an object oriented version of Zen Cart’s zen_cfg_xxxx() functions [for example: zen_cfg_select_drop_down()]. The advantage of using classes is that it is possible to:

    • customize the UI
      This is possibly not that important, but just fun to have. For example, I’ve created a boolean form widget that can either render as radio button group or select/dropdown.
    • Each widget can have different parameter
      Since widgets are configured as bean using a GET parameter style (name=deng&foo=bar), it’s easy to implement and configure custom properties for each widget
  • Subscriptions
    One of my clients is very close to moving a new plugin to production that allows customers to subscribe to orders. This means they can select from a range of schedules (weekly, monthly, etc.) and new orders will be generated automatically.
    The only manual step is that payments are not integrated. The current payment API is tricky at best and messing even more was nothing I fancied. If the plugin proves useful it might be something for the future.
    At this stage I’ll hold off releasing this to the public until we’ve got some live data to see how well this is working.

January 23, 2009

ajax security

I’ve just checked in a change that allows to configure access and authentication requirements of Ajax calls on method level. That means it is possible to restrict single methods of an Ajax controler to HTTPS, or require to be registered.

The second would then allow to use the sessions account details rather than an accountId from the URL. That way it would be ensured that users can’t access other users data.

January 19, 2009

theme support toggle

There has been a setting isEnableZenMagick in ZenMagick since the very first releases. Initially, it was intended as simple switch to disable ZenMagick completely. However, over time this morphed into a ‘disable themes‘ flag and recently is was a bit broken too.

I checked in some changes to get this working again. To reflect the changed behaviour I also renamed the setting to isEnableZMThemes.

I thought about removing the flag completely. After all, if you want to get rid of ZenMagick, the easiest way is to remove all patches using the installation page. However, it occured to me that keeping the flag might actually increase the potential user base. Reason being that with the storefront disabled, ZenMagick would become interesting for people that would like to use the admin enhancements (for example the Catalog Manager).

Also, to counter the claim about ZenMagick being a Zen Cart fork, the project could perhaps be broken into two packages:

  • ZenMagick (core)
    The API and basic admin pages
  • ZenMagick themes
    The majority of the code including the default theme, controller classes, etc.

So this is only a thought I don’t even know if want that. It would be a bit of work to get the current build process changed to create two separate packages. I suspect at least some files would need to be split in order to cleanly separate functionallity. Oh well, another item on my list of things to think about.

product associations

Since it is now possible to inject methods into ZMObject based classes, I figured I might as well use it. In fact, this is how most new (framework) features come to exist.

So, what better place than to keep improving the unfinished product associations plugin. I decided to attach a new JSON/Ajax method to the catalog ajax controller. Of course, the devil is in the details and I soon found myself fixing some obscure things in ZMBeanUtil and the reflection code in ZMAjaxController to allow it to find injected methods :}

Once that was all sorted I really could use the existing catalog controller to access my new method :) ! The nice thing is that I do not have to inherit, but due to the fact that the injected method always has access to the original target object, it’s easy to access all relevant data/methods of  the original controller.

And, because it is so nice, another screenshot of the current state of the product picker. The image shows the picker on the second page of products of the ‘Big Linked’ category with one product selected in the current list and one from another category.

product-picker3

January 16, 2009

method injection

Tags: , , , , , , , ,
Filed under: PHP,ZenMagick — DerManoMann @ 12:11 am

I just checked in a fancy change to ZMObject that allows to dynamically add methods to any class (assuming the class extends from ZMObject) at runtime.

So, what’s the deal? you ask? Well, I always have been slightly uncomfortable about the fact that if multiple plugins wanted to extend/modify an existing core class, say, for example, ZMProduct, there could be only a single winner.

The alternative is to add new services and use them in templates. Of course, that is ok and all, but wouldn’t it be much cooler to just use the affected class directly without something like the following?

$value = MyService ::instance()->getFoo($product);

So, compare that with:

$value = $product->getFoo();

And here is how this can be done:

class MyService {
/**
* @param mixed target The instance the method was invoked on (instance of ZMProduct).
* @param var ... some Some single parameter.
*/
public function getFoo($target, $some) {
return "foo: ".$some.": ".$target->getName();
}
}

ZMObject::attachMethod(‘getFoo’, ‘ZMProduct’, array(new MyService (), ‘getFoo’));
$product = ZMProducts::instance()->getProductForId(3);
echo $product->getFoo(‘xx’);

So, what does it do?

  • First there is a new class that implements the calculation of the new property.
  • Next we attach an instance of MyService as handler of getFoo calls on ZMProduct objects
  • Load a product from the database
  • call getFoo('xx') on $product

The same works if the handler is a simple function:

ZMObject::attachMethod('getFoo', 'ZMProduct', create_function('$target, $some', 'return "foo: ".$some.': '.$target->getName();'));

Another of those things that are not strictly necessary, but nice to look at :)

January 15, 2009

jquery 1.3

As part of my work on the new product picker I’ve upgraded to jquery 1.2.6. So today they release 1.3!

Sounds like a goor release with tons of new stuff. I guess I’ll be upgrading again soon :)

In a way  this is good, because it means I’ll be reviewing all used JS and try consolidate things a bit. In particular the used plugins should be looked at again. Most use cases are quite simple, so it would make sense to review the available options again and go for the best performing alternative.

Another thing is that I noticed that the catalog manager page doesn’t support injecting header code. This is going to be more important with more plugins coming and each having its own requirements.

In fact, I might change the current system of passing around a ZMPluginPage instance to another service. This would also make it a lot easier to avoid including the same file more than once. It also would mean there is no need to change the admin page .php file for each new plugin that wants to include something different.

Of course, there are also the other usual suspects like IE compatibility. I’ve noticed a few glitches in the category tree and right now, the product picker doesn’t really look that good at all :/

On the plus side, I’ve extracted the javaScript and CSS into separate files, cleaned up the code, wrapped it in it’s own class and generally am finished with the actual UI JS coding.

Next will be a bit more layout and beautification. After that the jquery/plugin review. Suggestions for good and simple widgets are welcome. I’ll be looking at plugins/code for:

  • (non-)modal dialogs
  • a tree view
  • tabs (incl. lazy loading via Ajax)
  • a date picker
  • other suggestions?

January 14, 2009

random facts XXII

1. Dynamic CSS

Yesterday the question popped up whether it is possible to access the ZenMagick API from within a CSS / JavaScript file.

This obviously involves a performance penalty. Nevertheless it is possible.
The first step is to rename the file. This is essential, because otherwise your PHP will never be executed. For example, you’d rename your site.css file to site.css.php. The second step is to include the ZenMagick file external.php.
Example: (This examle assumes that your CSS file is located in the theme’s content folder)

<?php include '../../../external.php'; ?>

After that you can start using the ZenMagick API as you would in any other template file.

2. Organizing template files in subfolder

Currently all views with the exception of email and popup templates are stored in  a single folder. With the way URLs are mapped in ZenMagick (ZMUrlMapper) it is easy to change that.

Let’s have a look at how things are done for popups right now (core/settings/url_mapping.php):

$urlMapper->setMapping(null, 'popup_search_help', 'popup_search_help', 'PageView', 'subdir=popup');

The main_page value popu_search_help is mapped to a template (also) named popu_search_help. However, the property subdir is set (on the configured view ZMPageView).This means the view will look for the template file in a subfolder popup. To add to this twist, there is some magic code to trim everyting up to the first ‘_’ in the template name when constructing the final filename. This has historic reasons and is likely to be removed in the future. So, this mapping will resolve to (within the theme folder): content/views/popup/search_help.php.

There is another way of archiving the same that is a bit more sane (and a lot simpler), though:

$urlMapper->setMapping(null, 'popup_search_help', 'popup/search_help');

The template value is considered to be the filename without the set template filename extension. So this second mapping will resolve to the same file as the first, just in a much more elegant way.

Conclusion: To organize your view templates in different folders, all that is requires it to add a relative path to the mapping.
Please note that this would require some more mappings than there exist now. Typically, the main_page value is the template name, so nothing needs to be configured at all.

January 13, 2009

more ajax coming

With 0.9.4.1 out of the way I’ll be continuing with some more Ajax related work. Next thing on my list is a nice looking product picker. So far I’ve succeeded in reusing the category tree plus some jquery code to load products for the selected category.

To make things even better I just added pagination support to ZMAjaxCatalogController::getProductsForCategoryIdJSON(), so it will eventually be possible to page through all products of a category using Ajax.

(more…)

Next Page »