RSS
 

Archive for the ‘WebDevelopment’ Category

ACL – Access Control Lists – revised

06 Jan

With a focus on CakePHP application development.

Authentication vs Authorization

Those two are often confused. So here a little preface:

Authentication always comes first. It is about whether you are logged in or not. At this point it is not yet relevant who has access to what. It is merely checked if the specific action/URL can be publicly accessed or needs authentication first.

After the authentication process, usually completed through some kind of login, the authorization decides on who can do what. Here either roles or specific users are checked upon and the access is then either granted or denied.

Role Based Access Control (RBAC)

The easiest form of authorization is usually “role based access control”, where you assign each other a role, and all that needs to be done is comparing the user’s role (or roles in multi-role setups) to the required role for a specific action. This can be realized with a single “roles” table and “role_id” in “users” table (or for multi-roles a “roles” and “user_roles” table) along with some table or file to store the role/action relations.

Row Level Permissions

ACL is part of Authorization, the second step. It is called “row level” access control, as it can go beyond just roles/actions combinations. Depending on the implementation it can also allow or deny specific users access to certain actions or records and make inheritable tree structures possible. So if you deny a certain user access to a node in the ACL tree(s), the sub-nodes are also prohibited by inheritance. In its complex form (CRUD) it has even a flag for each type of action. Such ACL trees can be quite complex to handle manually, and as such the tools provide you usually with some methods and CLI commands to make things easier. So for the CakePHP core ACL there is even a plugin around some extra utilities for it.

ACO vs ARO

Read in the docs how ACL works regarding ACO (Access Control Object) / ARO (Access Request Object). Essentially, ACLs are used to decide when an ARO can have access to an ACO. While this post mainly focuses on controlling access to actions and records, ACOs could be anything you want to control, from a controller action, to a web service, to a line in your grandma‚Äôs online diary. So it allows you to make anything “accessible”.

Why ACL?

First of all you have to assess what kind of authorization is needed for your application. In 95% of all cases, a full stack row level ACL is not even needed, and simple roles per user would suffice.

The main questions boil down to: a) Does it need row level permissions as in “I need to allow/deny certain actions – or even specific records – to certain users”? Sure this can’t this be done with more roles? If so, then go for some ACL implementation. If not (and this often times cuts down the complexity quite a bit) use a role based one.

b) Does it have to be dynamic? For row level this usually has to be some DB driven solution. For roles it is sure nice to have some backend, but in my experience it is often not really necessary, at least if it is not some kind of CMS, but a web application that has developers close by.

So it results in 3 different outcomes: – Row level + dynamic (=ACL) – Role based + dynamic (=RBAC dyn) – Role based + static (=RBAC stat)

Note that the 2.x core ACL also provides an INI based approach, but that is not recommended and somewhat useless.

Problems with ACL

When working with ACL back in 1.x and 2.0/2.1/2.2 one large problem with it was speed. It is both slow in generating the aco/aro tree from all actions available throughout the project as well as checking them. Depending on the implementation this can sometimes be the bottleneck of some controllers and their actions. Especially with a larger user base and a not so small app this can probably get out of hand very soon.

When building the aro/aco trees the resulting tree structure table always seemed quite fragile to me. At least a few times it got, for some reason, broken, and repair tools had to recover the tree structure. It is also very difficult to debug due to its complexity. Additionally, you have to be very carefully with handling the data: You cannot just delete a user manually, or reset/truncate a table. It always has to go through the ACL channels for the tree to stay valid and filled with the right data.

Another problem I encountered when working with ACL: It is locked to the DB, instead of the code base. So reproducing some issues with accessing actions locally can become tedious as you have a totally different user-base, controlled records and thus ACL entries. And if you deploy, but forget to update the ACL (or some action is not added for some reason) people will be locked out without indication/feedback. If you upload new actions, the permissions to it will not always be deployed along with it which feels counter-intuitive to me. That applies for any dynamic (DB driven) permission setup, of course. So role based ones with an admin backend wouldn’t be off the hook here. Using static and “file commited” permissions here assert that those always fit to the current code base. I found that a lot easier to maintain and debug.

Static RBACs ftw

For the last 6 years I have never needed ACL for any of my applications or have it found useful for a lot of others I have examined. Defining some good roles was enough. And it was simple. Additionally, by keeping it static I neutralized the issue with the “not-in-sync” issues above.

I see a lot of people over-engineering that part without the (immediate) need for it. So I would really keep it as simple as possible until the use case for more complex mechanisms arises.

ACL definitely has its use cases, and I wouldn’t dare to call it evil, but it needs to be thoroughly thought through and not applied blindly. In case you need to use it, check here, if the ActionsAuthorize (Uses the AclComponent to check for permissions on an action level) suffices over CrudAuthorize (action -> CRUD mappings).

Alternatives to the CakePHP core ACL

Alternatives on row level

Often times you can’t get around some basic row level checking, e.g. when a user may only edit/delete his own posts.

The book has examples on how to add the currently logged in user to the data upon add action, and how to check for edit/delete if that user is the owner of that record. This can be done using the controller’s isAuthorized() method. A little bit of hardcoding saves a lot of trouble here.

Alternatives to ACL in general

Role based

  • TinyAuth – static INI files by default but could be easily made DB driven or at least backend adjustable.

Other

  • Controller based: ControllerAuthorize Calls isAuthorized() on the active controller, and uses the return of that to authorize a user. This is often the most simple way to authorize users. You can even mix role based with row level based auth if required.

Let me know if I forgot to list one. The full list of available plugins can be found at awesome-cakephp.

Last notes

In CakePHP3 ACL has been moved into a separate plugin, as it is just too much overhead for the core (since not so many actually use it) and doesn’t quite fit the 80%-rule therefore.

 
No Comments

Posted in CakePHP

 

Why CakePHP?

23 Dec

A Xmas post from Germany.

My last 6 years with CakePHP

I am now with CakePHP for over 6 years (wow.. time goes by!), the second half of it as core member. I started with it back in the days where 1.2 had just come out. I was just playing around back then. Soon I started to write the first small 1.2 apps, mostly private stuff and ideas in my head. A “phonebook” app, “recipes” site, a “sandbox” for trying out Cake/PHP things, a small social network approach and few plugins on the side.

Not long after that I helped to develop the first real CakePHP app meant to be thrown out there for commercial purposes – and since then never stopped. A little bit over a year ago I managed to finally upgrade even the last live app to the latest version 2.2/2.3 at that time.

Disclaimer: This is not meant to be a rip-off from josediazgonzalez’ why-to-actually-choose-cakephp/. It is my personal opinion why I have been sticking to this framework for the last years.

So why CakePHP in the first place?

There are alternatives, Symfony, Zend, Laravel, CI, … But they all didn’t convince me in the beginning – and still don’t. Mostly because as a beginner the first steps seemed and seems to be more complicated than with CakePHP. You need to do more to see actual and usable results. But I don’t want to go into detail here too much.

A framework is an absolute must

At least as a beginner. But even as a pro you are sometimes happy to not have to modify all those “core changes” in your code when PHP, MYSQL or any other external script is used differently over time. You are also grateful for the community effort of being able to find and fix bugs as a group effort. And last but not least, you could never come up with all those great new features and ideas all on your own. I found CakePHP to not only be community-driven but also very intuitive – over some time anyway.

CakePHP was already easy at the beginning

I already had PHP/MYSQL experience, but even without I might have succeeded with the first trial apps. And although CakePHP has lots of conventions and opinions on certain things it still allows you in many ways to use your own way of doing it. Since 2.x even more than ever before. Once you understand what goes on behind the hood you start to like it even more. You are able to contribute to the framework code as well as the documentation directly.

My personal reasons to still stick with CakePHP

Well, first of all, after so many years working with it and contributing you kinda get attached to it. Within the last three years I rose to the one of most active core developers besides the master Mark Story :) After what one helped the framework to become it would not make too much sense to just hop on to the next framework without a good reason. So here the hard facts:

Less coding time

CakePHP is all about reducing development time. So most of the things are already decided for you in best-practice approaches and you can overwrite only what you want to. Using bake and other tools you have a usable app in no time. Adjustments in your code are then also just a couple of quick changes. Fast development means less costs and earlier results.

Fast core update/fix progress

Issues or enhancements usually get added pretty quick. From a few hours (happens quite often actually) to a few weeks. The less complicated the issue and the better your initial work the faster it gets approved and included. So providing a detailed report and a patch in form of a Github pull request can really speed up the process.

Plugins

There are already quite a few very useful plugins or at least plugin-able snippets by very experienced programmers. You can easily use and enhance those. I use my own plugins like Tools, Setup, … with various useful stuff to enhance the core and my apps even further in a DRY (Don’t Repeat Yourself) way. That’s also one of the reasons why changing would be painful: I would miss so many of my already written Plugin classes I need every hour of every day. The overhead of rewriting it would probably be quite immense.

Busted myths

CakePHP is dead/legacy

Yeah, right :) That’s like super-lame to say. Check out the Github changelog and you will see how dead it really is. Fact is, that with CakePHP3 the activity goes to a new all time high throughout the timeline. And that is just the beginning. Fact is also, that until now, it was a very constant log of activity and improvement. Compared to other (very new) frameworks out there, that is quite the achievement. Most frameworks come and go as quick as the wind, but CakePHP is solid as a rock in its presence and how it improves. People/Businesses can actually rely on it.

A far more interesting question would be: Why isn’t Cakephp popular despite being one of the earliest PHP framework to be written?. People can get easily deceived by sparkling new “coolkidz” stuff. Backwords compatibility and reliability has’t been as important to any other framework. So they could progress to cutting edge in a faster pace, of course. There is a certain trade-off here to make. Nonetheless progress has been made, and that quite remarkable. See for yourself.

CakePHP is slow

Yeah, that was partly true in 1.x due to missing lazyloading. So many things have been included without actually needing them. It could consume quite a lot of memory, as well. Since 2.x and lazyloading the developer is responsible for only fetching the data needed and making sure that caching and other speed/performance enhancements have been accounted for. Then Cake is not really that much slower than any other Framework or PHP script. Sure: CakePHP 2 is still much more full-stack than most slim PHP frameworks. It might also not be cutting edge regarding speed. But with a little tweaking of server and app this difference is almost not measurable anymore. And the upcoming version 3.0 beats even most other frameworks, as with composer autoloader dump and some minor caching layer it runs pretty darn fast. Even the routing, which often was a bottleneck, has been sped up a huge factor.

This is not even a good argument for comparison, as with server configuration this can easily be overcome anyway. And what is often forgotten: CakePHP is actually super-fast in development time compensating for any speed issues compared to vanilla PHP coding. If I had a project to finish, I would rather use CakePHP and 1/4 of the development time (and costs!) and invest those in better server infrastructure (fully compensating any speed issues and going beyond). The outcome: You still pay only half the costs ;)

The documentation is outdated and incomplete

Total nonsense if you didn’t travel back in time. The documentation improved greatly since 2008 and Cake1.x. You could say that everything is covered and some things even more than you would probably need. Even the migration guides up until 2.6 (not released yet) are 100% complete and the code changed documented in the book in detail. So if you don’t find something it must either be a really rare use case or you are not quite capable of using Google or the book internal search. Well, that is too harsh of course. We all overlook things sometimes. Drop in the IRC #cakephp channel and ask, if you really can’t find it, and you will be helped in seconds/minutes.

For CakePHP3.0 the focus was even put on documentation: Writing thorough docs for each part that has is been added in sync with the actual feature PR. So far the result should be quite remarkable for a not-even-yet-RC version.

CakePHP is too much convention over configuration

I sometimes hear people complain about too many conventions and that you can’t configure CakePHP the way you like/need it. This actually was true in earlier versions. But in 2.x this also improved quite a lot. You can pretty much configure/adjust the whole framework as you need it – either via extending, aliasing, replacing core files or events/callbacks. Bear in mind that conventions are usually a good thing. They – in a default scenario – help you to get it done very quickly. If you start to reach an edge case you can still adjust accordingly, but first try to stay within the conventions for your own benefit.

With CakePHP3.0 this even goes one step further: You can leverage the whole conventions stack if you want to, or you can go totally down your own path. The latter I wouldn’t recommend, though, as you really save a lot of config overhead when using conventions wisely. Also: Using namespaces, there is pretty much no limitation anymore. Classes can be finally named the same without fatal errors. A simple use x as y and it’s resolved. You can replace complete parts of the application. Since major parts like “bake” and “translation” are moved out of the core, you can also more easily extend and adjust those now.

My learnings

Over the years, you also learn from your previous work – and mistakes. And we all make em. That’s natural.

Documenting is important

I didn’t really think of documenting in the beginning. Over the years there were many times were I had to regret that for various reasons. So new plugins and functionality get documented from the start, making it transparent both for me and others what to expect. I follow the approach to put the dochs directly into the repo as subfolder, containing a README.md as overview. This is very handy (close to the code) and readable (automatic markdown parsing online).

Write tests

I also didn’t test much when I started to develop. Working with CakePHP showed me how simple and yet effective it can be to do that though. You save yourself from a lot more regressions and it serves as part of implicit feature documentation, in case your forgot that.

Don’t reinvent the wheel

Yeah, back in 200x I had to write everything myself. But the systems around us evolve quicker and quicker. It is just impossible to keep up with everything and still write new application code. So if there are existing libs or services that do the job, I try to use them now. An example is “Carbon” for datetime or “Mailchimp/Mandrill” for sending emails/newsletters.

Keep code clean

Refactor once in a while to keep the code clean and readable. This makes understanding and extending it afterwards easier. Follow best practice approaches where applicable. Use a documented coding standard and stick to it.

Learning from other code and frameworks

Other frameworks have different approaches, they are valid for some use cases nonetheless. I had to look into Symfony2 and alike for one or two projects and even if I wouldn’t use them for my RAD (Rapid Application Development) projects, they can be useful for other projects. I could also once in a while get some very good ideas from them on how to approach certain things, and sometimes even let them mold into CakePHP functionality. Similar things can be said about existing library code out there. So be open minded and take a look over the “comfort zone” once in a while and suck in other people’s ideas and approaches. And always check if the tools you use still are the right ones for the task. If at some point something could be better handled with a different framework, I would probably look into it. But knowing my “tool” quite well, I didn’t see anything yet that wouldn’t have been handled by it so far in an appropriate way for the tasks at hand.

Splitting Utility repos into smaller chunks

I wouldn’t exactly call this a mistake, it was more the logical choice back then with SVN (and later basic GIT). My Tools plugin got pretty loaded with stuff, just because it was easier to include a single plugin than trying to svn:externals or git submodules separate ones. The overhead was not acceptable. Now in 2014+ with composer as de-facto standard, it looks a whole lot different. As such, I try to outsource some functionality of it into their own plugin repos, e.g. Geo and TinyAuth for 3.0. More should follow.

Which brings me to the last point which will also be easier with smaller repo code:

Follow some kind of semantic versioning

With composer this is an even more important task than before: SemVar is necessary to prevent incompatible libraries. So if you develop new features for a plugin for one app, other apps using the old version should still function normally. By always using a single branch directly, this can soon blow up. Using semantic versioning and releasing new versions (version numbers are cheap) we can assert that everyone is happy and code breakage stays at a minimum.

What’s next

I will try to help with the release of 3.0, the next major step in PHP framework history, as much as possible besides my day job and extracurricular activities. Earlier versions of CakePHP sure lacked the “coolness” of new PHP features, letting quite a few users drift off to other frameworks. I can understand that partially. We all want to use the newest and geeky stuff. If it is really necessary (at that point in time!) is a different story. Anyway, CakePHP 3 will catapult itself to the very front, and probably beyond most other PHP frameworks. And rumor has it that this time it will try to stay on top – with a fairly high chance of succeeding.

So I am really looking forward to how this will change the balance of framework usage here again, and how probably many of laravel’s or symfony’s followers will jump back to the framework with the longest history of all. Stay tuned for more posts on how to prepare 2.x apps for 3.x so that the final migration will be as smooth as possible.

Don’t forget to spread the word about CakePHP(3). Blog, twitter, write plugins (or upgrade existing ones) …

Additional Resources

For German developers there’s a very recent podcast where I go into details about CakePHP. The (English) podcast.cakephp.org one is mainly about upgrading between the different versions of the framework.

If you want to stay updated, subsribe to the blog RSS feed or follow my on twitter.

Merry Xmas everyone

And a great start into the next chapters of coding!

 

CakePHP3.0 coming up

03 Nov

CakePHP version 3.0 is coming closer and closer to a stable release.

The leap from PHP5.2 to PHP5.4 was more than necessary. Personally, I think, this will bring CakePHP back on the same level as “Laravel” or “Symfony2″. Those, using already PHP5.3 for a while, kind of left CakePHP behind. But now those will probably be overtaken again to some extend ;)

Try it out now.

All you need is to clone the cakephp/app repo, run composer update on it and its ready to go. Alternatively, you can run this simple command:

composer create-project -s dev cakephp/app [app_name]

Major differences compared to 2.x:

  • All namespaces. Note that they live only in the respective file. So try to avoid non-helper class usage in your view layer. Better to wrap them as helpers.
  • The former APP dir is now src, and a subfolder of the root dir. The composer.json file stays in root, though. So does “vendor” (note the lowercase v), “plugins”, “tests”, “config” and “webroot”. So basically, the src now only contains the classes, view templates and Locale.
  • Directly uses PHPUnit – there is no shell and no web test runner anymore (I do miss the latter though sometimes – VisualPHPUnit is supposed to substitute).
  • Completely new ORM – returning objects to easily work with.
  • Session is not static anymore. So using it inside models/behaviors is discouraged.
  • Themes are now Basic Plugins.
  • Uses templates for FormHelper and CO – making it way more customizable.

Upgrading

If you followed my earlier posts you probably know by now that I paid close attention to the changes between 2.x and 3.x. So my 2.x code already follows the new standards as close as it gets. This sure eases a possible 3.x upgrade.

The most important ones are:

  • Use composer and git (no git submodules etc)
  • Use query strings (remove all named params)
  • Remove deprecated functionality and provide shims if necessary

For details on latest 2.x upgrades see this article.

So use the following weeks or months wisely, and already bring your application to a current up-to-date version. Especially if you plan on upgrading it to 3.x some time. Taking away already most of the work beforehand and in small and well testable steps is the best approach.

Even if you don’t plan to upgrade the outlined standards sure ease current and future development. And that saves time and money.

I will soon release a new post with some experiences of upgrading small 2.x apps to 3.x. So stay tuned.

First Cake3.x notes and tips

I have been playing around with the dev, alpha and beta release so far, and I like it a lot so far. A lot :)

The migration guide looks intimidating for sure. But for new projects it will be irrelevant anyway. I still would want to wait until at least a few important plugins are upgraded – so probably close to stable release.

How to overwrite static classes

This has been pretty much impossible to do without namespaces in 2.x so far. Now you can overwrite/extend those classes very easily, as well. E.g. the Utility Hash class:

namespace App\Utility;
 
use Cake\Utility\Hash as BaseHash;
 
class Hash extends BaseHash {
}

You can then use App\Utility\Hash throughout your code to get access to any additional methods you want to add/change.

No need for phpunit composer dependency anymore

Use the phpunit.phar file directly and you don’t need the dependency in Cake3.x. It is also easier to work with, just drop it in your root folder and run:

php phpunit.phar

It will automatically read the config from the phpunit.xml file in your application’s root folder.

Oh, and CakePHP get’s more and more popular:

Currently it’s the 3rd most popular PHP framework on GitHub (No, codeigniter doesn’t count). For some reason ZF2 isn’t shown here. If you then compare RAD from CakePHP with the other two remaining ones, there really is only one to pick, isn’t there? After all, development speed matters…

 
6 Comments

Posted in CakePHP

 

UTF8 can be tricky – especially with PHP

15 Aug

Everybody uses (or should!) UTF8 these days. An easy and fully supporting PHP version I did not come across yet, though. It seems there is sometimes more to it. This article is supposed to guideline the basic setup of a CakePHP app using UTF8 and will go beyond that to the really tricky parts regarding the de facto standard encoding these days.

Note: this post is really long overdue and was in my draft folder for 2+ years. So here it is, quickly published before it got even more dusty^^ And dusty sure is the right word with (hopefully) no one using ANSI/ISO-8859-1 anymore these days.

UTF8 and PHP

Use the mb_ functions if you know that you real with strings than can contain UTF8 chars. So if you want to count the length of such a string:

$length = mb_strlen($string);

If you are simply manipulating strings, you do not always have to use those slower and UTF8-aware fnctions, though. But in doubt always do so.

UTF8 and preg_match()

Now this is a tricky one – especially if you don’t want to recompile PHP with the PCRE UTF-8 flag enabled or if you don’t know about it at all. IMO that should be the default, but it usually isn’t it seems.

Most times, when dealing with UTF8 strings, the /u modifier and p{L} helps:

preg_match('/^\p{L}[\p{L} _.-]+$/u', $username, $matches)

In other cases you might have to add (*UTF8) in your pattern.

UTF8 and CakePHP

CakePHP setup

The main parts are handled in the book, especially in the getting-started section. But the main part that sometimes people get wrong is that the APP encoding is “utf-8″ while in the database.php its spelled utf8.

Make sure you save all files as “UTF8 without BOM” via your IDE as soon as they start to contain UTF8 chars. Failing to do so will cause output issues. I usually try to avoid this and use Locale translation and mainly English chars in all files as much as possible.

Note: Before adding any UTF8 chars to files, those files are always ANSI (there is no way without the BOM to distinguish those two encoding formats as they are one and the same here). So no matter how often you try to save them as UTF8, they will always still be ANSI. In case you wondered why it falls back to it again in most IDEs.

Correcting PHP functions

Some PHP functionality has been wrapped in CakePHP to overcome deficiencies regarding Unicode. String::wordWrap() for example replaces the faulty wordwrap() function.

I also added a few fixes to my Tools plugin as Utility/Utility class: – pregMatch(): Unicode aware replacement for preg_match() – pregMatchAll(): Unicode aware replacement for preg_match_all() – strSplit(): Unicode aware replacement for str_split() – pregMatchAll(): Unicode aware replacement for preg_match_all()

Probably more to come..

Proper validation

Make sure your validation is unicode aware – that’s probably one of the most made mistakes from mainly English speaking devs/people. They maybe assume that it works to simply use strlen() or a [a-z] regex or alike – not taking into account that for example many normal first/last names contain a lot of special chars. Validation here should never be too strict. Otherwise a lot of people will be very upset.

So in the above example we do NOT want to use

preg_match('/^\[a-z][a-z .-]+$/i', $firstName)

but something more like

preg_match('/^\p{L}[\p{L} .-]+$/u', $firstName)

to validate a first name. IF we actually have to validate this further than a simple “not empty” check is a different topic (I don’t think so). But if you really must, PLEASE do not shut people out because their parents gave them non-English names ;)

A similar thing I had to fix in the core a while back, regarding domains/urls. And this is CakePHP2.5 – the current master – so that topic sure is still quite current for some cases. More and more so with further internationalization.

Checklist for your CakePHP app

  • Ideally, use utf8_unicode_ci as collasion for your DB
  • Your layout should contain <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  • The apache/nginx should serve files as UTF8 via header Content-Type text/html; charset=UTF-8

Outview

Only in PHP7 (as PHP6 got skipped) there will be a more built-in approach then for UTF8. Until then (and maybe even then) we will have to fight quite a lot here for the next years.

There are even a few popular projects in GitHub around the UTF8 issues, e.g: – https://github.com/nicolas-grekas/Patchwork-UTF8 – https://github.com/heartsentwined/php-utf8 – https://github.com/voku/portable-utf8 – https://github.com/gatsu/UTF8

Might be worth checking out.

Anything missing? Please let me know.

 
4 Comments

Posted in CakePHP

 

All new CakePHP Tips Summer 2014

05 Aug

For CakePHP2.x

Awesome CakePHP

Check out this all new awesome CakePHP list: awesome-cakephp Star it, fork it, enhance it :)

Note the cake3 branch that will proabably soon be filled rapidly with all new shiny CakePHP3 resources and plugins.

There are also a few more generic awesome lists links in there.

CakeFest 2014 coming up

Check it out – and be part of it. You can read about last year’s event here.

This year is going to be awesome (again that word^^). And not only regarding the temperatures in Madrid ;) A few well connected people like @philsturgeon pulled some strings and the event is listed on sites like php.net. Let’s make this the largest fest ever.

Note: My attendance app only lists a very small subset of all people actually joining the event!

Finally a book on CakePHP2.5+

CakePHP Core Developer @josegonzalez wrote a cool book on CakePHP: Rapid Application Development with CakePHP 2. It has some real insight in topics that are not covered by the online CakePHP documentation.

Hot tip: Use the promo code DEREUROMARK when purchasing the bundle to get 20% off your purchase!

Deployment with composer and script hooks

This is already widely used in Symfony2, for example. Here it fires the following scripts after installing/updating to clear the cache and re-build assets etc:

"scripts" : {
    "post-install-cmd" : [
        "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
        "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
        "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
        "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
        "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
    ],

The list of available commands be found here: getcomposer.org/doc/articles/scripts.md

Why not leveraging this for your Cake2.x app, as well? You could re-built AssetCompress files, clear the persistent/model cache, run custom post-update hooks and so on. (DB) Migration could also be hooked in this way.

Post links inside Forms

Most probably didn’t see this change. But it allows postLink() to be used inside forms now. The issue was, that forms don’t work inside forms. And that post links contain those inline, breaking the form around it.

You can now easily create “Delete” links or other POST links inside your forms. It can write the forms to a View block which you can output later on then. All you need to do is set 'inline' => false:

echo $this->Form->postLink('Delete', array('action' => 'delete', 1), array('inline' => false));

And output your buffered View block after closing the form:

echo $this->View->fetch('postLink');

This also works with multiple postLink() calls. The View block would simply contain all of the forms then.

Prevent internal field names

I try to stay away from internal framework used names for fields. Once you attach Search plugin or any other additional functionality on top of your actions, this could get messy otherwise. The Paginator, for instance, uses “limit”, “sort”, “direction”, “page”. In order for them to not conflict with search fields on existing fields, I avoid them and use “order” instead of “sort” or “max” instead of “limit” for field names. In case this is not avoidable or a legacy DB schema, one can add the model prefix, though: “MyModelName.sort” and would also be able to resolve the conflict. But if you can already do so in hindsight it is probably smarter.

Array and ArrayObject

The new CakePHP3 core uses ArrayObject already quite a bit. In 2.x you probably don’t use it too much yet. But it is wise to voice a warning regarding on some flaws of ArrayObject. This article describes it. Basically, empty() and ArrayObject don’t play nice. It only works with count():

if (count($options)) {
    // Yes
} else {
    // No / empty
}

The alternative would be to cast it prior to checking on it: (array)$options. Then empty() would work again.

The same issue you might face in index views and alike, where you want to display a subsitute text if no records can be listed in the pagination yet:

if (empty($users) { // BAD - better use count() here then.
    echo 'No users enlisted so far';
}

This would also always fail now in CakePHP 3 without any indication whatsoever as objects replaced the arrays and render empty() invalid as check here.

The rest of those issues in the article are also quite interesting. Check them out, as well.

A complete list of “flaws” has been put together on this page. It reads like the bible of Anti-PHP, tough :) Quite entertaining even in some parts. I would just read it as an informative page, though. It is good to know those things, but it is also easy to avoid or work-around them.

MySQL and returning integers

Some probably wondered why integers and other non-stringish values is often returned as string. This has nothing to do with CakePHP itself, but with the PDO extension of PHP underneath.

But you can easily disable that with the following flags in your database.php config:

'flags' => array(
        PDO::ATTR_STRINGIFY_FETCHES => false,
        PDO::ATTR_EMULATE_PREPARES => false
    )

UUIDs as char36 vs binary16

UUIDs (Universally Unique Identifier) can be used as an alternative to the normal AutoIncrement IDs for primary keys. Use them wisely, they are larger and slower than than the AIIDs. But if you use them, try to prevent char36. According to tests such as storing-billions-uuid-fields-mysql-innodb, it is 6-8 times faster to use binary(16) instead of char(36) for UUIDs. CakePHP 2.x+ supports binary just fine.

PHPUnit and Windows

You might have seen something as descibed in this issue: Weird output in your console when running unit tests. This is mainly because the default setting for PHPUnit in the phpunit.xml(.dist) file is usually colors="true". You can easily overwrite it in your own file and the weird output stops:

<phpunit
  colors="false"
  ...

Or you can try to use the library linked in that ticket. I didn’t try that one yet.

 
No Comments

Posted in CakePHP

 

Migrating SVN apps to Git and Composer

23 Jul

Just recently I had to move a few remaining legacy CakePHP2.x apps from SVN to Git+Composer. This serves as a short how-to.

You can also use this post if you are migrating a git app to a composer based git app.

Note: Installing a new CakePHP 2.x app with Git and Composer right away is dead easy and explained quite well in the cookbook. This post is more about migrating existing ones.

SVN + Composer/Git?

They can actually work side-by-side. For a migration process this can be useful, especially when migrating huge apps. Then doing it piece by piece helps to avoid chaos.

For this little how-to the main repo will stay a SVN one until the very end for this very same reason.

First steps

We have our SVN repo – up to date thanks to svn update. Download composer.phar in your APP dir. This file should be added to your excludes. Set up a composer.json file in there, as well, and commit it.

CakePHP Core

You might have hard-coded the core files in ROOT/lib/Cake – or used an svn:externals on ROOT/lib. Either way, remove that and add CakePHP2.x as Composer dependency.

Update index.php and webroot.php

As per documentation, we now need this in those files:

define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . APP_DIR . DS . 'Vendor' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib');

Resolve global vendors folder

In case you used a global vendors folder it will now not automatically be included anymore. To quick-fix this, add this to your bootstrap.php (at the beginning probably):

App::build(array('Vendor' => array(ROOT . DS . 'vendors' . DS)));

This will load your App::import()ed classes again from that folder. Same goes for the plugins folder, by the way.

In a second step you can then start moving those to the APP/Vendor folder – either as Composer dependency or hard-coded.

When all are transferred, you can remove the global vendors folder and also remove the additional App::build() call.

Resolve svn:externals for plugins

Most plugins will probably be hard-coded or included via svn:externals. Remove the svn:externals and add them as Composer dependency. Do the same for any plugins in your ROOT/plugins folder. If they are hard-coded there, move them to the APP/Plugin folder.

Almost done

At this point we already have a fully functional application again that loads all dependencies via composer – even though it is still a SVN repo. All it needs is

cd .../root && svn update
cd app && composer install

If some global vendor libs are harder to migrate or the “svn to git” conversation is troublesome, you can take your time get it up and running again on this level just fine. At some point you will have finished the migration though, then proceed to the final step.

Move SVN to Git

When all externals have been resolved, the root vendor and plugin folders have been cleaned and their content moved to the APP pendents, we can now start migrating the application to Git. For this we drop the usual /trunk/... folder structure and directly copy the APP folder from your SVN repo into the root of your new Git repo. The ROOT folder itself serves no purpose anymore, and we can have APP as root folder now. Therefore in root, you should now have the composer.json file. For an example, see cakephp-sandbox.

As for “copy”: You can either directly copy-and-paste your repo (quick and dirty), or use git-svn tools to preserve your changelogs/history. The latter is the cleaner approach, of course. See this guide on how to do that. Some services like GitHub might also offer a git-svn push access or link useful tools. Those approaches usually need a folder move of the APP folder content to the root level then on top.

Either way, the more you composer and the less you hard-code your libs, the quicker and easier the svn…git transformation will go.

Now updating app + core + plugins + vendors is just:

cd .../root
git pull
composer install

Since the APP folder is now the root folder, no need to further cd deeper.

Sugar

You may add

require_once dirname(__DIR__) . '/Vendor/autoload.php';

at the top of your bootstrap.php file to add autoloading via PSR for new namespaced repos (on top of the still working App::import() and App::uses() methods).

That means, that you can now use namespaces and third party packages via composer quite easily. Let’s say we want to use the MediaEmbed lib in our project. We then simply add it to our composer.json:

"require": {
    "dereuromark/media-embed": "dev-master"
}

In our CakePHP classes, e.g. an EmbedHelper, we can now use it right away:

<?php
use \MediaEmbed\MediaEmbed;
 
App::uses('AppHelper', 'View/Helper');
 
class EmbedHelper extends AppHelper {
    /**
     * @param string $url Absolute URL of the video/audio.
     * @return string|null HTML snippet or null on failure.
     */
    public function media($url) {
        $MediaEmbed = new MediaEmbed();
        if ($MediaObject = $MediaEmbed->parseUrl($url)) {
            return $MediaObject->getEmbedCode();
        }
    }
}

Isn’t that awesome? You now have the full PHP5.3+ (GitHub) lib variety out there at your disposal. You might want to check out this list of cool libs.

Private repos

With the externals, it was quite easy to pull from your own repo URLs. Composer makes this a little bit more difficult. To overcome the issue for GitHub private repos, for example, you can use vcs:

"require": {
    ...
    "your-username/cakephp-some-private-plugin" : "*"
},
"repositories" : [{
        "type" : "vcs",
        "url" : "git@github.com:your-username/cakephp-some-private-plugin"
    },
    ...
],

Note that this will prompt once for your username and password and create a token for re-use:

Your GitHub credentials are required to fetch private repository metadata. The credentials will be swapped for an OAuth token stored in …/Composer/auth.json, your password will not be stored.

Last tips

This tutorial assumes that you are properly using the current master (2.5.3 at this time) version of CakePHP. Always upgrade to the current master – never use anything older.

Make sure you have a current index.php/test.php file as well as a current APP/Console dir including those cake scripts (current as in master/2.5.3 at least). You can just copy them over from the CakePHP source folder (Cake/Console/Templates/...) if you are unsure. Especially for console this is quite important. Otherwise Console/cake might not work out of the box with the new composer approach – even though it would if you had up-to-date files.

Also, don’t forget to .gitignore all included dependencies (both Vendor and Plugin ones). And also the ones from SVN, composer.phar etc.

 
No Comments

Posted in CakePHP

 

HTML, Markdown or BBCode?

16 Jul

Or something different? Or just plain text maybe?

“User input is hard”

There are pretty prejudiced blog posts in favor or against the usage of BBCode for blog posts, comments etc. Here for instance – continuing on this second post.

Personally, I am in favor of some abstraction for the frontend user, usually BBCode or a similar syntax. But it always depends on the usage in the app. For forums, blog post comments, etc they are sure quite useful and avoids exposing HTML to users.

Let’s dig into some options more deeply.

Plain text

We all probably do or did it: Using .txt files to store some pseudomarkup enriched text including lists and headings. While its simple and easy, the output on a a browser for such textual representations is pretty poor. It starts with missing <p> paragraphs or newlines. All those would have to be manually modified. In CakePHP there is a helper method that does exactly that: TextHelper::autoParagraph(). Adding autoLink() you even get your URLs and emails enriched as HTML. It works perfectly for all varchar or text DB fields that are exposed as textareas in the forms and only needs to accept plain text. This is all nice for very basic use cases, but is quite limited in the presentation.

HTML and WYSIWYG Editors

This widely used in backends as this is easy to implement. Just add a JS based WYSIWYG editor on top of your textareas and you got yourself editing in the way it will be presented upon output. This live preview while typing sure is a nice bonus here. One drawback often is the amount of overhead added via tags, classes and alike. But that depends on the editor being used.

Often times there is a “plain HTML” button to even allow custom HTML modifications in the source code. While this is probably the most flexible approach, it is also the most dangerous. You can easily screw up the HTML – invalid HTML is hard to spot and might break your whole frontend layout.

Tools such as htmlpurifier exist to support those editors in removing unwanted content, fixing broken HTML and cleaning up the source code (mess). This also makes it possible to allow a subset of HTML in non-backend textareas untrusted users can have access to. In CakePHP, for example, you can attach a PurifiableBehavior to your model that cleans the content upon saving.

The most commonly used editors are probably listed on this comparison site.

BBCode

That was the very first abstraction level available. A lot of forum software still uses it quite thoroughly.

Everybody who opposes BBCode completely (like the above posts), does not know much about the user perspective. Users don’t care about semantics and just want their link to be added. They want it simple and straight forward. So [img]url[/img] in BBCode would be more intuitive as the resulting <img src="url" /> in HTML. Now what is easier to understand for a newbie? What is easier to read? Of course we have a little bit more processing with BBCode. But with caching that is minimized to nothing. For admin backends it is usually easier to use HTML. This way they have more tags, attributes to chose from. We can also assume that they don’t want to harm the site and that they know what they’re doing.

The second important point is abstraction. [code] can be <code>... or even <pre>... or a combination of both. Everybody understands [code] whereas [pre] etc is not so understandable. So we use [code] and afterwards transform it into the more complex HTML tags we need for markup. But the user text stays clean and straight-forward. He doesn’t need to know about the mapping of [code=php] to <pre id="xyz" class="php"><code>...

jbbcode looks like a solid implementation for this.

There is even a WSYIWYG editor for this now. Even though that one is based on JS – meaning you would have to keep your custom rules redundant, once in PHP and once in JS for this editor. Also, there might be slight edge case differences between preview and actual result.

Markdown

This is becoming more and more popular these days. Not only for developers who use GitHub a lot, but also by bloggers using WordPress plugins for this or other websites that want to avoid the HTML overhead when displaying lightweight markup text. The benefit here is that the text can be written almost as normal text. And even non-developers would easily understand lists such as:

- one
- two
- three

So it combines text with leightweight markup that is easily understandable by everyone – and probably even used intuitively without knowing it. Translation into HTML is straightforward.

Currently most people prefer the GitHub flavored addons as the original markdown implementation hasn’t had any progress anymore the last years. A nice demo and comparison shows the difference.

A slower but probably more powerful library is Ciconia. It is intended to be more flexible and extendable.

There are nice WSYIWYG editor implementations for Markdown: sofish.github.io/pen or markitup. But as with BBCode: since that one is based on JS – meaning you would have to keep your custom rules redundant again, once in PHP and once in JS for this editor. Also, there might be slight edge case differences between preview and actual result.

Imagine you can write all your HTML in such a DRY and non-HTML-polluted way and still get nice HTML from it. And you can also use it for textual representation right way (e.g. text emails). Awesome.

Speaking of – there are nice tools that can actually take your already written HTML and revert it back into Markdown. See http://blog.oddbit.com/2012/11/06/convert-html-to-markdown/ and to-markdown.

So if you have already existing records or blog posts in the old format, you might be able to convert them and then use markdown only from there on.

Summary

From what we read so far, the complexity would probably be best described as:

Text < Markdown < BBcode < HTML

And the further left, the better – not only for interoperability. You should use the easiest format that suits your need.

HTML

  • No additional parsing needed (once it is validated and saved)
  • Cannot work without a sanitizing process for non-admins (stripping off any unwanted attributes or unsafe elements)

BBCode

  • Simpler sanitizing
  • Abstraction possible ([ video ] or [spoiler] tag)
  • Does not interfere with HTML Markup (e.g. for code snippet posts in dev blogs)

Markdown

  • A compromise between writing plain text and using minimal additional markup to enhance it
  • Intuitive
  • Less error-prone than BBCode regarding simple tags/markup
  • Maybe more error-prone than BBCode for more complex tags/markup
  • Nice for inline references/images/hyperlinks (links can be grouped at the bottom)

Combining them

Sometimes, the lightweight Markdown might not cover everything. Writing a custom wrapper you can easily combine them enhancing your toolset.

You use Markdown as primary parser and parse the remaining BBCodes afterwords. HTML could be allowed using a custom markdown rule, e.g.:

```html
<myhtml />
```

You could also use BBCode then, of course:

[html]
<myhtml />
[/html]

Adding plain HTML in between the Markdown and BBCode markup would work, as well (I do that^^). But this can easily break or have unseen side effects when trying to escape the source code. It is more difficult to distinguish between an HTML tag <b>I am bold</b> and just plain text containing those chars by accident: I like the brand <FooBar>. In that case all those non-HTML-intended characters need to be properly escaped, which really is annoying. So please don’t do that ;)

In the example above the whole page would be escaped using h() (the htmlspecialchars() in CakePHP). This way it is secure by default. And the tags from above would automatically undo h() to display the raw HTML again.

I think combining them in a logical order can in some cases make all the difference and solve all your problems at once. You have the simple and lightweight markup as basis, you are able to apply custom codes via BBCode similar syntaxes and on top you can always use real HTML for more complex scenarios (tables and alike) where necessary.

Side notes

This blog also uses Markdown for all posts and some BBCode for the comments, of course.

I did not mention Textile as even though introduced shortly before Markdown it never really became that popular. Those are similar, though, in their ideas. A full list of further lightweight markup languages can be found at wikipedia.org.

Further addons

I use anchorjs to automatically add anchors on the fly using JS. This is especially useful if the parsed markdown itself produces headings without any attributes. This way they are added without having to dig deeper into the post-processing of the markdown parser or modifying the resulting HTML. Another alternative would be anchorific.

You can use my MediaEmbed lib as addon for BBCode or Markdown (or even plain text) to auto embed Video snippets. See the examples/bbcode.php there for a live example.

Further Links and Resources

This BBCode parser once looked quite promising. But it now seems abandoned.

The MarkupParsers Plugin combines several markup syntaxes into a plugin. There are even MarkdownView classes which would render a complete markdown-flavored layout into HTML. For me a helper or lib wrapper usually suffices as I usually only output parts of the layout as such a markup-flavored text.

See dillinger.io/ or stackedit.io for editing Markdown in real time. And there is a cheat sheet to go along with it.

Outview

I will probably add some real life examples and comparisons soon on my sandbox site. Stay tuned.

 
 

CakePHP 2.5 arrived + CakePHP Tips 2014

13 May

You probably read my last tip sections. And I started to move some of them to my sandbox app.

But once in a while it might also be nice to publish a few selected tips, here as well.

Oh, and CakePHP 2.5 is out! Get it – now :) See the last chapter of this post about why you really should upgrade ASAP. And it doesn’t matter if you are on 1.x or 2.x.

URLs in CLI

In CLI and your shells there is no HTTP HOST and therefore usually no absolute URLs. But in order to properly work with links/urls (e.g. sending batch emails), we need that to work. So I use Configure::read(‘Config.fullPageUrl’) here. My configs.php file then contains:

$config['Config'] = array(
    'fullPageUrl' =>  http://www.myapp.de // The primary URL
)

In case you have a different domain for local development like http://myapp.local and you want that to be the fullPageUrl, make sure you overwrite the default in your configs_private.php file:

Configure::write('Config.fullPageUrl', 'http://myapp.local'); // Usually defaults to the (live) primary URL

And in the end of my bootstrap file (after including all config files), I simply do:

if (php_sapi_name() === 'cli') {
    Configure::write('App.fullBaseUrl', Configure::read('Config.fullPageUrl'));
}

To test the current domain/fullBaseUrl, you can use my Setup plugin command cake Setup.TestCli router. It will output both relative and absolute URL examples generated by the Router class with your current settings.

So on the live server then it will output http://myapp.local instead of http://localhost when generating Router::url()s in your shells.

Careful with running shells in CLI

Most are probably not aware, but running shells in CLI needs to have a proper user management around them in most cases. Imagine yourself running your apache as www-data (default) and log in as root or any other user not affiliated with that www-data user/role (bad idea). Once you execute a shell and tmp cache data are (re)built, your www-data user cannot access them anymore, losing the ability to cache and triggering a lot of errors. So make sure you only log in with a user that shares the role of www-data at least, so that both can access each others’ generated files.

A popular example is the ClearCache shell which re-builds your cache dirs in debug 0 (when changing files or db schema makes this necessary).

PS: Of course you could also switch to another cache system than the default File engine. But most probably didn’t do that yet, either.

Merging arrays

Ever wondered what Hash::merge(), array_merge and array_merge_recursive have in common – or don’t have in common? Check out these merge comparison examples.

See what the requirements are – and use the appropriate merge method then.

There is also the + operator, which is quite useful when merging flat arrays and string key based options. This is quite commonly used in the core to merge options and defaults:

$defaults = array(
    'escape' => true
):
$options += $defaults;

In this case the $defaults are merged on top of $options, but only if that key has not been specified yet. This kind of merge is really efficient and fast (4-5x faster than array_merge() itself) – but should really only be used if all keys are definitely strings.

Paginating and merging

A propos merging: When setting up paginate settings in your controllers, try to prevent

public function index() {
    $this->paginate = array(...);
}

This way you kill all defaults you might have set via public $paginate or in your extending controllers (AppController’s beforeFilter() callback for example).

So it is better to use:

$this->paginate = array_merge($this->paginate, array(...));
// or
$this->paginate = array(...) + $this->paginate;

In my 2.x code for example I have this snippet in all my AppControllers to have query strings for paginations:

public function beforeFilter() {
    parent::beforeFilter();
 
    $this->paginate['paramType'] = 'querystring';
}

This will only work with proper merging of defaults and custom settings. I prefer the latter because the settings are string based and here the + operator is the fastest and easiest way of doing things. Once the key is already set in your method, the default will be ignored right away (with array_merge() and nullish values this can be different/unexpected).

And remember to not mix controller and component pagination.

Pagination and sort default order

Adjust your bake templates so that some fields like created/modified are ordered DESC instead of ASC per default in the index actions. For those fields the first click on the header row should display them DESC right away as one would then most likely be interested in the latest changes. Same goes for most date fields like “published” as well as fields like “priority”, “rating”, …

That’s how the baked code (or manually adjusted one if done afterwards) could then look like (index.ctp):

<th><?php echo $this->Paginator->sort('name');?></th>
<th><?php echo $this->Paginator->sort('amount');?></th>
<th><?php echo $this->Paginator->sort('priority', null, array('direction' => 'desc'));?></th>
<th><?php echo $this->Paginator->sort('status', null, array('direction' => 'desc'));?></th>
<th><?php echo $this->Paginator->sort('publish_date', null, array('direction' => 'desc'));?></th>
<th><?php echo $this->Paginator->sort('modified', null, array('direction' => 'desc'));?></th>
<th><?php echo $this->Paginator->sort('created', null, array('direction' => 'desc'));?></th>

Using modified model data in the form again

Some of you might have had the wish of posted data that was modified in the model due to beforeValidate/beforeSave to appear modified in the view again (so that the reason for validation errors might be more clear etc). So let’s say you have a beforeValidate callback to clean the input of a textarea:

public function beforeValidate($options = array() {
    if (isset($this->data[$this->alias]['comment']) {
        $this->data[$this->alias]['comment'] = $this->_clean($this->data[$this->alias]['comment']);
    }
    return true;
}

So in this case it could easily be that _clean() removes some invalid content and thus the minLength rule is suddenly triggered. Which is weird, since we posted at least twice the length of text. To clarify to the user what is going on, one could adjust the error message – but one could additionally return the modified (ready to save) data instead of the actually posted data.

public function add() {
    if ($this->request->is('post')) {
        $this->{$this->modelClass}->create();
        if ($this->{$this->modelClass}->save($this->request->data)) {
            $this->Session->setFlash(...);
            return $this->redirect(array('action' => 'index'));
        } else {
            // Here we assign the modified model data back to the request
            // object and therefore to the view/form
            $this->request->data = $this->{$this->modelClass}->data;
            $this->Session->setFlash(...);
        }
    } else {
        // Default values for the form
        $this->request->data[$this->modelClass]['status'] = true;
    }
 
}

The input field will now contain the content that was served to beforeValidate(). And combined with a good error message this will probably clear things up.

PS: You can also directly use the model’s name instead of {$this->modelClass}, e.g. ‘Comment’.

MySQL – MyISAM vs InnoDB

InnoDB is a little bit more robust as it allows transactions. Especially with CakePHP and “multiple queries” most of the time (per default) this can be quite helpful in keeping the DB in a valid state. Also read myisam-versus-innodb on pros/cons for each.

One additional problem with InnoDB, though: Per default it creates a file that always increases in size, never decreases again. This can soon be a nightmare with backuping when it becomes >> xx GB of size. See how-to-shrink-purge-ibdata1-file-in-mysql how to avoid that by not using that file, and instead using innodb_file_per_table.

Testing

Testing Controllers

I stumbled upon a few issues with testing controllers – especially plugin controllers. For plugin controllers to be testable unfortunately you always need to use $uses, even if it wasn’t necessary due to conventions. So for your Tools.TinyUrls Controller you would need

public $uses = array('Tools.TinyUrl');

Otherwise it would always try to look for the model/fixture in your app dir, which eventually always fails.

Do not forget to use --stderr when testing in CLI. Otherwise all tests that use the session (and which work fine in webtest runner) will fail:

cake test app AllController --stderr

Test Coverage

If you want to generate a HTML overview of all your locale test coverage:

cake test app AllApp --stderr --log-junit tmp/coverage/unitreport.xml --coverage-html tmp/coverage --coverage-clover tmp/coverage/coverage.xml

The report index.html will be in your /tmp/coverage folder.

More on testing – especially controller testing – can be found on the corresponding Tools plugin Wiki page.

Upgrade (deprecated) code

It is always good practice to upgrade to the current master. Not only for CakePHP, but there especially. It will save you a lot of time in the long run, as migration will be easier and faster in small steps instead of one huge step. It will also make it easier to use the new features and more importantly will also come with a lot of fixes and method corrections that the older versions didn’t get anymore. Those outdated versions usually only get security-bugs fixed. So if you look hours for an error that is already fixed in the current master, it was just a huge waste of time. I have seen that a thousands times – on IRC and elsewhere.

So in case you are not using the current master (2.5), do it now. Internally, upgrading 2.x is a “piece of cake”. Upgrading from 1.x is also not that big of a deal – just needs a little bit more manual adjustments. For most things you can use the core UpgradeShell as well as my Upgrade plugin.

In case you are already upgraded to 2.5, you can and should also remove deprecated functionality in favor of the right one. Those deprecated things will only add to the file of upgrades for the next 2.x release or 3.x. And using the upgrade shell it is usually just one single command to execute. So for 2.5, you should have removed all the “easy” stuff that will clearly be switched with a different way of doing things as it is mentioned in the migration guide, e.g.

  • loggedIn() in favor of Auth::user(‘id’)
  • CakeRequest::onlyAllow() in favor of CakeRequest::allowMethod()
  • Use first argument (string|array) instead of var args for CakeRequest::allowMethod(), AuthComponent::allow(), etc
  • $title_for_layout in favor of $this->fetch(‘title’) and all other deprecated view vars

From 2.4 and below there are also a few left overs that could easily be corrected:

  • FULL_BASE_URL, DEFAULT_LANGUAGE, IMAGES_URL, JS_URL, CSS_URL to Config variables
  • Remove CAKEPHP_SHELL, IMAGES, JS, CSS usage
  • Simplify HtmlHelper::css()
  • Remove Sanitize class usage in favor of a more sane approach
  • Simplify CakeRequest and PaginatorHelper usage with param() if applicable
  • Don’t use request shortcuts anymore – like $this->action in favor of $this->request->action etc
  • Get rid of Model::read() calls – in 3.x this will be get() – I use my Tools plugin MyModel::get() method here already for years
  • Use the new Model::save() syntax for options
  • Completey get rid of named params in favor query strings (Use my Tools plugin CommonComponent and Configure value App.warnAboutNamedParams to detect left-overs)
  • Replace all Set calls with Hash calls, as Set is deprecated. Make sure it is tested thoroughly (as the functionality of Hash might be slightly different).
  • Prevent using Validation::range() in favor of a custom validation rule for inclusive ranges to easier migrate to 3.x – or simply use my Tools plugin MyModel::rangeInclusive() method.
  • Further deprecations in favor of the 2.5+ way to do things

and so on. For some details see Tips-Upgrading-to-CakePHP-2.x.

My Tools plugin also contains a few further tweaks that can help ease migration from 2.x to 3.x See the full list on the corresponding Wiki page.

This will help making sure any future upgrade is less painful. Think about it: When you do that now the remaining TODO list will only be half the size and look a lot less intimidating. When the time comes to upgrade to 3.x it will look quite more doable.

My codez is now officially all 2.5 – and as 3.0 ready as it can get :P

And what always helps a lot is to code clean and structured. A code mess will always be difficult to maintain. So use coding standards and enforce them. Use best practice approaches. Refactor once in a while to prevent a mess from happening. Happy coding :)

 
No Comments

Posted in CakePHP

 

CakePHP flash messages 2.0

21 Apr

This is a topic often discussed. What is the best approach? While I might not have the best, I sure have a fully working one since 2008 and CakePHP1.3. I still use it in all 2.x apps. It is easy and does not require a lot of overhead.

Basically, it enhances the core one with the following features

  • Different types possible (now in 2.x kind of in the core, as well, using elements)
  • Multiple flash messages per type possible (with a max limit to avoid session flushing)
  • Transient messages (via Configure) and real ones (via Session)
  • Transient ones can also be fired from the views (to display some hint/info for this page) – although one should try to stick to the controller

Demo

sandbox/examples/messages

How does it work?

We attach the Common Component and the Common Helper to the AppController:

public $components = array(..., 'Tools.Common');
public $helpers = array(..., 'Tools.Common');

In our layouts we need to switch the default output to ours:

echo $this->Common->flash();

And we can use `em:

public function add() {
    ...
    if ($this->Entry->save()) {
        $this->Common->flashMessage('The Entry has been saved.', 'success');
    } else {
        $this->Common->flashMessage('The Entry could not be saved. Please check the form.', 'error');
    }
}

Styling

We style our flashmessages via CSS

div.flash-messages {
    width: 90%;
}
div.flash-messages div {
    padding: 10px;
    padding-left:40px;
}
div.flash-messages div.error {
    width:100%; border-style: solid; border-width:1px; border-color:#B84D17; 
    margin-right:2px; color:#000000; margin-bottom:8px;
    background: url(/img/css/layout/icon_error.gif) left center no-repeat;
    background-color:#F7C6A5;
}
div.flash-messages div.warning {
    width:100%; border-style: solid; border-width:1px; border-color:#D0C130; 
    margin-right:2px; color:#000000; margin-bottom:8px;
    background: url(/img/css/layout/icon_warning.gif) left center no-repeat;
    background-color:#F6F3A4;
}
div.flash-messages div.success {
    width:100%; border-style: solid; border-width:1px; border-color:#009900; 
    margin-right:2px; color:#000000; margin-bottom:8px;
    background: url(/img/css/layout/icon_success.gif) left center no-repeat;
    background-color:#A5F7A8;
}
div.flash-messages div.info {
    width:100%; border-style: solid; border-width:1px; border-color:#cccccc; 
    margin-right:2px; color:#000000; margin-bottom:8px;
    background: url(/img/css/layout/icon_info.gif) left center no-repeat;
    background-color:#ffffff;
}

Or any other layout for that matter. The images are small icons and also optional, of course :)

Transient flash messages

You can also put flash messages on top that are not stored in session but Configure (for this request only). This can be useful if you don’t intend to redirect and don’t want them to show up if that happens.

From your controller:

$this->Common->transientFlashMessage('This page is currently being redesigned', 'info');

Or from your view ctp (even elements, blocks or the layout if it happens prior to the flash message output):

$this->Common->addFlashMessage('This page is under maintenance. It may be broken!', 'warning');

Output in a specific order or only specific types

You can filter the output, both in order and types:

// Using Common helper
echo $this->Common->flash(array('warning', 'error'));

In this case it would only output the warning and error messages, in this order (Usually the order is “error, warning, success, info”).

Details

For details please the Wiki page.

Outview

It would probably be nice to add element support at some point. This would allow an easier approach to customization of those messages.

There are also quite a few CakePHP core tickets open regarding flash message enhancements – see this or this which might even lead to an own component for it some day. But until then my approach will still be used in all my xx apps :) So in 3.x there will be a Flash component and Flash helper to provide a clean way to produce flash messages. If they provide the same features my implementation currently does, will have to be investigated. But it will use templating which will sure be nice.

Update 2014-12

A FlashComponent and FlashHelper now replace the current way of handling flash messages. This helps to ease migration to 3.x at some point, as there this is also extracted from the Session classes. As syntactic sugar you can directly use the types as methods now:

// Normal
$this->Flash->message('Yeah', 'success');
 
// Possible now
$this->Flash->success('Yeah');
 
// Same with
$this->Flash->warning('Careful');
$this->Flash->error('o_O');
$this->Flash->info('Some information');

2015-01 CakePHP 3

The documentation for 3.x can be found in the repo itself now: Docs. Check it out!

 
3 Comments

Posted in CakePHP

 

Update your Server to PHP5.4+

13 Apr

With many new features and more speed it makes sense to upgrade to PHP5.4. It is also a requirement when you start using CakePHP3.0 (the dev releases) or code that contains short array syntax. So the sooner you upgrade the better.

The following examples are for Debian Squeeze.

Backup

Make sure you have a backup of your server/files/db and your php.ini and other config files.

Updating

Debian doesn’t offer this natively. We need to add some special packages for this.

Open the sources list using nano, vi or the edit tool of your choice:

vi /etc/apt/sources.list

And add those two lines at the end:

deb http://packages.dotdeb.org stable all
deb-src http://packages.dotdeb.org stable all
 
deb http://packages.dotdeb.org squeeze-php54 all
deb-src http://packages.dotdeb.org squeeze-php54 all

We need a public key to avoid those warnings showing up:

wget http://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | apt-key add -

Use apt-get update and apt-get install php5.

That should take care of it. PHP5.4.x should now be installed and ready to work with. And have fun playing around with CakePHP3.0 or some new features of PHP5.4 :)

Keep other packages up to date

Also make sure other packages are up to date using apt-get upgrade.

If it doesn’t install right away, one might also need apt-get dist-upgrade. Careful with this, though. It might install/overwrite more than it should.

Dev Libraries

If php5-dev libraries are needed, they can be installed via apt-get install php5-dev.

Key Benefits of 5.4

  • Speed/Stability
  • Traits
  • Closures and $this
  • callable as typehint
  • Short array syntax (no mixin of method brackets and array brackets anymore)

The only real benefit coming in 5.5 is “Generators” which will allow handling of huge arrays and larger amount of data more gracefully. But other than that 5.4 is just fine for the moment.

Features of 5.3 you can now also use in Cake3

  • Namespaces
  • Closures
  • Late Static Bindings
  • Ternary shorthand form
  • Magic method __callStatic()
  • Nested exceptions
  • These features weren’t used in Cake2 core (and probably most apps) so far due to the BC for PHP5.2. If you already updated your minimum requirement for your server and application, those are also now of great use.

Further tips

The encoding even in more current verions of apache usually defaults to the old “ISO-8859-1″ one. You should make it “utf-8″ per default in your php.ini:

; PHP's default character set is set to empty.
; http://php.net/default-charset
default_charset = "utf-8"

Then even error pages or non-normal responses will be properly displayed. It is sad that even 2014 and in PHP5.4 the default is still not a proper one – probably due to BC or something.

 
No Comments

Posted in PHP