Monday, December 6. 2010
Today we released the bugfix releases Stubbles 1.3.2 and 1.4.2. The releases fix a bug with the rdbms pdo implementation which caused a fatal error when trying to fetch a column on a result set. The other fix is for the stubProperties class where iterating over the sections was broken causing that after a first iteration the internal pointer was not reset to the start when starting the second iteration. Get the releases from our downloads page.
Sunday, November 7. 2010
Developers who are familiar with the topic of clean code know that static methods are a problem, especially if it comes to testability. Static makes the code global, and if there is some kind of state involved it is even more a problem because this is global state then - both a maintenance and testability nightmare.
Unfortunately, sometimes you don't get around of using such code. This could be due to a third party library you have to use, or even because of limitations of PHP itself. (Ever wanted to configure stream wrappers if stream context is not an option? Your only chance are static methods and therefore global state.) How can we keep our code clean and testable, at best without having a strongly coupled dependency to the class hosting the static method? Enter dependency injection for static methods.
Luckily PHP 5.3 comes with a new feature: dynamic access to static methods. Basically this means if you have a class with a static method you can call it like this:
Let's use this feature to get a more loose coupling between our own class and the static class. Suppose we have the following code:
For some reason the method call can not be moved to another place where we could get rid of the direct dependency. But if we change the code of the Bar class things look different:
The class still works as before, but we can change the name of the class the static method is called on. This is great, because in a test we can substitute the FooFromSomeLibrary class with our own mock implementation:
Our own Bar class is now only loosely coupled to FooFromSomeLibrary. While I don't suggest to use your own code in this way it is a helpful opportunity when working with code you don't have influence on.
Thursday, November 4. 2010
Note: this article was supposed to be released on November 3rd, but I was not able to finish and release it in time. So don't wonder if the tense in the article is not correct.
Some days ago Cem Derin proposed the idea of the Developers Shame Day. As his blog entry is German only here is a short summary of what this is about: basically, a developer should look into old source code of him/her and present a piece of code which is stupid in some kind, be it obvious errors, bad structure or security flaws - only guidelines are it most be his/her own source code and should not be changed. It must not necessarily be PHP, it could be in any language. It should be presented on November 3rd with a small description - and probably with an explanation why it is bad and makes you feel ashamed.
Initially I thought this is a great idea: showing other developers that even highly appreciated developers produce errors, sometimes even stupid ones; showing that we all started as beginners. Don't get me wrong, I still think it is a good idea. But it must be put into context. Producing bad code is nothing one should be ashamed of. Personally I believe that every developer always tries its best to produce the best code, the best solution to a problem. Bad code happens because of missing knowledge. Good thing is, you can learn how to make it better - and after applying a refactoring to the code it's not even there any more, just buried in the history of your source code control system.
However, it must be acknowledged that there is a lot of bad and even stupid code out there, even from developers who should know better. This is what developers should be ashamed of: being ignorant against what they learned from books, talks or other sources of information, not applying this knowledge to their code or to defy it because the first or even second try did not work out as expected.
So, the basic idea of the day is a very good one, showing beginners that all of us started on a low level. But I think it should not be called Shame Day - based on the context (knowledge and other constraints) in which the solution was created it probably was the best what you could do back then. And it's not about shame, because you learned and gained knowledge - which enables you to recognize something as an error or problem, and giving other developers the possibility to share your knowledge. If you take part in this day by providing a blog article about code mistakes from your past you should be proud instead: proud of having learned more, proud of sharing your knowledge with other developers and proud of defeating one of programmers worst enemy: ignorance.
Friday, October 15. 2010
As described in a previous blog article Stubbles did not work on PHP versions built using libxml 2.7, which is the case for at least all PHP versions since 5.3.0. We fixed the issue and make it today available as a bugfix release. This means that both 1.3.1 and 1.4.1 can now be used on PHP 5.3. See the changelog for a complete list of changes. Additionally we started to provide an Upgrade Guide with more detailed instructions on what needs to be done when upgrading from a previous version.
Thursday, October 14. 2010
Lately we came across the problem that the XML/XSL view engine of Stubbles stopped working when upgrading to a newer PHP version which included libxml 2.7 instead of the previous 2.6 version. As of course Stubbles should be able to run with PHP 5.3 which uses libxml 2.7 this had to be fixed. So I tried to investigate the issue, and it took me some hours to find out what the problem was. Once the problem was understood it was very easy to fix. However, to come to the point were it became clear what was wrong was quite disturbing.
But, first to the problem. In the XML/XSL view engine we provide a simple to use XSL template which allows inclusion of XML parts from other XML resource files, so that you can easily share content between different routes, e.g. the header or footer of a website. The template looks like this:
<stub:include href="foo.xml" part="bar"/>
In a first step this will be transformed to something like
<xi:include href="xinc://default/foo.xml?part=bar#xpointer(/parts/part[@name='bar']/node())"><xi:fallback> ... some fallback code ... </xi:fallback></xi:include>
So, what does the href attribute contain? First, the xinc scheme points to our internal stream wrapper which is applied to transform the given XML document first before returning it for inclusion. Second, default/foo.xml gives our stream wrapper the information which xml file from which project to read. The query with the part is only additional information for debug purposes. After this, an XPointer is appended as fragment. The XPointer is used by libxml to include only the part from the returned XML document that can be accessed using the XPath expression given with the XPointer. This works well with libxml 2.6, but stopped to work with 2.7.
First I thought it might be a problem with the stream wrapper. But it was not. Neither was the stream wrapper called nor did libxml complain about an invalid URL. Next step was to try to reproduce the issue using real file URLs instead of the stream wrapper URLs. Still did not work. So, I tried to ask Google. The answers where not really helpful. Last resort: read again in the XInclude standard. After reading the final XInclude 1.0 W3C recommendation I found out that there is a separate xpointer attribute to be used. By changing the generated XInclude statement to
<xi:include href="xinc://default/foo.xml?part=bar" xpointer="xpointer(/parts/part[@name='bar']/node())"><xi:fallback> ... some fallback code ... </xi:fallback></xi:include>
it resumes working as if nothing happened.
Turns out, the XPointer part is the problem with libxml 2.7. With version 2.7 libxml completely refuses to process the XInclude if there is such an XPointer fragment appended to the URL given with the href attribute. No warning or error is thrown for this. Luckily changing the XInclude statement to comply with the final standard works with 2.6 as well.
You may ask why we used a version which was not supported by the final recommendation. Well, it just worked. And as it turns out, the first version was the way to use XPointers in XInclude 1.0 W3C Candidate Recommendation. It seems libxml just dropped support for this with the 2.7 series.
What can we learn from this:
Friday, October 8. 2010
With the release of vfsStream 0.8.0 the status is now beta instead of alpha as it was before. New features include a umask simulation which allows you to set a umask for vfsStream URLs which is then applied for new directories and files, except if you explicitly set the permissions of a file or directory using the vfsStream API. To be backward compatible and easier to use the default umask is 0000 - so if you are not interested in using this feature just don't use it and everything stays at it is.
Another new feature is the support of .. in URLs, provided via patch by Guislain Duthieuw, which means you can now have constructs like vfs://root/path/../otherpath which is mapped to vfs://root/otherpath. However, realpath() still doesn't work - there is no way to make this work with how realpath() is currently implemented in PHP itself.
Besides this two bugs have been fixed, one where it was impossible until now to access a child of a directory via the vfsStream API if the child name is contained in the parent's name. The other one was an incomplete error message when you tried to access non-existing files on the root level.
You can get the new release via our pear channel.
Wednesday, September 29. 2010
Today we released Stubbles 1.3.0 and 1.4.0. First, what's new in 1.3.0? This release features a new API for the request interface which is much simpler to use. There are now separate methods for accessing parameters, cookies and headers, and the way to filter and validate request values was very much simplified. For more details on how the new API looks check the rewritten Wiki manual. All old methods are now deprecated.
Another change is the replacement of XML configuration via XJConf for error messages and route configurations. Both are now configured via property files. The old way of configuration via XML files is still available but has to be explicitly activated. However, it is deprecated as well. This is in compliance with our strategy to remove the dependency to XJConf from Stubbles.
The REST processor now supports filter annotations for REST method parameters. This is useful to validate such input values in the surrounding code, and to keep the business code of the REST method free from validation code.
In several different classes we added various methods for easier usage. See the changelog for a complete list of changes.
What's new in 1.4.0? Well, not that much. Basically, 1.4.0 is the same as 1.3.0, but with all code removed which became deprecated in 1.3.0. So, which version should you upgrade to? If you want to upgrade fast and only want to profit from bugfixes we recommend upgrading to 1.3.0 and activate the XML configuration. You might also want to change your route configuration files (and error message configuration files if you have any) into the new ini format. It is also recommended to upgrade to 1.3.0 before starting to migrate to the new request API. Upgrading to 1.4.0 should be done after all request API dependent code was migrated to the new methods and there are no calls to old methods left. We recommend to aim for migration to 1.4.0 as the next minor or major version will be based on 1.4.0 - deprecated and removed code will not return any more.
Until we release the next minor or major version we will continue to support 1.3.0 as well as 1.4.0 which means bugfix releases will be done for both minor versions.
Tuesday, September 14. 2010
Nearly two years ago back in November 2008 I wrote about the state of annotations in the PHP world. Today I want to take the chance to revisit this and find out if annotations are still present and used, or if they are not.
Review of old candidates
Of those which I described two years ago, AttributeReader saw no further development, so I don't consider it as an option any more.
Addendum has seen new releases, the last one in October last year. The repository has seen commits recently in June this year, so I believe it's not dead, but as it is feature complete there's of course not much development activity required any more.
The third candidate was FLOW3. FLOW3 is still alive and kickin', nearing it`s final stable 1.0.0 release. Annotations are still part of the framework and the Introduction tutorial has usage examples of where you utilize annotations provided by the framework, for dependency injection and validation. The manual additionally lists persistence and even Aspect-Oriented Programming as usage scenarios. So as FLOW3 is likely to be adopted within the TYPO3 community we will see more and more FLOW3 based applications using annotations.
Another framework is Stubbles. From what was stated in the first blog post nothing has changed, beside the fact that Stubbles is now available in version 1.2.0, with versions 1.3.0 and 1.4.0 shipping within the next two or three weeks. Stubbles is used in various applications at 1&1 Internet where we make heavy usage of the annotation features.
The third framework mentioned was the XP framework. Current release is 5.7.11 with 5.8.0 right around the corner. For the annotation part nothing has changed, and XP framework is used to build the intranet of 1&1 Internet as well as a lot of internal tools.
New kids on the block
So, the three frameworks providing annotations are still alive. Question is, are there any new kids on the block? A little research reveals: yes, there are.
One of them is Pia which provides annotations and an annotation API for PHP 5.3. It seems to be under active development and there seems to be no release yet.
Nothing really usable yet, but recently a feature idea for annotation support within the Yii framework was brought up in their forums.
Another one is the Recess! PHP Framework. Recess! uses annotations for routing and ORM. I did not find anything whether Recess! allows user-defined annotations or not.
Then there is Symfony 2, currently scheduled for release in March 2011. Symfony integrates Doctrine 2 which uses annotations heavily to provide ORM features. It includes the Doctrine common annotations library which allows to define and access your own annotations. The inclusion of Doctrine 2 into Symfony 2 makes me very confident we will see a major usage boost of annotations in the PHP community.
In the first edition of this article I already speculated about the idea of having support for annotations within the language itself. Now there is an RFC for annotations including a patch which is discussed heavily on the PHP internals mailing list. Personally I would like to see this included in the PHP language, but it might be a long way ahead. It needs to fit into the language itself, and provide a syntax which integrates with the other parts of the language (though it might be noted that PHP is not very compliant in itself, but there's no need for history repeating).
However, stating that there are no uses cases for annotations in PHP is simply not true. There won't be so much ideas about annotation support if it would be useless. As more and more implementations emerge, even ones which will boost the usage within the PHP community, I'm more than confident that annotations will become widely used in PHP. Providing support in the language would be a good way to give this a solid foundation.
Friday, July 30. 2010
Today marks the day of the release of Stubbles 1.2.0. This release features improvements for the XSL view engine, namely introduction of support for bot link cloaking, and the handling of the session id as a normal request parameter instead as part of the path. Additionally, if a user agent is now recognized as a bot the link creation functionality of the stub:link template will not add the session id to the created URL. This is applicable for user agents only which are not recognized as bots and which do not support cookies. All of this should help applications build on Stubbles to be more SEO compliant and should help improve the search indexing from search engine bots.
As this is a major release all code which was deprecated with 1.1.0 was removed. If you still rely on interceptor and database configurations in XML, now is the time to upgrade both to property file based configurations.
With the addition of Romanian translations for error messages delivered by the framework Stubbles can now be used for Romanian applications out of the box.
For a complete list of changes please consult the changelog. You can get the release on our downloads page.
Tuesday, June 8. 2010
As promised in my talk about vfsStream at the International PHP Conference Spring Edition last week (see slides on slideshare) I released vfsStream 0.7.0 today. This release features two additions: an improvement for support of file permissions resulting from a bug fix, and an API improvement for simpler setups of test cases using vfsStream.
The improved file permissions support now respects file permissions when you access files and/or directories. Until now it was possible to write into a non-writable file or to read from a non-readable file. This is not possible any more, vfsStream enforces file permissions now in every situation. This allows you to create tests to check how your application responds if it does not have correct file permissions on a directory, for example. Please test this change, I'm not sure I got it completely right.
With the API improvement it becomes much simpler to write the setup method for test cases using vfsStream. Before 0.7.0 you had to write something like this:
Starting with 0.7.0 this can be simplified into a single method call:
Still you can have all the flexibility you need. The vfsStream::setup() has the same arguments as vfsStream::newDirectory(), namely name and permissions for the new directory, defaulting to 'root' and 0777. Additionally, the method returns the newly created root directory so that you can use it to do further adjustments as required.
If you like the new additions get the new release.
Wednesday, March 17. 2010
Today we released Stubbles 1.1.1. This is a bugfix release, addressing three issues we found with 1.1.0: It turned out that the database bindings delivered within the framework are not sufficient for every use case. Therefore we rewrote net::stubbles::rdbms::ioc::stubDatabaseBindingModule to fit for new requirements, and removed the deprecation status of this class. However, if you still use XML config files for database connections you need to set the correct database initializer class via the new method stubDatabaseBindingModule::setDatabaseInitializerClassName() to net::stubbles::rdbms::stubDatabaseXJConfInitializer.
The other two bug fixed resort around the build files provided with Stubbles releases: PHP_CodeSniffer introduced a bc break with bugfix release 1.2.2. We adjusted the check-style target to be compatible with this version. Additionally we fixed the setup-examples target, which was broken due to the change of how the projectdir attribute is evaluated since Phing 2.4.0, and slipped through in 1.1.0 when we did the change to this Phing version.
As always, you can get the release from our downloads page.
Sunday, March 7. 2010
This weekend we shipped the fresh Stubbles 1.1.0 release to our downloads page, bringing one or the other great new feature to our users. This includes but is not limited to full support for dependency injection on interceptors, delayed logging, support for providing REST services, and several more improvements which allow simpler usage of Stubbles by supporting dependency injection on even more places throughout the framework.
Such improvements can be seen on the example of how the usage of databases had to be enabled in Stubbles 1.0.0 and how it could be done with 1.1.0: With 1.0.0 you had to configure the database connections in a config file, and you had to add the stubDatabaseBindingModule to the list of binding modules which configure the binder. Now in Stubbles 1.1.0 the last step is not necessary any more, you only require a config file (which, btw, changed from XML to ini format), and after the config file is there you can start in your application classes to get database connection or entity manager instances injected. This works because we added annotations to the framework classes, so that the framework provides a usable default binding without the need to explicit specify these defaults by the user. However, if the default bindings do not satisfy a user's needs he still can configure his own database bindings using his own binding module. Convention over configuration, sort of.
Get the release from our downloads page, for a full list of changes see the changelog.
Monday, February 15. 2010
Seldom in a life of a developer it comes to the point where a bug can be fixed by a feature addition. This February, it happend to vfsStream. A user reported a bug where overwriting an existing vfsStream file with new but smaller content replaced only portions of the file, leaving the rest in place instead of truncating the old content before writing the fresh content. After some investigation it turned out the best fix for the problem was to implement the long scheduled feature issue 7. Thought, said, done. So today I shipped vfsStream 0.6.0 including complete support for for $mode param when opening files.
While I was at it, I added support for the $options param as well, it now evaluates whether STREAM_REPORT_ERRORS is set and acts accordingly when opening a file.
Unfortunately there are bad news as well. Due to another issue I found out that ext/zip does not work with vfsStream, and that there is no way to add support for it in vfsStream. Maybe if someone with slightly more C skills than me (which are equal to zero) might want to look into this problem for a better explanation, as I can only assume that it's due to ext/zip not supporting userland stream wrappers.
If you like the new additions get the new release.
Monday, January 25. 2010
Today I shipped vfsStream 0.5.0 which brings a new feature thanks to the efforts of Benoit Aubuchon: vfsStream now supports the rename() functionality which allows you to write test cases using vfsStream for methods that rename files. Another patch of him was to change the stat() call to respect the STREAM_URL_STAT_QUIET flag.
One more new feature is the added support for . as current directory alias so that vfs://foo/. resolves to vfs://foo - this allows to use file_exists($dir . '/.') as workaround for the failing is_executable() call on directories, as described in the comments to the is_executable() documentation in the PHP manual. Of course this raises the question if vfsStream will support .. as well - if somebody takes the time to create a patch I will incorporate this. I did not look into this issue further, but I guess it might involve recursion and a more advanced parsing of the vfs URL to make it work properly, as there might be cases like vfs://foo/bar/baz/../../dummy.
So grab the release and make use of the new features, if you like to.
Friday, January 8. 2010
Today I want to present a new feature we will introduce with Stubbles 1.1.0: delayed logging. Stubbles already offers a simple to use but powerful logging API, so what can we achieve with this new feature and how to use it?
But first I want to take a look at how log data is generated and written. If you want to log something you first call $logger->createLogEntry('aTarget) which gives you an instance of LogEntry. Depending on the log entry factory which is actually used to create the instance this LogEntry instance might already be prefilled with some data, e.g. the session id, a timestamp and so on and so forth. After that you fill this instance with the data you actually want to log by using its addData() method, and finally calling log() to get it written to a logfile, a database or whatever appender you use.
Now, what happens if you want to log data but when some data utilized by the log entry factory is not available at this point? An example might be the startup phase of your application, where some of the log data depends on calculations done in a later step, but you have to log some data from the current step which in turn is a prerequisite for the later step. Until now this was only possible using ugly workarounds and hacks - and if you are using Stubbles one thing is for sure: you neither like workarounds nor hacks.
Stubbles 1.1.0 and delayed logging to the rescue: we extended the log entry class with a new logDelayed() method which will take care the logger knows about this log entry, but does not hand it over to the log appenders yet. Instead, the logger keeps the log entry in memory, and waits until someone calls it's processDelayedLogEntries() method, or (more likely) the logger instance gets destroyed. If this happens it asks the log entry factory to recreate the log entry in question before handing it to the log appenders, and this gives the log entry factory the chance to replace any earlier not available data with the current version before the log entry is finally written.
Sounds good? Well, as all great stuff this comes with a price. The log entry factory interface had to be extended, so if you upgrade your application you have to change your log entry factory implementation as well: either provide an own implementation of the new recreate() method or extend the abstract log entry factory class introduced with 1.1.0 which provides a default implemention.
Why this API break? We had two options: either provide a new interface or do the API break. Introducing a new interface would have saved us from the API break, but would be more effort to test and implement, harder to document and understand by (future) users and leading to more complications in the future as well. On the other hand, this is a minor release where API breaks are allowed. Keeping backward compatibility only to be friendly is nothing we should aim at as the API break would be have to be done somewhere in the future anyway, by deprecating the old interface. As users tend to delay API upgrades whenever they can it is better to force them to do it as early as possible.