RSS
 

Posts Tagged ‘Composer’

Developing CakePHP 3+ Plugins, it’s fun!

29 Jan

It is fun – and it should be!

The days of CakePHP 2 plugins and how difficult it was to actually develop plugins are over.
Back in the days (OK, I still have to do it once in a while), there was even an app required to test a plugin. Since you didn’t want to have a boilerplate app for each plugin, you usually worked in your actual app. So you had cross contamination from that messing up your tests and stuff. Really annoying.
The only thing I am still missing once in a while is the web test runner, as it speeds up things for some use cases (usually with browser related output).

While most of the concrete examples are about plugin development for CakePHP 3, the main ideas apply to all library code you write. And if you are a developer for other frameworks, the same principles apply, only the concrete implementation might differ. So you could skip the "real story" part.

Well, but now to the fun part I promised in the title.

CakePHP 3 plugin development – real story

My goal was simple: Developing a simple plugin for hashids support in CakePHP in a few hours.

The CakePHP plugin docs mentioned a few basics, but in the following paragraphs I want
to go into more concrete details.

How do you start?
I started by creating a fresh GitHub repo "cakephp-hashid" and cloning it (git clone URL).

Then I added the boilerplate stuff like composer.json and gitignore file. You can either copy and paste from existing ones,
or even bake your plugin code (cake bake plugin Name) and move it to your stand-alone plugin.
Keeping in the app is also possible, but I prefer to keep it outside and develop it test driven until it is in a working state.
This way you are usually faster. TDD – test driven development – actually helps to speed up development, and you get tests with it for free.

Now it was time to set up the behavior code and the constructor setup as well as a test file.
With php phpunit.phar I already got immediate results of the initial work, and could fix those with almost zero overhead.
As soon as I added more use cases, especially with some config options and edge cases, I quickly saw where things were not working as expected.
But while getting those to run, I also saw if I broke the existing already working tests. Big help.

Once I got everything in a beta usable state, I pushed and published the repo.
After some documentation (!) in the README as well as Travis/Packagist enabling, I already composer required it in my Sandbox project and started to use it "for real".
When I got it all working in live mode, I felt convinced enough to release a 0.1 beta tag.

The cool thing that coveralls (or codecov.io etc) told me then:
I got 95% code coverage out of the box without writing additional tests (I did write them parallel to the code as "pseudo app test frame").
Simply because when I wrote the plugin code and tests, I already tried the different options available, running into all possible code lines by design.

So now I added more features over the next 1-2 hours, released 2 more tags and after a few days it is now time for the official 1.0.0 release.

Here is my sandbox demo code for this plugin, by the way: sandbox3.dereuromark.de/sandbox/hashids.

In parallel I started even a 2nd small plugin Markup, which took my only half the time even because now I was already quite fast in setting up the boilerplate stuff. Here I also tried to keep it extensible for use cases of future plugin users.

So overall I invested a few hours total to have two easily maintainable plugins that are open for extension, but by default suit my needs. Try it yourself, you will see that this way it really is not too hard to develop and publish such a plugin.

(Plugin) coding tips

If you develop a plugin for the first time, take a look at the existing ones listed in the awesome-cakephp list.
They might give you some insight in how things can look like. How we add a bootstrap for testing, how a Travis file looks like etc.

For test cases it also never hurts to take a look into the core test cases.

Plugin vs. core feature

This issue comes up every week basically. For me, beginning with CakePHP it was difficult to tell what should be covered by the core and what should stay as community plugin. I had this idea that every use case must be supported by the framework itself. Over time, it become more and more clear to me that a framework itself should stay lean and focus on the majority of the use cases and maybe provide a way to make it extensible for those edge case.

As a logical conclusion some of the CakePHP core functionality has been split off into it’s own repositories, like Acl, Migrations, Bake, Localized.
Not all of the users need those additional tools, in fact almost no one used Acl, and you only need Bake for development.

The positive side-effect here is that the iterations of these plugins can be independent from the core development, making feature development faster as there is no core release for the whole package necessary anymore.

Ask yourself the following questions:

  • Does the majority of devs need this functionality, and if so, this specific implementation of it?
  • Is it beneficial for both core and plugin to keep it standalone for maintenance and extendability reasons?

There will be more questions you can ask if you continue reading the next chapters about more generic principles.

Try to follow coding and package principles.

With CakePHP 3 we can finally adhere more correctly to some very basic coding principles. Most of you might know (or at least heard) about SOLID and Package Principles.
They following tips go into more detail what it means for our CakePHP plugins.

Coding principles (SOLID)

SOLID principles

The 5 well known SOLID principles can help us deciding how to best code our plugins and libraries.

Single responsibility principle (S)

Try to keep your classes simple and short, doing one specific task.
Take a look into my Geocoder behavior.
It does not actually geocode, because that is the task of a specific class. To avoid it doing too much, the behavior only wraps this Geocoder class and forwards calls to it. This way the only responsibility of this behavior is to help the model layer (usually a Table class) to geocode the entity data, while the single responsibility of the Geocoder class is to perform this geocoding task by talking to an API.
The additional advantage is that we can also use the library class as standalone, so we might want to provide a GeocodeShell, for which we most certainly don’t want to use behavior to encode a simple input string.

Open/closed principle (O)

Your code should be open for extension, but closed for modification. You will most likely never be able to guess and support all use cases for your code out of the box. Often times people will have come up with new ways to use your plugin.
So at the one side you do not want to have to change your code for every possible scenario. But if it was possible to support a lot of extensions out of the box, why not doing this?

If we are using dependencies in our classes, we do not want to rely on a specific class dependency, but an interface.
This might be not so important to you as plugin designer, but as soon as people use it, they might want to change maybe how a specific implementation of your dependency works.

Lets take a look at the [Slug plugin][(https://github.com/UseMuffin/Slug). It shows how you can simply set a default for 'slugger' => 'Muffin\Slug\Slugger\CakeSlugger', but it would allow any other slugger implementing the SluggerInterface. Instead of providing and versioning all possible sluggers (and their potential dependencies) itself, it allows another package to contain a user-specific slugger
to use.

So always try to not contain specific switch statements or if/else blocks. Instead, always implement against a generic interface that allows for exchangeability. This is especially important for type-hinting constructors and methods.

Here, the implementing classes just need to provide a slug() method and it will work just fine even with some BinarySlugger 🙂

Liskov substitution principle (L)

Every subclass or derived class should be substitutable for their base/parent class. So make sure you make don’t widen the input/constructors, but keep them the same or narrow them.
You can always become more strict, but not less. Interfaces also help with that, as they make sure that at least those common methods have been provided.

Interface segregation principle (I)

If you create one interface containing too many different method stubs, often times you limit the possibilities of implementation.
Often times those classes can be grouped by API or Non-API, and in either of those cases need only a subset of the interface methods.
In this case it will most likely make sense to have two specific interfaces for each use case, this allows the sub-parts of your code to only rely on those relevant methods they care about.

Dependency inversion principle (D)

Ideally, we always enforce class dependencies via constructor argument commonly known as "Constructor Dependency Injection". When allowing to exchange the used class, we should respect that.

So in our case, we allow a closure to be passed into our plugin library class config:

$geocoderClass = $this->config('provider');
if (is_callable($geocoderClass)) {
	// Use the injected closure
	$this->geocoder = $geocoderClass();
	return;
}
// Manually create class
$this->geocoder = new $geocoderClass();

You never know if the class your plugin users want to use require some constructor dependencies on their own.
The DI principle should be possible for them to use, too, to fully respect the Open/Close Principle from above.

They can now have their own HTTP adapter passed into the Provider class:

$config = [
	'provider' => function () {
		return new \Geocoder\Provider\FreeGeoIp(new \Ivory\HttpAdapter\CakeHttpAdapter());
	}
];
$this->Geocoder = new Geocoder($config);

As with the first principle, it is also important for DI that if you type-hint methods, class properties and alike, always try to use the Interface, not a concrete class.

Note that there is a second way to pass class dependencies usually referred to as "Setter Dependency Injection".
This should be avoided for required classes and only be used for optional parts, if any.

Package principles

Some of the 6 commonly known package principles can also be quite useful for our decisions.

Reuse-release equivalence principle – consider the scope

It is very much possible that whatever plugin you are going to write, the functionality itself could be interesting to other PHP applications.
With 2.x it was hard to provide it both ways, with 3.x this is now as easy as it gets.

A good example is Mark Story’s AssetCompress plugin.
Back in 2.x this was a full blown CakePHP-only dependency.
He realized that most of the code behind it could very well be useful to other PHP projects, though.
With CakePHP 3 it was finally possible to move the code into a standalone lib called MiniAsset.
All that was left of the plugin code was to function as a CakePHP bridge. This enables the actual library to be used by everyone whereas the framework users could use the plugin.
r
So also check your existing (plugin) code for this maybe.

Common-reuse principle (CRP)

Code that is used together, should be ideally in the same package. Micro-splitting each class into it’s own plugin might not always be wise. It also increases maintenance time/costs.

So if you have a Geocoder Library class talking to the API and a Geocoder Behavior using this Library to populate entities, you would always use them together, or just the library class.
Splitting them into own plugins does not sound feasible here, as the default case sees them used together.

Common-closure principle (CCP)

A package should not have more than one reason to change. So when you put too many different classes or even multiple different dependencies into a plugin/lib, you might have to major bump for each of those separately, creating a lot of annoyance for the users only using the unrelated part of code.
Bear that in mind when packaging. Packaging a lot together eases maintenance time/costs, however. So you need to find a good balance here (also regarding CRP principle) for the maintainer(s) as well as the package users.

Most probably know my Tools plugin, which was started way back in 2006 with SVN and no github/composer.
At that time it would have been super painful to support multiple plugins via SVN externals and no release/version locking really.
Thus one monolith class collection. Over the time, with GitHub and more people using it (not just me anymore), it became clear this approach is outdated and troublesome. Most of the time people use only a small subset and have to get all irrelevant class changes on top.
So with CakePHP 3 already becoming alpha/beta I started to split off some of the chunks that really deserve their own plugin namespace.
TinyAuth, Geo, Ajax, Rss and Shim have been created.
Now everyone using TinyAuth or Rss, for example, will most likely use all those classes together, while inside Tools it would have been 1% of all the rest.

I will further split out stuff in the future, wherever this makes sense regarding to these two first packaging principles. But it would also be impractical to have to maintain 150 new plugins for each small stand-alone class used somewhere at some point. So a good balance is the key again.

Package coupling (ADP, SDP, SAP)

  • Prevent cycling dependencies
  • Change is easiest when a package has not many dependencies (stable), so make sure if it does those are also not blocked for change.
  • Stable packages ideally have a lot of abstraction (interface, …) exposed to the depending parts so their stability does not prevent them from being extended.

Note that the term "stability"/"instability" isn’t evaluative. It simply refers to the dependencies of a package here.

A quote about stability of classes:

Typically, but not always, abstract classes and interfaces are not dependent on others and tend to be more stable as against concrete or implementation classes. This is because the abstract classes or interfaces typically represent the high level design and not the implementation, e.g, an interface called Logger will be more stable than classes FileLogger or DBLogger.

ifacethoughts.net/2006/04/15/stable-dependencies-principle

So in both cases (class vs package level) stability means something slightly different but in the end sums up to "less reasons to change".
By trying to create and use packages and classes in the direction of stability usually is the best approach and will keep necessary changes at the endpoint (usually your app) at a minimum, as well as for most parts (plugins) in between.

Releasing

Don’t forget to release your code with tags following "semver".
You can start with 0.x and once you feel comfortable that it is fairly stable, release a 1.0.0.
New functionality usually goes into minor releases, bugfixes in patch-releases. A BC break warrants a major version jump.

Framework Semantic Versioning

With releasing plugins for a CakePHP version strict semver can be somewhat confusing, though (1.x/2.x here is for 3.x there, 3.x+ is for 4.x there, etc).
One more severe problem with that is that once you released a new 3.x framework compatible version you cannot major bump your 2.x code, as there is no number left in between. You have to break semver, or do some other workaround using composer-constraints. Some might even suggest to use a new repository for the 3.x compatible code etc.
Most of the time people are just afraid of major bumps and often use a minor one to introduce larger breaking changes.
It seems like here the design itself does not fit to the use case and misleads the maintainer to do bad things (talking from experience).
I think there is a better approach.

Something that could be considered "framework-semver" is the following approach I have seen occasionally so far:

x.y.z

  • x: CakePHP major version
  • y: Plugin major version
  • z: Plugin minor/patch version

Examples:

  • 2.3.4: CakePHP 2.x, Plugin 3.x for this major, Minor/Patch v5
  • 3.1.0: CakePHP 3.x, Plugin 1.x for this major, First Minor

So the first number of both core and plugin matches.

In my book this makes it way more clear as the plugin itself cannot live without the CakePHP core dependency and at the same time has to be compliant to each of those different major versions.
So in all this makes more z bumps, and occasionally an y bump. But that is OK.
It also requires you to look the y version then "vendor-name/plugin-name": "1.2.*", as every y bump could break BC.

In theory you could also use a 4th digit, the actual patch version: x.y.z.patch, e.g. 2.3.4.1. This would make it fully semver in itself again, but is usually not needed, as new functionality that is BC and bug fixes are both supposed to be z compliant (otherwise it would be major plugin version bump).
Either way it solves the issue of framework dependent plugins by design, and not by workarounds.

A smilar approach was already published here, but this is not composer friendly, and since all non major bumps should be BC, there should be no immediate need for a prefixing that includes the minor version of a framework.

Note: This is just some grounds for discussion so far. If you plan on using this you should really make it clear and documented it in bold visible in the README or something.
Because by default people will most likely assume you are following default "semver". Are there any downsides so far? I would really like to have some feedback here from the whole community.

License

Most people tend to forget that they release packages that are to be used in other peoples’ (proprietary) software. That means that they cannot legally use your code unless you specifically put a license in they know they can use. An MIT license is recommended and always works.
But that requires the file to be present in the root folder and/or in the files itself.
Just having a statement in the README usually does not suffice. Just something to look out for.
It would be sad if lots of projects/companies would like to use your plugin but cannot because of trivial license issues. Get it out of the way. You will benefit from more uses because of more feedback/contributions of them, as well.

Maintaining

One thing you should consider is regular maintenance for your plugins. Make sure CI (e.g. Travis) tests pass, that issues and PRs are taken care of in a reasonable time frame etc.
If that is too much to do, you can always ask for help and co-contributors, or even hand off the repo to someone else entirely.

Ready, set, …

Then take an idea and pluginize it.

You really want to start coding your own awesome plugin now but don’t have an idea? Look into the wiki of that very same repo from above. There you can find a lot of 2.x plugins that have not been upgraded yet. You could take care for any that interest you.
Or you go through your existing code and check those classes (helpers, behaviors, libs, …) for re-usability.
Also don’t forget to add your upgraded or new plugin to that list 🙂

Final notes

Some people might know DIP also as IOC (Inversion of Control).
Maybe also take a look at containerless-dependency-injection-for-services, a new article of @markstory about how most frameworks make their users potentially abuse DIC and
how better code your service classes.

Book Tips / Source Materials / Interesting Videos:

 
1 Comment

Posted in CakePHP

 

CakePHP 3.0 Migration Notes

06 Jun

Trying to migrate my CakeFest app for this year’s event, I made some notes regarding the upgrade process from 2.x to 3.x.
I completed them during the upgrade of my Sandbox app to 3.0. And adjusted them after RC2 and 3.0.0 stable again while upgrading 2 more apps and 5+ plugins.

Initial steps and requirements

The following were given in my case:

  • The app was already composered (as it should be for all CakePHP 2 apps) and thus "composer" was already available
  • I used a 2.x setup with ROOT dir as APP dir directly (which seemed to cause some trouble later on)
  • I used GIT for version control and supervise each upgrade step (which also caused some trouble)

Also make sure you covered the following reading material:

As a side note: It is also wise to follow the 3.0 development, read the PRs and proposed as well as recent changes.

Let’s go

By the time I wrote this I still had to tweak and fix the Upgrade tool along with it, so bear with me if something is not perfectly in sync here.

I first made sure I got a clean 2.x app with the latest (right now 2.6) changes, as outlined in previous posts regarding "how to prepare 2.x apps for 3.x".
I also used a "AppUsesCorrection" tool I have written to move all inline App::uses() statements to the top of the file. This was a left over from earlier days and will
screw up the files if not taken care off.

I also started to use the Shim plugin a while back for all my 2.x apps to make sure I already shimmed as much as possible towards 3.x, so the now required changes are minimal. If you already know you want to upgrade sooner or later, save time and shim "ahead".

Then I basically downloaded and initialized the Upgrade tool and ran the all command on my app and plugins separately.
In case something goes boom, better run the commands individually and verify the changes after each command (and commit them away).

Afterwards I adjusted my composer.json file for 3.0 and used composer update to get all new dependencies.
Here you should also make sure all dependencies like plugins are available as 3.0 versions, otherwise temporally remove/exclude them for now if possible.
Also don’t forget the new autoload and autoload-dev parts in the composer file.

A first try run revealed that I had still a lot of manual work to do in /config first:

  • config/app(_local).php
  • core.php (deprecated) => bootstrap.php
  • database.php (deprecated) ) => app(_local).php
  • routes.php

A tip here: IMO it is wise to not directly modify app.php as changes along the line will be harder to spot.
Instead I keep the file as it is (default) and just use a second one app_custom.php on top to overwrite/complete it where necessary.
I also use a third app_local.php, which is not under version control (.gitignore), to store non-commitable stuff like keys, salts, passwords etc.

Configure::load('app', 'default', false);
...
Configure::load('app_custom', 'default');
Configure::load('app_local', 'default'); // Not under version control

I found a lot of namespaces to be missing, as a lot of App::uses() have been left out in 2.x. It still worked there, as without namespaces it only needs it once per dispatching. But now it fails hard. So if you didn’t add the missing ones back in 2.x, you need to do that now at least.
I developed a tool to do that, the opposite of the unused_use fixer pretty much. This is very complex though. as it is not
always clear what package the use statements need to come from. It needs some config overhead.

I also had to remove the table prefixes as they are not supported in 3.x using my new CakePHP 3 Setup plugin DbMaintenance shell command cake Setup.DbMaintenance table_prefixes. It removed them in a few seconds. Afterwards my Table classes were able to find the tables again.

Afterwards I already tried to access a public page. Got quite a few things I had to manually take care of now:

Manual changes

Change public $uses = array('User'); to public $modelClass = 'User';. If there are multiple statements, this has to be resolved afterwards on top, using
$this->loadModel() etc.

Routes

The routes file will most likely also have to be adjusted by hand. The (admin) prefixes are the change that sticks out most.
But it is more repetitive than difficult to adjust the routes.
Bear in mind that you can easily set the fallback route class to InflectedRoute here first to handle them just as 2.x did:

Router::defaultRouteClass('InflectedRoute'); // Use DashedRoute for new 3.x projects

URLs

All the URLs usually are now more case sensitive (and CamelCased/camelBacked)

// Before
Router::url(['admin' => true, 'plugin' => 'my_plugin', 
	'controller' => 'my_controller', 'action' => 'my_action'])
// After
Router::url(['prefix' => 'admin', 'plugin' => 'MyPlugin', 
	'controller' => 'MyController', 'action' => 'myAction'])

Also make sure, you dont use the prefix values directly (admin, …) anymore, but the prefix key itself:

// Before
'loginAction' => ['admin' => false, 'plugin' => false, 
	'controller' => 'account', 'action' => 'login'],
// After
'loginAction' => ['prefix' => false, 'plugin' => false, 
	'controller' => 'Account', 'action' => 'login'],

E.g. for the AuthComponent config here. Otherwise it will redirect you to the prefixed URL instead as admin is not recognized anymore.

Auth

The auth code in the AppController and login action needed to be adjusted.
In the controller, it is not via properties anymore, but Auth->config(). The login action needs identify() and setUser() now.

Array => Entity

With the array to entity changes a lot of view files cannot be fixed with the Upgrade shell, and stuff like echo $profile['User']['id'] has to be refactored into echo $profile->user['id'], for example.
As $user['User']['id'] would be $user['id'] now, there are changes across all MVC layers to be applied in order for the functionality to work again as expected.

Custom

For all my own custom replacements I collected them and made a Custom task over time to avoid having to do this all over again across multiple apps or plugins.
I therefore forked the Upgrade plugin.

When working with date(time) fields I also had to do some special refactoring, as some older apps had 0000-00-00 00:00:00 stored as null/default value.
This is quite unfortunate, as with Carbone and Time class, this would create negative values, which blows everywhere.
So I created a Setup.DbMaintenance dates command in the Setup plugin to refactor those fields and their content into the proper value.

The same goes for foreign keys and '0' stored in wrong DEFAULT NOT NULL columns. With the Setup.DbMaintenance foreign_keys command you can also clean those up (DEFAULT NULL + NULL value).

Validation

It would be quite the task to rewrite the whole validation with all the models and their $validate properties. So here I just used the Shim plugin from above and kept the old syntax to save time. The same for relations and a lot of other model properties. It then only needed minimal adjustments, like adding 'provider' => 'table' for isUnique rule or changing notEmpty to notBlank.

Virtual fields

Mixing them with the fields array itself is not so easy anymore.
You can use closures to help out:

// For your find('all', $options) $options
'fields' => function ($query) {
	return [
		'jobtype', // Normal field
		'num' => $query->func()->count('*'), // COUNT(*)
		'fetchdelay' => $query->func()->avg('UNIX_TIMESTAMP(fetched) - IF(notbefore is NULL, UNIX_TIMESTAMP(created), UNIX_TIMESTAMP(notbefore))'), // Something more complex
		'age' => $query->newExpr()->add('IFNULL(TIMESTAMPDIFF(SECOND, NOW(), notbefore), 0)'), // Custom expression
	];
},

Locales

The Locale folder is inside src, but the subfolders changed quite a bit. It is now flat, just two-letter country codes, for Germany the po file would be located in /src/Locale/de/ now (instead of .../Locale/deu/LC_MESSAGES/).

View ctps

These template files also have to change quite a bit.
For starters, the above array to entity conversion introduces a lot of change.
Also, all static calls now have to be handled by either importing the classes via use ...; statement at the top of each file, or you can wrap them with a helper.
A quickfix would be to just class_alias() them, e.g. the Configure::...() calls would need a lot of use statements you can omit if you put the following in your bootstrap.phpfile:

class_alias('Cake\Core\Configure', 'Configure');

Now, all Configure::read() calls work again in the ctps.

Assets

If you don’t directly output your inline assets, but add them to the "scripts" block to be outputted together in the layout, you will have to change the method calls.
It used to be 'inline' => true/false, now it is:

$this->Html->css('jquery/galleriffic', ['block' => true]);
$this->Html->script('jquery/jquery.galleriffic', ['block' => true]);

In your layout ctp you can then keep the echo $this->fetch('css'); and echo $this->fetch('script'); part as it was in 2.x.

Tricky ones

Tricky as in "not ease to spot"…

The !empty PHP bug I mentioned a while back.
I had a pagination index view where I iterate over all users and display something else if there are none (yet). This fails, now, though, as the empty check will always return false:

<?php foreach ($users as $user) {} ?>
<?php if (empty($users)) {} ?>

The empty check needs to be this way in order to work as expected:

<?php if (!count($users)) {] ?>

Or, when you know it is a query finder object:

<?php if ($users->count()) {] ?>

Same with:

while ($records = $this->_table->find('all', $params)) {}

This will run endless now. Here either add ->toArray() or use a streamable result.

UPDATE Since recently (3.0.4?) you can also use ->isEmpty() as check on any Query or Collection object:

$result = $this->TableName->find()->...;
if ($result->isEmpty()) {}

find()

I used the Shim plugin and the support for find(first) and find(count), but even then you need to make sure that for find(first) you don’t forget to adjust all those $options regarding keyField and valueField which are now required to be set if you plan on using non displayField values, as the "fields" list is ignored for it (used to work to filter on 2 fields and it automatically used those).

Magic/Dynamic finders

Careful with those, like findByUsername(). In 2.x. those returned find(first) results (limit 1 so to speak), in 3.x. those need an additional ->first() appended to have the same result.

Trait or Behavior?

You might run into this when refactoring your models and behaviors.
In 2.x behaviors had the problem that they didn’t work for non-primary models, and as such where often too limited and one probably tried to workaround it using traits.
In 3.x that limitation is gone.

I think the main idea behind behaviors keeps the same: If you want to dynamically attach and detach functionality to your models, this is the way to go. Traits are too static for this. Traits, on the other hand will be necessary if you want to cleanly overwrite Table methods, see the SoftDelete trait for an example. In that case you just can’t do this dynamically.

Additionally, behaviors can more easily be configured using built-in config() and they can be aliased easily. The downsite might be speed, which is neglectable, though.
So try behaviors first, then fallback to traits IMO.

Summary

All in all quite a lot of migration steps can be (partially) automated, which will help a lot for larger applications where it would just be super-tedious to do that manually on such a scale. But most of the ORM changes need manual code changes, which makes it really a time-intensive task for medium apps and above.
Using shims, coding wisely ahead of time, avoiding hacks or non-wrapper low-level functions, all those can help to ease migration. In the end you just have to swallow the bitter pill and get it over with. It is worth it!

 
2 Comments

Posted in CakePHP

 

CakePHP 3.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

 

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

 

Using Composer

30 Mar

There are quite a few good articles on this topic, already. Especially on how to leverage it for CakePHP projects.

See

So I won’t go into detail too much.
It is worth noting that composer really made a few things easier for us in the long run.
And I was really against composer and packagist at the beginning as I didn’t want to use more dependencies than necessary.
But that one sure is worth it if you use it right. And as every project pretty much uses it these days it is
fairly stable and future proof to rely upon.

Installation

Easiest way:
Download the phar and run php composer.phar [command]. You can just place this file into your app dir.
You can also install it more globally, of course to just have to run composer [command] directly. The above articles or the composer docs explain that in more detail.

Usage

In general you can either use the composer commands to add dependencies or you can directly modify the composer.json file via editor (note that some IDEs support that natively with auto-completion).
You also need to distinguish between "install" and "update" command. The first respects the current composer.lock file. The latter should only be used for development/staging, not for productive systems.
See the basic usage docs for more details.

Composer and CakePHP

Can I switch my 2.x git project from submodules to composer?

Most definitly, yes. And you probably should.
Using submodules really is a great annoyance, especially with the number of plugins increasing in a project.
Unfortunately, getting rid of them is also not always easy – but doable.

You need to

  • git submodule deinit <path/to/plugin>
  • git rm <path/to/plugin>

Which, under windows, for example can proof a little bit difficult sometimes.

Then re-add them to the composer file and don’t forget to exlude the folder in the .gitignore file.

Composer and CakePHP3.x

In 3.x composer will pretty much be the de facto standard for CakePHP. So it is worth getting used to it now.

A few tips and tricks

I can add least talk about a few things I came across working with composer now for a few months.

VCS

Version control system repositories can easily be included if they don’t support composer or if you need to run a modified version of a 3rd party plugin/dependency.
We then include the main source in the "require" section and add our specific (tweaked) fork as VCS in "repositories":

"require": {
	"josegonzalez/cakephp-wysiwyg" : "dev-master",
},
"repositories" : [{
		"type" : "vcs",
		"url" : "https://github.com/MyOwnNameSpace/cakephp-wysiwyg"	
}],

Our version then contains some bug-fixes or additional stuff that needed it to branch off here.

dev prefix/suffix?

It kind of confused me when to use the suffix and when to use the prefix for "dev".
I found quite a look explanation from someone I added to this PR:

Basically dev releases are now simply branch names with a dev suffix for numeric branches which are comparable (3.0.*-dev) – or a dev prefix for textual names that are not comparable, like feature branches and master (dev-master)

You should authenticate the server/locally to avoid hitting the API limit

This page describes on how to generate an OAuth token and use this to avoid hitting the limit of requests per minute for GitHub.

Use proper user management to run composer commands

If you log in as root or any user that is not affialited with the www-data user, the files that are updated/created will most likely not be readable/usable.
And using chmor -r 777 * sure is a really bad idea, as well. It is better to create a user that shares the same rights/group as www-data and use this one to deploy or do any changes on the code.

If something aint working

Try it again first – sometimes there are failures in the communication between GitHub, Packagist and your local connection.

Also try the self-update command to make sure you are running a recent version of composer. diagnose can also tell you of there is something wrong.
Maybe you forgot to enable some required PHP extensions, like "curl" (which is necessary for it). But the error message usually tells you what exactly what the issue is.

Last Tip

You can also take a look at my enhanced Upgrade shell. Maybe it can help getting your code to the latest code-base.