Category Archives: Development

How to use aggregation SQL functions with CakePHP

Have you ever wondering how to find MAX, MIN or AVG of a database table column in CakePHP way? Well I haven’t since yesterday. The solution is quite simple and obvious.

Lets say you want to show the average views per post (in the example we have the views field in every post).
The SQL should be something like this:

SELECT AVG(views) FROM posts

Instead of using query() function you can use the CakePHP way:

$this->Post->find('first', array('fields'=>array('AVG(views) as avg_views')));

Hope this will help someone.

JSON and CakePHP

Last few articles in this blog are only for stupid problems and unfortunately this one will be the same.

I had to use JSON to update some chained select boxes. I am using one jQuery plugin for this. The problem is that if you code, most likely your debug setting in the core.php file is set to 1 (or 2). This way the developer can see errors from CakePHP.

When the level is set to 1, at the end of the page, there is an comment, displaying the processing time for the page, but when you use JSON, this comment causes troubles (probably, because JSON doesn’t accept this type of comments) and the JS fail to process the response.

In order to check JSON, I needed to disable set debug level to 0 and after this to reset it again to 1 (for debugging purposes in other parts of the application).

So, the conclusion: bear in mind, that JSON doesn’t like HTML comments.

Hope this helps.

linxspy.com – track your links

Today I want to present you a small service which I wrote for a week /including the design/. πŸ™‚

I’ve wrote it, because few times I’ve exchanged some links with strangers and few weeks after this, my link was disappeared from their sites while their was on mine. It is a bit unfair isn’t it? I know that link exchange is not promoted from Google, but people still do it. Do you? πŸ™‚

The service is called Linxspy.com and in general it is a simple interface, where you can define your links and partner’s websites. On a regular basis /at this moment every week/, the service will check the partner site and will look for your link. If everything is ok and link is there, no action will be taken, but if the link is missing, you will be notified by mail.

It should be very usefull for web masters which exchanging or buying links with unknown or not well known partners.

Basically if everything is cool with your partners, you should forget about Linxspy, because it will bother you only for troubles. πŸ™‚

A little bit for implementation: As I said it was build for a week and as you probably guess it’s CakePHP app. On this project I’ve used Console Shell interface for triggering the weekly check.

Here you could find more information on about the service page

Here are some screenshots from Linxspy:

Hope it would be useful for you.

CakePHP ajaxed pagination and sort

Here I will describe how I did an Ajaxed pagination for one of my projects using jQuery and Livequery Plugin. Currently I am working on a huge project which, hopefully, will feed me with some ideas for blog posts and this is one of them :). So:

1. Loading the javascript libs

Loading the jQuery and Livequery was done by Autoloader helper, but if you don’t use it just include jQuery and Livequery in your layout with following code

<?php
echo $javascript->link('jquery.min');
echo $javascript->link('plugins/jquery.livequery');
?>

Continue reading

Passing variables to all Models from the Controller – strict MVC way

It’s really easy to find inspiration when you developing on CakePHP. For the current project I need to create global (for all models) behavior which stores creator and modifier as well as deleter and deleted (for soft-delete).

What are the requirements

1. For every table (or at least the most of them) there are fields 6 fields:

  • creator (int) – user who create the the record
  • created (datetime) – date when the record was created
  • modifier (int) – user who modified the the record
  • modified (datetime) – date when the record was modified
  • deleter (int) – user who delete the the record
  • deleted (datetime) – date when the record was modified

2. Some tables doesn’t have such fields (like aros, acos, settings etc), so it should update tables which has such fields.

I’ve seen Soft Deletable Behavior as well as recently added WhoDidIt behavior, but I don’t like the approach of using _SESSION. I’ve also decided to use datetime field to determine if the record is active (field deleted is NULL) or deleted (if the field is set with date).

So the result was – I’ve write my own behavior who serves this.
Continue reading

Creating Wholesale Solution with Magento Commerce

osCommerce to Magento migrationMy first approach for this post was to explain my first impressions from Magento Commerce, but I decided to explain how I managed to create a Retail/Wholesale solution required for a current project.

The requirement (so far, because it’s an ongoing project):

The client want to have a shop where regular customers to be able to see products with their retail price, while Wholesale partners to see the prices with ? discount. The extra condition: retail and wholesale prices hasn’t mathematical dependency. So, a product could be $100 for retail and $50 for whole sale and another one could be $60 retail and $50 wholesale. And of course retail users should not be able to see wholesale prices at all.

Basically, I will explain what I did step-by-step, but in order to understand what I mean, you should be familiar with the basics of Magento.

1. Creating two magento websites, stores and views
(Magento meaning of website of course) It’s done from from System->Manage Stores. The result is:
Website | Store | View
————————————————
Retail->Retail->Default
Wholesale->Wholesale->Default

Both sites using the same category/product tree

2. Setting the price scope
in System->Configuration->Catalog->Catalog->Price set drop-down to Website. Now you could enter prices per store/website and they could be totally different.

3. Get some plugins
Get following plugins from Magento Connect and install them from admin: System->Magento Connect->Magento Connect Manager:
Netzarbeiter_LoginCatalog – User need to login in order to see the store (it will be used for Wholesale site)
Netzarbeiter_CustomerActivation – User need to be approved from site admins in order to be able to login to the site. (again it will be used for wholesale site)

Both plugins need to be activated for wholesale only. Because they are activated when they are installed, you need to disable them for Default/Retail website and to leave enabled to Wholesale. You should know that distinction between sites in System->Configuration is done from top left corner of the config window.

First plugin is enabled/disabled from: System > Configuration > Catalog > Login only catalog
Second one: System > Configuration > Customer > Customer Activation.

4. Setting separate url for Wholesale
Now wholesales need to have separate urls, so regular users will access http://domain.com/, while wholesale will access http://domain.com/wholesale/. I found this solution in the Magento Forum: Thread.

So, following the instructions I created directory wholesale/ and copied .htaccess and index.php files from the root directory. Modifications in the index.php are the same as in the Forum:
Mage::run(); become Mage::run(‘wholesale’);
and
$mageFilename = ‘app/Mage.php’; become $mageFilename = ‘../app/Mage.php’;

5. Change the wholesale paths from the admin
From System->Configuration (select Wholesale website)->General->Web and change the paths by adding wholesale/ (it’s also mentioned in the forum thread).

6. Adding products to both websites
When adding products, you should mark them visible for both sites. This is done from Product page->Websites tab.

That’s it! Now on http://domain.com/ users will see full catalog, they can login without Admin approval and prices will be retail, while on http://domain.com/wholesale only users registered as wholesale and activated from admin will be able to see catalog with wholesale prices.

What’s left…

And this was the easiest part … the rest is to import about 2000 products from the current osCommerce store, and to add another 4000 from the client’s ERP system. After this on regular basis to update prices and quantities from ERP system. πŸ™‚

Hopefully this will help someone.

Strange issue with captcha field

Captcha caseWell, it’s more an observation than a real problem.

For my current CakePHP project I had to set a captcha field to a user registration form. I decided to be “creative” and I set the captcha image as background of the input field. In fact the graphical representation wasn’t bad at all. Unfortunately when it’s used, the captcha word shows wrong image and of course the result was wrong. To be correct the first attempt was always ok, but the second one (let’s say if the user decided to register again) the captcha was always wrong.

I checked everything especially after the image in Javascript library case and I couldn’t find anything suspicious.

The solution came when I removed the image from the background of the field and call it with an <img> tag. This time everything went just fine. This make me think that it’s a cache problem. I didn’t dig it deeply, because for now it’s working and as you can see it’s looking better.

So, an advise from me – never put your captcha image as background of your field, or call through css. Just use good old <img> tag instead.

Autoload your javascript and css in CakePHP

Have you ever wanted to have all your css or javascripts files loaded automatically once they are on place under /webroot/js and webroot/css folders? Well this is the solution.

What is all about

I’ve build a quick helper which will include all files under the js/ and css/ directories. So once the javascripts and css are there, they will be loaded automatically.

How to use it?

Using it is really easy. It’s like a normal helper:
1. add the file autoload.php under your /app/views/helpers
2. add it in the $helpers var in the controller
3. add the following snippet in your layout file. It should be under /app/views/layouts:

<?php echo $autoload->javascript();?>

This will include all files under /webroot/js

<?php echo $autoload->css();?>

This will include all files under /webroot/css

<?php echo $autoload->all();?>

This will include all files under /webroot/js and /webroot/css

Key features:

1. The helper includes all files recursively.
2. The helper includes also files under /root/vendors/js and /root/app/vendors/js too (same apply to css). Vendors are loaded first. (Thanks to suggestion from Juan Basso)
3. The order of the files in one directory is based on the name, so now you can control the order as well. (Thanks to suggestion from Juan Basso)
4. Files starting with . (dot) are not included, files under directories starting with . are not included as well, so you can exclude some files
5. if you want to load some files after other use directories. For example if you want to include plugins after the main lib (jQuery), place them in plugins directory like:
js/plugins/plugin_one.js
js/plugins/plugin_another.js
js/.hidden/plugin_third.js
js/jquery.js
the result will be:

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/plugins/plugin_one.js"></script>
<script type="text/javascript" src="js/plugins/plugin_another.js"></script>

(same apply to css as well)

Warning: I’ve noticed that this helper doesn’t work properly with scriptaculous, because the script tries to load the additional plugins and they fail, but for jQuery there is not a problem at all.

Finally here is the code of the helper:
Continue reading

Careful with JavaScript includes

Ok, this is not a code snippet article. It’s just an experience which you probably already met, but it was nightmare to find and it took me 1/2 a day to fix this “stupid” bug.

So what is the case?

Working on a project including some advanced JavaScript and Ajax techniques my coworker Milen noticed that the Session is not behaving as expected. In a simple function like:

 function test($id = false){
  if ($id != false) {
    echo $id;
    echo $k = $this->Session->read('some_var');
    $this->Session->write('some_var', $id);
  }
  $this->set('tests', $this->paginate());
 }

The result should be quite easy to be predicted: if you pass for example 5 on the second reload the $k should be with the same value as $id. Unfortunately instead of 5 the $k was ‘images’. Yep, quite strange, isn’t it?

if you put die() at the end of the function, the result is as expected.

What was the problem

In our current project we are using jQuery and some of it’s plugins. So the problems was in the ThickBox plugin. If you remove it from the header everything works.

Digging into unpacked version of the plugin we’ve noticed that the loading picture is not where it should be. there is an variable

 var tb_pathToImage = "images/loadingAnimation.gif"

and as you may notice the path is not compatible with Cake convention and obviously it’s not in the http://server/cakeapp/tests/test/images/.

In the example above we were writing id into the session. Yes but calling: http://server/cakeapp/tests/test/images/loadingAnimation.gif mean that $id take value of ‘images’.

It was quite tricky, because if you loading CSS or JavaScript and the file is not there, FireBug or even the html /if there is no correct CSS the styling will fail/ will warn the developer, but image loaded into the JS function is quite difficult to find.

Anyway, the conclusion is “Watch you JavaScript libs and what files they require”.

My first WordPress plugin

Hey,

I am very proud to present you, my first plugin for WordPress platform – Autocompleter.

The plugin adding autocomplete functionality for the search input field of your blog. The values are the tags and categories existing in the blog and this way you will help your visitors to find easily the proper information in your blog.

My first implementation was with Prototype and Script.aculo.us, but because I like very much jQuery library and I found a wonderful plugin for autocomplete, I build it with jQuery.

You can check the demo in this blog – top right – search box πŸ™‚

Hope you will like it and you will vote for it πŸ™‚ Thanks

The official page is: wordpress.org/extend/plugins/autocompleter